python要求:如何获得相同的版本?

时间:2018-05-02 13:25:42

标签: python virtualenv pipenv

这个问题是校长的结果 需求说明的解决方案:

python django pip update problems: how to get compatible versions?

我尝试在服务器之间同步python需求 和当地的发展系统。两者都是Ubuntu 16.04。, 所以这应该是一个问题。 服务器给我一个需求文件(在pip-installation django之后,如另一个quwtion中所述)。

但是在本地计算机上安装需求会产生一些错误, 像这样:

Could not find a version that satisfies the requirement python-    
apt==1.1.0b1 (from -r requirements.txt (line 3)) (from versions: 0.0.0, 
0.7.8) No matching distribution found for python-apt==1.1.0b1 (from -r 
requirements.txt

有没有办法确保在类似系统上满足要求 没有因版本不兼容而导致的错误 (或者因为改变性地解​​决了不相容问题)?

我需要虚拟环境来解决这个问题吗? 甚至是pipenv? 或者有一个简单直接的方法来拥有两个系统 兼容的python和包环境?

2 个答案:

答案 0 :(得分:3)

问题

此特定模块(python-apt)是only available on PyPi with version 0.7.8。但是,此版本似乎是一个错误!

python-apt has stated the following的开发人员和Debian软件包维护者之一:

Aargh,不再是整个PyPI。从未有人正式 在这里上传了python-apt。它与APT紧密结合,并且 除通过发行外,不应以任何其他方式发行 Debian软件包。

没有,而且从来没有对PyPi的支持。我可以 说我绝对不愿意在那里重复工作。 Source: Debian "Deity" Mailing List 2016-11-22 msg#00094

您可以从apt安装python-apt,我们没有在python-apt上提供pip。最近,我控制了pypi条目,需要对其进行处理。尽管(python-apt和apt版本xy需要匹配),但我不愿意在发行版之外提供python-apt,所以我宁愿放弃它,所以人们会停下来询问过时的版本。 Source: python-apt#1883451

因此,至少对于这种依赖关系,当通过pip + PyPi原生解决python依赖关系时,我们似乎不走运。幸运的是,上游项目托管在salsa.debian.org GitLab实例上,并且pip现在支持git+个SCM url,以及其他选项。

解决方案:

通常,有许多解决此依赖性的解决方案。您要解决的问题是:

  • 此软件包从何处提供?
    • 系统操作系统软件包管理器
    • 任意上游发行网址
    • 开发SCM存储库
    • 带有错误修正的分叉Git回购
    • 等...
  • 您将安装什么版本?
    • 兼容性问题:
      • 必须为>= 2.0.0
      • 分叉的仓库/功能分支,带有一些错误修正
      • API兼容性:不大于2.x / Semantic Versioning
    • 发展:
      • 只使用最新的和最大的(最前沿的)
      • 为我的平台或系统使用特定版本(例如:系统OS软件包,开发目录中的本地分叉版本)
    • 质量检查/测试:
      • 针对特定版本进行测试
      • 针对最新版本(例如每晚构建)进行测试
      • 针对系统操作系统版本提供的版本进行测试
  • 应如何解决依赖性?
    • pip-module-name + version constraint的“抽象”依赖
      • 以后可以使用 where 进行收集(URL / PyPi / Artifactory)和 什么 版本可以满足约束条件。
      • 如果需要,用户可以始终通过指定pip的参数,使用特定的virtualenv进行安装等来覆盖这些内容。
    • 对特定URL +程序包名称+版本的“具体”依赖
      • 极端情况:使用校验和验证锁定到特定的URL +版本+ sha1 / sha256 / sha**,以确保确切的位置和文件的完整性。
      • 灵活性较差,但可以肯定地锁定了确切的版本和来源。
  • 您是在开发“应用程序”还是“库” / Python模块?
    • 是否需要使用pip setup.py样式解析通过install_requires = [...]安装依赖项? (图书馆)
    • 应用程序安装程序是否需要通过pip install -r requirements.txt安装依赖项? (应用程序)
  • 您的项目将如何发布?
    • 谁将安装该软件包,以及如何允许他们的系统解决该依赖关系?
    • 这是要作为库在PyPi上发布,还是作为应用程序在其他地方发布? (遵循一些经验法则)
      • 通常来说:
        • 图书馆往往希望拥有开放式的版本说明符
        • 应用程序需要非常具体的依赖项来确保稳定性(很多依赖项意味着很多未经测试的版本排列!)
      • 使用setup.py指定PyPi的库依赖项
      • 使用requirements.txt指定应用程序的依赖项
    • 这将被打包为本地OS软件包吗? (例如:.deb.rpm.apk等)
      • 本机软件包管理器也具有依赖项解析...也许可以使用它来确保本机兼容性!
    • 您的软件包将支持哪些其他OS平台以及这些平台将如何解决依赖关系?

因此,大多数情况下,我们可以看到所有与 所需特异性 有关的问题,这些问题在哪里以及如何解决和安装这些依赖项。这里没有“一刀切”的解决方案...有优缺点,只有许多不同的解决方案可以满足以下需求:

more specific <---------------------> less specific
reliable compatibility                reliable installability
less testing permutations             more (possibly un-vetted) testing permutations
limited platform support              more platform support (when more permutations are well tested)
dependable known configurations       less dependable known configurations                        
less platform tolerant                more tolerant and agnostic of platforms
more OS native                        less OS native

GitLab上游回购中最新,最伟大的

解决python-apt软件包问题的一种方法是使用git+中的requirements.txt URL功能。这对于使用GitLab的python-apt上游版本进行开发非常有用。为了进一步将安装与系统OS提供的python-apt版本隔离开,可能需要virtualenvpip install --user。例如:

requirements.txt

--index-url https://pypi.python.org/simple/

-e git+https://salsa.debian.org/apt-team/python-apt.git#egg=python-apt
-e .

此示例项目可用于包含setup.py的示例项目:

[...SNIP...] # Boilerplate stuff here

setup(

#[...SNIP...] # Other setup() args here

    platforms=['linux'],
    # Reference:
    #  - https://github.com/pypa/interoperability-peps/pull/30/files#r184839487
    # sudo apt install python3-apt apt-rdepends apt
    # os_requires=[
    #     ['python3-apt', type='packagename', target='run', os='ubuntu'],
    #     ['apt-rdepends', type='packagename', target='run', os='ubuntu'],
    #     ['apt', type='packagename', target='run', os='ubuntu']
    #     ['libapt-pkg-dev', type='packagename', target='build', os='ubuntu']
    # ]
    # Build-deps for apt-python via git SCM: sudo apt install libapt-pkg-dev 
    python_requires='>=3.5',
    install_requires=[
        'python-apt (>= 2.0)',
        # rest of your dependencies here
        #[... SNIP ...]
    ],
    package_dir={'': 'lib'},
    scripts=_glob('bin/*'),

#[...SNIP...]

)

注意:os_requires isn't actually supported yet, but is proposed for a PEP。将来这可能会有助于软件包的外部依赖关系。在不通过PyPi / pip分发python模块,而是仅通过OS上的apt / .deb软件包提供python模块的情况下,这将很有帮助。

设置virtualenv或根据需要使用pip3 install --user,然后继续。 运行git+时,使用pip3 install -r requirements.txt需求功能会导致以下结果:

$ pip3 install -r requirements.txt
Looking in indexes: https://pypi.python.org/simple/
Obtaining file:///../example-project (from -r requirements.txt (line 4))
Obtaining python-apt from git+https://salsa.debian.org/apt-team/python-apt.git#egg=python-apt (from -r requirements.txt (line 3))
  Updating ./example-project-venv/src/python-apt clone
  Running command git fetch -q --tags
  Running command git reset --hard -q c97d4159beae2f9cd42d55d3dff9c37f5c69aa44
ERROR: example-project 0.0.1 has requirement python-apt>=2.0, but you'll have python-apt 0.0.0 which is incompatible.
Installing collected packages: python-apt, example-project
  Running setup.py develop for python-apt
  Running setup.py develop for example-project
Successfully installed example-project python-apt

注意:您可能想先为setup.py安装运行时和build / python-apt依赖项:

# Runtime deps (e.g.: Ubuntu 20.04 needs python3-apt, <20.04 needs python-apt):
sudo apt install python3-apt apt
# python-apt pip install deps (also for setup.py / development)
sudo apt install libapt-pkg-dev

替代:dependency_links(注意:可能已弃用)

如果您正在开发库类型模块,并且还希望使用GitLab作为python-apt 的源代码,则可能需要考虑将setup.py中的using dependency_linksgit+中提供http(s)requirements.txt的tarball发布URL。这有助于将“应用程序” python项目与“库” Python模块项目区分开。这完全取决于项目的安装过程。 (例如:您要pip install -r requirements.txt,还是pip install example-modulepython[3] setup.py {sdist,bdist,bdist_rpm, etc...}。为分叉版本python-apt指定自定义URL也可能会有所帮助。 ,此方法 可能很快就会被弃用 (如果在pip的新版本中尚未部分淘汰),您可能希望考虑其他选择,以便将来-证明您的依赖性规范,例如PEP 508pip install --find-links ...

此外,"application" vs "library" distinction以及“抽象”与“具体”依赖项的概念也很重要。快速摘要可能是:

抽象和具体之间的这种区别是重要的。它是 是什么使PyPI镜像基础架构能够正常工作。是什么 允许公司托管自己的私有软件包索引。甚至 是什么使您能够派生一个库来修复错误或添加功能,以及 用你自己的叉子。因为抽象依赖关系是名称和 可选的版本说明符,您可以从PyPI或从 Crate.io,或从您自己的文件系统。您可以派生一个库,更改 代码,只要它具有正确的名称和版本说明符 该库将愉快地继续使用它。

Setuptools具有类似于Go示例的功能。叫做 依赖关系链接,看起来像这样:


setup(
    # ...
    dependency_links = [
        "http://packages.example.com/snapshots/",
        "http://example2.com/p/bar-1.0.tar.gz",
    ], ) ```

This “feature” of setuptools removes the abstractness of its
dependencies and hardcodes an exact url from which you can fetch the
dependency from. Now very similarly to Go if we want to modify
packages, or simply fetch them from a different server we’ll need to
go in and edit each package in the dependency chain in order to update
the dependency_links.

Source: caremad.io Blog Post: setup.py vs requirements.txt

对于此python-apt示例,我们可以使用类似的方法来锁定v2.0.0上的“具体依赖项”:


setup(
    # [...SNIP...]
    dependency_links = [
        "https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz#egg=python-apt"
    ],
    # [...SNIP...]
) `

注意:此“错误功能”为briefly removed,然后在指定私有软件包依赖项URL时为brought back赋予了some usefulness。但是,目前pip --process-dependency-links标志已被弃用,因此其作用可能仅限于Python 2 + pip的旧版本。

替代:PEP 508 Syntax

Newer versions of pip now have URL support for PEP 508 syntax。这可能是使用复杂语法指定具体和抽象依赖关系的最可靠的方法(有关详细信息,请参见PEP 508)。现在可以通过多种方式指定软件包,包括自定义URL。

例如,使用可选的python-apt校验和将v2.0.0锁定到sha256

setup(
    # [...SNIP...]
    install_requires=[
        'python-apt@https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz#sha256=1ddbd3eb7cbc1ded7e0e8a2dd75219f0c59c7e062c6e6bfd5c8ff6f656c59a4e',
        # [...SNIP...]
    ],
    # [...SNIP...]
)

requirements.txt

--index-url https://pypi.python.org/simple/

-e .

然后,pip install -r requirements.txt仍然可以正常运行,没有任何额外的标志:

$ ./example-project-venv/bin/python3 ./example-project-venv/bin/pip3 install -r requirements.txt 
Looking in indexes: https://pypi.python.org/simple/
Obtaining file://./src/pub/example-project (from -r requirements.txt (line 4))
Requirement already satisfied: graph-tools>=1.5 in ./example-project-venv/lib/python3.8/site-packages (from example-project==0.0.1->-r requirements.txt (line 4)) (1.5)
Collecting python-apt@ https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz#sha256=1ddbd3eb7cbc1ded7e0e8a2dd75219f0c59c7e062c6e6bfd5c8ff6f656c59a4e
  Using cached https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz (458 kB)
Building wheels for collected packages: python-apt
  Building wheel for python-apt (setup.py) ... done
  Created wheel for python-apt: filename=python_apt-0.0.0-cp38-cp38-linux_x86_64.whl size=2040980 sha256=79eeb0d1bb9e3c9785acb68f164a3f72a5777539137d180e9ded7558d2547a49
  Stored in directory: ~/.cache/pip/wheels/c4/09/b5/36fc8c9a1ebe8786620db922f1495da200dce187ee7c618993
Successfully built python-apt
Installing collected packages: python-apt, example-project
  Attempting uninstall: example-project
    Found existing installation: example-project 0.0.1
    Uninstalling example-project-0.0.1:
      Successfully uninstalled example-project-0.0.1
  Running setup.py develop for example-project
Successfully installed example-project python-apt-0.0.0

替代:pip install --find-links ...

安装锁定到特定版本的“具体依赖项”的另一种替代方法是使用已发布的tarball文件将--find-links传递到pip install。在给定发布URL的情况下,此方法可能有助于显式安装特定版本。例如,使用python-apt v2.0.0

$ ./example-project-venv/bin/python3 ./example-project-venv/bin/pip3 install --find-links 'https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz' -r requirements.txt 
Looking in indexes: https://pypi.python.org/simple/
Looking in links: https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz
Obtaining file://./example-project (from -r requirements.txt (line 4))
Requirement already satisfied: graph-tools>=1.5 in ./example-project-venv/lib/python3.8/site-packages (from example-project==0.0.1->-r requirements.txt (line 4)) (1.5)
Collecting python-apt>=2.0
  Downloading https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz (458 kB)
     |████████████████████████████████| 458 kB 614 kB/s 
  WARNING: Requested python-apt>=2.0 from https://salsa.debian.org/apt-team/python-apt/-/archive/2.0.0/python-apt-2.0.0.tar.gz (from example-project==0.0.1->-r requirements.txt (line 4)), but installing version 0.0.0
Building wheels for collected packages: python-apt
  Building wheel for python-apt (setup.py) ... done
  Created wheel for python-apt: filename=python_apt-0.0.0-cp38-cp38-linux_x86_64.whl size=2040783 sha256=d0a8f88c04f202e948b9855837140517d9b2bd3cef72e626221614552a476780
  Stored in directory: ~/.cache/pip/wheels/8a/07/e9/b3c3328bac08c030a5b1e754e01e327b62fd26f9baedf07c15
Successfully built python-apt
ERROR: example-project 0.0.1 has requirement python-apt>=2.0, but you'll have python-apt 0.0.0 which is incompatible.
Installing collected packages: python-apt, example-project
  Attempting uninstall: python-apt
    Found existing installation: python-apt 0.0.0
    Uninstalling python-apt-0.0.0:
      Successfully uninstalled python-apt-0.0.0
  Attempting uninstall: example-project
    Found existing installation: example-project 0.0.1
    Uninstalling example-project-0.0.1:
      Successfully uninstalled example-project-0.0.1
  Running setup.py develop for example-project
Successfully installed example-project python-apt-0.0.0

基本系统Debian软件包

在Debian和Ubuntu上,您会在不同的发行版本上看到两个.deb软件包:python3-aptpython-apt(对于Python2)。

These packages are managed由APT软件包管理器安装,因此安装在系统位置:/usr/lib/python3/dist-packages/usr/lib/python2.7/dist-packages分别用于Python3和Python2.7。

dist-packages路径和其他Python打包约定为explained well in this post

系统已将Python软件包安装在每个Python版本的全局dist-packages目录中,并创建了符号链接:

/usr/lib/python2.7/dist-packages/numpy

/usr/lib/python3/dist-packages/numpy

ls -ls /usr/include/numpy
#-> ../lib/python2.7/dist-packages/numpy/core/include/numpy

ls -l /usr/include/python2.7/numpy
#->../../lib/python2.7/dist-packages/numpy/core/include/numpy

ls -l /usr/include/python3.5/numpy
#-> ../../lib/python3/dist-packages/numpy/core/include/numpy

请注意dist-packages而不是site-packages的良好用法,应将其保留给系统Python。

因此,如果您要使用python3-apt的基本OS系统级别版本,则需要确保此路径位于sys.pathPYTHONPATH上因此import apt将起作用。而如果您想使用site-packages位置或virtualenv位置,则这些位置必须存在于sys.path / PYTHONPATH上。

不幸的是,as mentioned before还没有一种正式的方法来声明对提供特定版本python模块的OS软件包的依赖。但是,只要您管理python运行时环境的import路径,就应该能够使用dist-packages目录中的OS软件包中的正确版本。

答案 1 :(得分:0)

事实上,python-apt的最新版本是0.7.8 https://pypi.org/project/python-apt/

如果您100%确定它是相同的包,请尝试在requirements.txt文件中更改它。

另一方面,您可以尝试查看本地python-apt的位置。

import apt
print(apt.__file__)  # or print(apt.__path__)

然后,去那里手动检查那个python-apt包是什么。