【问题标题】:How to write setup.py to include a Git repository as a dependency如何编写 setup.py 以包含 Git 存储库作为依赖项
【发布时间】:2015-12-17 18:25:17
【问题描述】:

我正在尝试为我的包裹写 setup.py。我的包需要指定对另一个 Git 存储库的依赖。

这是我目前所拥有的:

from setuptools import setup, find_packages

setup(
    name='abc',
    packages=find_packages(),
    url='https://github.abc.com/abc/myabc',
    description='This is a description for abc',
    long_description=open('README.md').read(),
    install_requires=[
        "requests==2.7.0",
        "SomePrivateLib>=0.1.0",
        ],
    dependency_links = [
     "git+git://github.abc.com/abc/SomePrivateLib.git#egg=SomePrivateLib",
    ],
    include_package_data=True,
)

当我跑步时:

pip install -e https://github.abc.com/abc/myabc.git#egg=analyse

我明白了

找不到满足要求的版本 SomePrivateLib>=0.1.0(来自分析)(来自版本:)无匹配 发现 SomePrivateLib>=0.1.0 的分布(来自分析)

我做错了什么?

【问题讨论】:

  • 请注意 setup.py 和 pip 是完全不同的系统。我遇到的一个问题是我能够让这个工作为 pip 而不是 setup.py。

标签: python django git packaging setuptools


【解决方案1】:

注意:此答案现已过时。请查看以下来自@Dick Fox 的答案以获取最新说明:https://stackoverflow.com/a/54794506/2272172


你可以找到正确的方法来做到这一点here

dependency_links=['http://github.com/user/repo/tarball/master#egg=package-1.0']

关键不是给出一个 Git 存储库的链接,而是一个 tarball 的链接。如果您附加 /tarball/master,GitHub 会为您创建一个主分支的 tarball,如上所示。

【讨论】:

  • 看起来这种方法已被 github.com/pypa/pip/issues/3939 弃用
  • 这个方法对于私有仓库也没什么用,因为没有办法验证。
  • 我确实设法让它工作并添加了另一个答案。
  • /tarball/master 方法不适用于 gitlab
  • 已弃用。正确答案是使用 Pep508,由下面的@Dick Fox 回答
【解决方案2】:

随着 Python 多年来的发展,此答案已定期更新。滚动到底部以获取最新答案,或通读以了解其演变过程。

不幸的是,另一个答案不适用于私有存储库,这是最常见的用例之一。我最终确实使用了一个看起来像这样(现已弃用)方法的setup.py 文件:

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository - needs entry in `dependency_links`
        'ExampleRepo'
    ],

    dependency_links=[
        # Make sure to include the `#egg` portion so the `install_requires` recognizes the package
        'git+ssh://git@github.com/example_org/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)

较新版本的 pip 不再需要使用“dependency_links”,从而使这变得更加容易-

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository
        'ExampleRepo @ git+ssh://git@github.com/example_org/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)

但是,对于最新的 pip,您会遇到 EGG 格式处理程序的问题。这是因为当 egg 被忽略时,pip 现在正在做直接的 URL 匹配,并且会考虑两个 URL,一个带有 egg 片段,另一个没有,即使它们指向同一个包,它们也是完全不同的版本。因此,最好不要留下任何鸡蛋碎片。

因此,向 Github 添加可与公共和私有存储库一起使用的依赖项的最佳方式(截至 2021 年 6 月):

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository
        'ExampleRepo @ git+ssh://git@github.com/example_org/ExampleRepo.git'
    ]
)

【讨论】:

  • 您能否详细说明-0.1 在您的方法中代表什么?您是从 git 版本还是从 setup.py 描述中获取版本号?
  • 来自 setup.py 文件——如果你想使用特定的分支或标签,你的格式会有所不同。
  • “不幸的是,其他答案不适用于私人存储库”这不再是真的Fox's 答案在不需要dependency_links(即deprecated)的情况下可以在私人仓库上工作
  • 这确实应该是最佳答案,它实际上与当前时间相关。
  • 这在运行python setup.py install 时似乎不起作用——它只对我适用于pip install -e [module_name]。对所有人都是这样吗?这是在 pip 21.1.3
【解决方案3】:

在挖掘了上面 cmets 中 @muon 链接的 pip issue 3939PEP-508 specification 之后,我发现通过 setup.py 使用 install_requires 中的此规范模式安装了我的私有 repo 依赖项(不再dependency_links):

install_requires = [
  'some-pkg @ git+ssh://git@github.com/someorgname/pkg-repo-name@v1.1#egg=some-pkg',
]

@v1.1 表示在 github 上创建的发布标签,可以替换为分支、提交或其他类型的标签。

【讨论】:

  • @Brian 能否提供官方声明的链接?
  • 请注意,如果您不想使用 SSH,可以使用git+https://github.com
  • 那么进行--upgrade 的正确方法是什么?即使我指定了标签版本,升级也会忽略较新的标签版本
  • @Elephant 不是超级官方,但这些至少是来自 PyPA 实际成员的 pip GitHub 项目上的 cmets:github.com/pypa/pip/issues/4187#issuecomment-415667805 和进一步解释:github.com/pypa/pip/issues/4187#issuecomment-415067034
  • 是否有适用于 pip 需求文件和install_requires 的协议?我通常使用模式install_requires=open("requirements.txt", "r").read().splitlines()
【解决方案4】:

更一般的答案:要从 requirements.txt 文件中获取信息,我会这样做:

from setuptools import setup, find_packages
from os import path

loc = path.abspath(path.dirname(__file__))

with open(loc + '/requirements.txt') as f:
    requirements = f.read().splitlines()

required = []
dependency_links = []

# Do not add to required lines pointing to Git repositories
EGG_MARK = '#egg='
for line in requirements:
    if line.startswith('-e git:') or line.startswith('-e git+') or \
            line.startswith('git:') or line.startswith('git+'):
        line = line.lstrip('-e ')  # in case that is using "-e"
        if EGG_MARK in line:
            package_name = line[line.find(EGG_MARK) + len(EGG_MARK):]
            repository = line[:line.find(EGG_MARK)]
            required.append('%s @ %s' % (package_name, repository))
            dependency_links.append(line)
        else:
            print('Dependency to a git repository should have the format:')
            print('git+ssh://git@github.com/xxxxx/xxxxxx#egg=package_name')
    else:
        required.append(line)

setup(
    name='myproject',  # Required
    version='0.0.1',  # Required
    description='Description here....',  # Required
    packages=find_packages(),  # Required
    install_requires=required,
    dependency_links=dependency_links,
)

【讨论】:

    【解决方案5】:

    实际上,如果你想让你的包可以递归安装(YourCurrentPackage 包括你的 SomePrivateLib),例如当您想将 YourCurrentPackage 包含到另一个中时(例如 OuterPackage → YourCurrentPackage → SomePrivateLib),您将需要两者:

    install_requires=[
        ...,
        "SomePrivateLib @ git+ssh://github.abc.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ],
    dependency_links = [
        "git+ssh://github.abc.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
    

    并确保您有一个使用您的版本号创建的标签。

    此外,如果您的 Git 项目是私有的,并且您希望将其安装在容器中,例如 DockerGitLab 运行器,则您需要获得对您的存储库的授权访问权限。请考虑使用带有访问令牌的 Git + HTTPS(例如在 GitLab 上:https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html):

    import os
    from setuptools import setup
    
    TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')
    
    setup(
        ....
    
        install_requires=[
                ...,
                f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
        ],
        dependency_links = [
                f"git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
        ]
    )
    

    更新:

    如果您希望在 requirements.txt 文件中具有此依赖项,则必须将 #egg=SomePrivateLib 放在依赖项行的末尾。否则 pip install -r requirements.txt 对你不起作用,你会得到类似的东西:

    错误:无法检测到需求名称 'git+https://gitlab-ci-token:gitlabtokenvalue@gitlab.server.com/abc/SomePrivateLib.git@0.1.0', 请用#egg=your_package_name 指定一个

    如果你使用 reuirements.txt,这部分负责将在 python_home_dir/src 中创建的依赖文件夹的名称和 中的 egg-link 的名称em>site-packages/

    您可以在 requirements.txt 中使用环境变量将依赖项的令牌值安全地存储在您的 repo 中:

    requrements.txt 文件中针对这种情况的示例行:

    ....
    
    -e git+https://gitlab-ci-token:${EXPORTED_VAR_WITH_TOKEN}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib
    ....
    

    【讨论】:

      【解决方案6】:

      我在GitLab 中成功使用了这三个选项。我使用的是 GitLab 11 版。

      选项 1 - 未指定令牌。 shell 将提示输入用户名/密码。

      from setuptools import setup
      
      TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')
      
      setup(
          install_requires=[
              "SomePrivateLib @ git+https://gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
          ]
      )
      

      选项 2 - 指定用户访问令牌。通过转到 GitLab → 帐户右上角 → 设置 → 访问令牌生成的令牌。创建具有 read_repository 权限的令牌。

      例子:

      import os
      from setuptools import setup
      
      TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')
      
      setup(
          install_requires=[
              f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
          ]
      )
      

      选项 3 - 指定的存储库级令牌。通过转到存储库→设置→存储库→部署令牌生成的令牌。从这里,创建一个具有 read_repository 权限的令牌。

      例子:

      import os
      from setuptools import setup
      
      TOKEN_USER = os.getenv('EXPORTED_TOKEN_USER')
      TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')
      
      setup(
          install_requires=[
              f"SomePrivateLib @ git+https://{TOKEN_USER}:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
          ]
      )
      

      在这三个中,我能够简单地做到:“SomePrivateLib @ git+https://gitlab.server.com/abc/SomePrivateLib.git”,最后没有#egg 标记。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-02-25
        • 2020-09-28
        • 1970-01-01
        • 2014-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多