标签归档:requirements.txt

如何为多个环境自定义requirements.txt?

问题:如何为多个环境自定义requirements.txt?

我有两个分支,开发和生产。每个都有依赖关系,其中一些是不同的。开发指向自身在开发中的依赖项。生产同样如此。我需要部署到Heroku,它期望每个分支的依赖性都在一个名为“ requirements.txt”的文件中。

最好的组织方式是什么?

我想到的是:

  • 维护单独的需求文件,每个分支中一个(必须在频繁合并中生存!)
  • 告诉Heroku我要使用哪个需求文件(环境变量?)
  • 编写部署脚本(创建临时分支,修改需求文件,提交,部署,删除临时分支)

I have two branches, Development and Production. Each has dependencies, some of which are different. Development points to dependencies that are themselves in development. Likewise for Production. I need to deploy to Heroku which expects each branch’s dependencies in a single file called ‘requirements.txt’.

What is the best way to organize?

What I’ve thought of:

  • Maintain separate requirements files, one in each branch (must survive frequent merges!)
  • Tell Heroku which requirements file I want to use (environment variable?)
  • Write deploy scripts (create temp branch, modify requirements file, commit, deploy, delete temp branch)

回答 0

您可以级联需求文件,并使用“ -r”标志告诉pip将一个文件的内容包含在另一个文件中。您可以将需求分解成模块化的文件夹层次结构,如下所示:

`-- django_project_root
|-- requirements
|   |-- common.txt
|   |-- dev.txt
|   `-- prod.txt
`-- requirements.txt

文件的内容如下所示:

common.txt:

# Contains requirements common to all environments
req1==1.0
req2==1.0
req3==1.0
...

dev.txt:

# Specifies only dev-specific requirements
# But imports the common ones too
-r common.txt
dev_req==1.0
...

prod.txt:

# Same for prod...
-r common.txt
prod_req==1.0
...

在Heroku之外,您现在可以设置如下环境:

pip install -r requirements/dev.txt

要么

pip install -r requirements/prod.txt

由于Heroku在项目根目录中专门查找“ requirements.txt”,因此应仅镜像prod,如下所示:

requirements.txt:

# Mirrors prod
-r requirements/prod.txt

You can cascade your requirements files and use the “-r” flag to tell pip to include the contents of one file inside another. You can break out your requirements into a modular folder hierarchy like this:

`-- django_project_root
|-- requirements
|   |-- common.txt
|   |-- dev.txt
|   `-- prod.txt
`-- requirements.txt

The files’ contents would look like this:

common.txt:

# Contains requirements common to all environments
req1==1.0
req2==1.0
req3==1.0
...

dev.txt:

# Specifies only dev-specific requirements
# But imports the common ones too
-r common.txt
dev_req==1.0
...

prod.txt:

# Same for prod...
-r common.txt
prod_req==1.0
...

Outside of Heroku, you can now setup environments like this:

pip install -r requirements/dev.txt

or

pip install -r requirements/prod.txt

Since Heroku looks specifically for “requirements.txt” at the project root, it should just mirror prod, like this:

requirements.txt:

# Mirrors prod
-r requirements/prod.txt

回答 1

今天发布原始问题和答案时不存在的可行选择是使用pipenv而不是pip管理依赖项。

使用pipenv,不再需要像pip一样手动管理两个单独的需求文件,而是通过命令行上的交互来管理开发和生产包本身。

要安装用于生产和开发的软件包:

pipenv install <package>

要仅为开发环境安装软件包:

pipenv install <package> --dev

通过这些命令,pipenv在两个文件(Pipfile和Pipfile.lock)中存储和管理环境配置。Heroku当前的Python buildpack本机支持pipenv,如果存在Pipfile.lock而不是requirements.txt,它将从Pipfile.lock进行配置。

有关该工具的完整文档,请参见pipenv链接。

A viable option today which didn’t exist when the original question and answer was posted is to use pipenv instead of pip to manage dependencies.

With pipenv, manually managing two separate requirement files like with pip is no longer necessary, and instead pipenv manages the development and production packages itself via interactions on the command line.

To install a package for use in both production and development:

pipenv install <package>

To install a package for the development environment only:

pipenv install <package> --dev

Via those commands, pipenv stores and manages the environment configuration in two files (Pipfile and Pipfile.lock). Heroku’s current Python buildpack natively supports pipenv and will configure itself from Pipfile.lock if it exists instead of requirements.txt.

See the pipenv link for full documentation of the tool.


回答 2

如果您的要求是能够在同一台计算机上的环境之间进行切换,则可能有必要为需要切换到的每个环境创建不同的virtualenv文件夹。

python3 -m venv venv_dev
source venv_dev/bin/activate
pip install -r pip/common.txt
pip install -r pip/dev.txt
exit
python3 -m venv venv_prod
source venv_prod/bin/activate
pip install -r pip/common.txt
exit
source venv_dev/bin/activate
# now we are in dev environment so your code editor and build systems will work.

# let's install a new dev package:
# pip install awesome
# pip freeze -r pip/temp.txt
# find that package, put it into pip/dev.txt
# rm pip/temp.txt

# pretty cumbersome, but it works. 

If your requirement is to be able to switch between environments on the same machine, it may be necessary to create different virtualenv folders for each environment you need to switch to.

python3 -m venv venv_dev
source venv_dev/bin/activate
pip install -r pip/common.txt
pip install -r pip/dev.txt
exit
python3 -m venv venv_prod
source venv_prod/bin/activate
pip install -r pip/common.txt
exit
source venv_dev/bin/activate
# now we are in dev environment so your code editor and build systems will work.

# let's install a new dev package:
# pip install awesome
# pip freeze -r pip/temp.txt
# find that package, put it into pip/dev.txt
# rm pip/temp.txt

# pretty cumbersome, but it works. 

使用pip命令从requirements.txt升级python软件包

问题:使用pip命令从requirements.txt升级python软件包

如何使用pip命令从requirements.txt文件升级所有python软件包?

尝试以下命令

$ pip install --upgrade -r requirements.txt

由于python软件包的后缀是版本号(Django==1.5.1),因此它们似乎没有升级。有没有比手动编辑requirements.txt文件更好的方法?

编辑

正如Andy在其答案中提到的那样,软件包已固定到特定版本,因此无法通过pip命令升级软件包。

但是,我们可以pip-tools使用以下命令来实现。

$ pip-review --auto

这将自动从requirements.txt中升级所有软件包(确保pip-tools使用pip install命令安装)。

How do I upgrade all my python packages from requirements.txt file using pip command?

tried with below command

$ pip install --upgrade -r requirements.txt

Since, the python packages are suffixed with the version number (Django==1.5.1) they don’t seem to upgrade. Is there any better approach than manually editing requirements.txt file?

EDIT

As Andy mentioned in his answer packages are pinned to a specific version, hence it is not possible to upgrade packages through pip command.

But, we can achieve this with pip-tools using the following command.

$ pip-review --auto

this will automatically upgrade all packages from requirements.txt (make sure to install pip-tools using pip install command).


回答 0

否。您的需求文件已固定到特定版本。如果您的要求设置为该版本,则不应尝试升级到那些版本之外。如果需要升级,则需要在需求文件中切换到未固定的版本。

例:

lxml>=2.2.0

这会将lxml升级到2.2.0以上的任何版本

lxml>=2.2.0,<2.3.0

这会将lxml升级到2.2.0和2.3.0之间的最新版本。

No. Your requirements file has been pinned to specific versions. If your requirements are set to that version, you should not be trying to upgrade beyond those versions. If you need to upgrade, then you need to switch to unpinned versions in your requirements file.

Example:

lxml>=2.2.0

This would upgrade lxml to any version newer than 2.2.0

lxml>=2.2.0,<2.3.0

This would upgrade lxml to the most recent version between 2.2.0 and 2.3.0.


回答 1

你可以试试:

pip install --upgrade --force-reinstall -r requirements.txt

您也可以忽略已安装的软件包并安装新的软件包:

pip install --ignore-installed -r requirements.txt

you can try:

pip install --upgrade --force-reinstall -r requirements.txt

You can also ignore installed package and install the new one :

pip install --ignore-installed -r requirements.txt

回答 2

我已经在这里回答了这个问题。这是我的解决方案:

因为没有简便的方法来逐个软件包升级软件包和更新requirements.txt文件,所以我写了这个pip-upgrader,它requirements.txt为所选软件包(或所有软件包)更新了文件中的版本

安装

pip install pip-upgrader

用法

激活您的virtualenv(这很重要,因为它还将在当前virtualenv中安装新版本的升级软件包)。

cd 进入您的项目目录,然后运行:

pip-upgrade

高级用法

如果需求放置在非标准位置,请将其作为参数发送:

pip-upgrade path/to/requirements.txt

如果您已经知道要升级的软件包,只需将它们作为参数发送:

pip-upgrade -p django -p celery -p dateutil

如果您需要升级到发行前/发行后版本,请添加 --prerelease请在命令中参数。

全面披露:我写了这个包裹。

I already answered this question here. Here’s my solution:

Because there was no easy way for upgrading package by package, and updating the requirements.txt file, I wrote this pip-upgrader which also updates the versions in your requirements.txt file for the packages chosen (or all packages).

Installation

pip install pip-upgrader

Usage

Activate your virtualenv (important, because it will also install the new versions of upgraded packages in current virtualenv).

cd into your project directory, then run:

pip-upgrade

Advanced usage

If the requirements are placed in a non-standard location, send them as arguments:

pip-upgrade path/to/requirements.txt

If you already know what package you want to upgrade, simply send them as arguments:

pip-upgrade -p django -p celery -p dateutil

If you need to upgrade to pre-release / post-release version, add --prerelease argument to your command.

Full disclosure: I wrote this package.


回答 3

我建议冻结所有依赖项,以使构建具有可预测性

这样做时,您可以像这样一次更新所有依赖项

sed -i '' 's/==/>=/g' requirements.txt
pip install -U -r requirements.txt
pip freeze > requirements.txt

完成上述操作后,请使用新的程序包集测试您的项目,并最终将文件提交requirements.txt到存储库。

I suggest freezing all of your dependencies in order to have predictable builds.

When doing that, you can update all dependencies at once like this:

sed -i '' 's/==/>=/g' requirements.txt
pip install -U -r requirements.txt
pip freeze > requirements.txt

Having done the above, test your project with the new set of packages and eventually commit the requirements.txt file to the repository.


回答 4

我只需要做同样的事情…用这个小的一线工作:

packages=$(cat requirements.txt | sed 's/==.*//g'); echo $packages | xargs pip3 install -U; freeze=$(pip3 freeze); for p in $(echo $packages); do echo $freeze | grep -E "^${p}==" >> requirements.new; done

哪一个:

  • packages=$(cat requirements.txt | sed 's/==.*//g') 在requirements.txt中创建当前软件包名称的列表(删除版本)。
  • echo $packages | xargs pip3 install -U 然后将所有软件包作为参数传递给pip3进行升级。
  • freeze=$(pip3 freeze); 以requirements.txt所需的格式获取所有当前软件包版本。
  • for p in $(echo $packages) 然后遍历软件包名称
    • echo $freeze | grep -E "^${p}==" >> requirements.new 从pip Frozen输出中获取与软件包匹配的软件包版本行,并写入新的requirements.txt

这具有保留原始requirements.txt的顺序的额外好处。:)

希望这可以帮助!

I’ve just had to do the same… used this small one-liner to do the job:

packages=$(cat requirements.txt | sed 's/==.*//g'); echo $packages | xargs pip3 install -U; freeze=$(pip3 freeze); for p in $(echo $packages); do echo $freeze | grep -E "^${p}==" >> requirements.new; done

which:

  • packages=$(cat requirements.txt | sed 's/==.*//g') creates a list of the current packages names in requirements.txt (removing the version).
  • echo $packages | xargs pip3 install -U then passes all of the packages as arguments to pip3 to upgrade.
  • freeze=$(pip3 freeze); Gets all of the current package versions in the format required for requirements.txt
  • for p in $(echo $packages) then iterates through the package names
    • echo $freeze | grep -E "^${p}==" >> requirements.new gets the package version line from the pip freeze output which matches the package and writes to new requirements.txt

This has the added benefit of preserving the ordering of the original requirements.txt. :)

Hope this helps!


回答 5

由于无法使用bash做到这一点,因此我编写了一个python模块来创建一个没有版本的新需求文件并使用它:

data = open('requirements-prod.pip', 'r')
data2 = open('requirements-prod-no-version.pip', 'w')
for line in data.readlines():
    new_line = line[:line.index('==')]
    data2.write(new_line + '\n')
data2.flush()

然后从新文件安装库 pip install -U -r requirements-prod-no-version.pip

最后将版本冻结到原始文件 pip freeze > requirements-prod.pip

Since I couldn’t do that using bash, I wrote a python module to create a new requirements file with no versions and use it:

data = open('requirements-prod.pip', 'r')
data2 = open('requirements-prod-no-version.pip', 'w')
for line in data.readlines():
    new_line = line[:line.index('==')]
    data2.write(new_line + '\n')
data2.flush()

Then install the libs from the new file pip install -U -r requirements-prod-no-version.pip

Finally freeze the versions to the original file pip freeze > requirements-prod.pip


回答 6

另一个解决方案是使用升级要求

pip install upgrade-requirements

然后运行:

upgrade-requirements

它将升级所有不是最新版本的软件包,并在最后创建一个更新的requirements.txt。

Another solution is to use the upgrade-requirements package

pip install upgrade-requirements

And then run :

upgrade-requirements

It will upgrade all the packages that are not at their latest versions, and also create an updated requirements.txt at the end.


回答 7

  • 1)要从reqs.txt升级pip安装的文件, 添加> =代替==, 这将告诉pip安装的lib大于或等于您请求的版本,此处安装的是请求的库的最新版本

    1.a)**我对线程的回答**通过将py -m pip install -r reqs.txt添加到每日重启中…或者类似的性质,您可以更新已安装的库。安迪完美总结

    -我进入此线程的原因是查找有关如何更新虚拟环境基本点的信息(通常对我来说是10.0.03 ??)

希望解决一个问题,我能够得出两个解决方案之一

A. venv创建|| B.安装必需的库

多亏了安迪,我满足了需求B

通过在reqs.txt中添加pip > = 请求的版本

在实例化新的虚拟环境后|| 重新说明以前的Venv

  1. py -m venv devenv

设置新的开发环境

  1. devenv\scripts\activate.bat

激活开发环境

  1. python -m pip install -r requirenments.txt

安装基本库

Yield输出

收集pip > = 20.0.2(从-r requirenments.txt(第1行))使用缓存的> https://files.pythonhosted.org/packages/54/0c/d01aa759fdc501a58f431eb594a17495f15b88da142ce14b5845662c13f3/pip-20.0.2-py2.py3-无任何

找到现有的安装:pip 10.0.1

卸载pip-10.0.1:

 Successfully uninstalled pip-10.0.1
 Successfully installed pip-20.0.2

对不起,我们希望可以帮助某人:)

🤳奥斯汀👨‍🎤🚀🥊

  • 1) To upgrade pip installed files from reqs.txt add the >= in replacement of == this will tell pip to install lib greater than or equal to the version you are requesting, here by installing the most to-date version of requested library

    1.a) **My answer for thread ** By adding py -m pip install -r reqs.txt to a daily restart… or something of the nature you can update your installed libs. Summed up by Andy Perfectly

    -My reason For entering this thread was to find information on how to update virtual env base pip (usually 10.0.03 for me??)

in-hopes of satisfying an issue of which have I was able to derive one of two solutions

A. creation of venv || B. Installation of Required libs

Thanks to Andy I have satisfied need B

By adding pip >= requested version in reqs.txt

upon instantiation of new virtual-Environment || re-instantiation of previous Venv

  1. py -m venv devenv

to setup new dev env

  1. devenv\scripts\activate.bat

to activate dev env

  1. python -m pip install -r requirenments.txt

to install base libs

yeilds output

Collecting pip >= 20.0.2 (from -r requirenments.txt (line 1)) Using cached >https://files.pythonhosted.org/packages/54/0c/d01aa759fdc501a58f431eb594a17495f15b88da142ce14b5845662c13f3/pip-20.0.2-py2.py3-none-any.whl

Found existing installation: pip 10.0.1

Uninstalling pip-10.0.1:

 Successfully uninstalled pip-10.0.1
 Successfully installed pip-20.0.2

Sorry for the Brain Dump, Hopes this helps someone :)

🤳 Austin 👨‍🎤🚀🥊


回答 8

第二个答案是最有用的,但是我想做的是锁定某些程序包,同时使其他程序包处于最新版本(例如youtube-dl)。

一个示例requirements.txt如下所示(〜表示兼容):

Pillow==6.2.2
requests~=2.22.0
youtube_dl

然后在终端中,使用命令 pip install --upgrade -r requirements.txt

这样可以确保Pillow保持在6.2.2,将请求升级到最新的2.22.x(如果有),如果尚未安装,则将安装最新版本的youtube-dl。

The second answer is the most useful but what I wanted to do is lock some packages while having others at the latest version (e.g. youtube-dl).

An example requirements.txt would look like this (~ means compatible):

Pillow==6.2.2
requests~=2.22.0
youtube_dl

Then in the terminal, use the command pip install --upgrade -r requirements.txt

This ensures that Pillow will stay at 6.2.2, requests will be upgraded to the latest 2.22.x (if available), and the latest version of youtube-dl will be installed if not already.


回答 9

我猜最简单的解决方案是使用以下命令创建requirements.txt:

pip freeze | sed 's/==/>=/' > requirements.txt

I guess the simplest solution is creating the requirements.txt with:

pip freeze | sed 's/==/>=/' > requirements.txt

回答 10

如果您在django项目中安装了任何内容,并且在安装后想要更新需求文件,则此命令可以更新您required.txt文件pip冻结> requirements.txt

如果您的需求文件不存在于项目中,则可以使用此命令来创建新的需求文件。

If you install anything in your django project and after installation you want to update your requirement file this command can update you requirement.txt file pip freeze > requirements.txt

if your requirement file not exist in you project you can use this command for make new requirement.txt file pip freeze > requirements.txt


回答 11

我按如下所示编辑requirements.txt并运行$ sh ./requirements.txt

pip install -U amqp;
pip install -U appdirs;
pip install -U arrow;
pip install -U Babel;
pip install -U billiard;
pip install -U celery;
pip install -U Django;
pip install -U django-cors-headers;
pip install -U django-crispy-forms;
pip install -U django-filter;
pip install -U django-markdown-deux;
pip install -U django-pagedown;
pip install -U django-timezone-field;
pip install -U djangorestframework;
pip install -U fcm-django;
pip install -U flower;
pip install -U gunicorn;
pip install -U kombu;
pip install -U Markdown;
pip install -U markdown2;
pip install -U packaging;

I edit the requirements.txt as below and run $sh ./requirements.txt

pip install -U amqp;
pip install -U appdirs;
pip install -U arrow;
pip install -U Babel;
pip install -U billiard;
pip install -U celery;
pip install -U Django;
pip install -U django-cors-headers;
pip install -U django-crispy-forms;
pip install -U django-filter;
pip install -U django-markdown-deux;
pip install -U django-pagedown;
pip install -U django-timezone-field;
pip install -U djangorestframework;
pip install -U fcm-django;
pip install -U flower;
pip install -U gunicorn;
pip install -U kombu;
pip install -U Markdown;
pip install -U markdown2;
pip install -U packaging;

requirements.txt与setup.py

问题:requirements.txt与setup.py

我开始使用Python。我已经添加了requirements.txtsetup.py我的项目。但是,我仍然对两个文件的目的感到困惑。我读过,它setup.py是为可再发行的事物而requirements.txt设计的,并且是为不可再发行的事物而设计的。但是我不确定这是正确的。

如何真正使用这两个文件?

I started working with Python. I’ve added requirements.txt and setup.py to my project. But, I am still confused about the purpose of both files. I have read that setup.py is designed for redistributable things and that requirements.txt is designed for non-redistributable things. But I am not certain this is accurate.

How are those two files truly intended to be used?


回答 0

requirements.txt

这可以帮助您设置开发环境。诸如此类的程序pip可用于一次安装文件中列出的所有软件包。之后,您可以开始开发python脚本。如果您计划让其他人参与开发或使用虚拟环境,则特别有用。这是您的用法:

pip install -r requirements.txt

setup.py

这使您可以创建可以重新分发的软件包。该脚本旨在将软件包安装在最终用户的系统上,而不是像在准备开发环境那样pip install -r requirements.txt。有关setup.py的更多详细信息,请参见此答案

两个文件中都列出了项目的依赖项。

requirements.txt:

This helps you to set up your development environment.

Programs like pip can be used to install all packages listed in the file in one fell swoop. After that you can start developing your python script. Especially useful if you plan to have others contribute to the development or use virtual environments. This is how you use it:

pip install -r requirements.txt

setup.py:

This helps you to create packages that you can redistribute.

The setup.py script is meant to install your package on the end user’s system, not to prepare the development environment as pip install -r requirements.txt does. See this answer for more details on setup.py.


The dependencies of your project are listed in both files.


回答 1

简短的答案是requirements.txt仅列出软件包要求。setup.py另一方面更像是一个安装脚本。如果您不打算安装python代码,通常只需要requirements.txt

该文件setup.py除了描述软件包的依赖关系之外,还描述了应打包(或编译,对于本机模块(即,用C编写)的文件和模块)和添加到python软件包列表中的元数据(例如,程序包名称,程序包版本,程序包描述,作者等)。

因为两个文件都列出了依赖性,所以这可能会导致一些重复。请阅读下面的详细信息。

requirements.txt


该文件列出了python软件包的要求。这是一个纯文本文件(可选带注释),列出了python项目的程序包依赖项(每行一个)。它没有描述python软件包的安装方式。通常,您将使用消耗需求文件pip install -r requirements.txt

文本文件的文件名是任意的,但通常requirements.txt是约定的。浏览其他python软件包的源代码存储库时,您可能会偶然发现其他名称,例如dev-dependencies.txtdependencies-dev.txt。它们具有与特定目的相同的目的,dependencies.txt但通常列出特定软件包开发人员感兴趣的其他依赖项,即在发布之前测试源代码(例如pytest,pylint等)。程序包的用户通常不需要整个开发人员依赖项来运行程序包。

如果requirements-X.txt存在多个变体,则通常一个将列出运行时依赖性,而另一个将列出运行时依赖性或测试依赖性。一些项目还会层叠其需求文件,即一个需求文件包含另一个文件时(例如)。这样做可以减少重复。

setup.py


这是一个python脚本,使用该setuptools模块定义python包(名称,包含的文件,包元数据和安装)。像一样requirements.txt,它将列出软件包的运行时依赖项。Setuptools是构建和安装python软件包的实际方法,但是它也有缺点,随着时间的流逝,它催生了新的“元软件包管理器”(如pip)的开发。setuptools的示例缺点是无法安装同一软件包的多个版本,并且缺少卸载命令。

当python用户这样做pip install ./pkgdir_my_module(或pip install my-module)时,pip将setup.py在给定目录(或模块)中运行。同样,setup.py可以pip安装任何具有的模块,例如,pip install .从同一文件夹运行。

我真的需要两者吗?


简短的答案是没有,但同时拥有它们是很好的。它们实现了不同的目的,但是都可以用来列出您的依赖项。

您可能需要考虑一种技巧,以避免在requirements.txt和之间复制依赖项列表setup.py。如果您已经setup.py为您的程序包编写了一个完整的文档,并且您的依赖关系大部分是外部的,则可以考虑requirements.txt仅使用以下内容:

 # requirements.txt
 #
 # installs dependencies from ./setup.py, and the package itself,
 # in editable mode
 -e .

 # (the -e above is optional). you could also just install the package
 # normally with just the line below (after uncommenting)
 # .

-e是一个特殊pip install选项,它以可编辑模式安装给定的软件包。如果pip -r requirements.txt是在这个文件运行时,PIP将通过在列表中安装您的依赖./setup.py。可编辑选项将在您的安装目录中放置一个符号链接(而不是egg或存档副本)。它允许开发人员从存储库中就地编辑代码,而无需重新安装。

当两个文件都位于软件包存储库中时,您还可以利用所谓的“ setuptools extras”。您可以在setup.py中的自定义类别下定义可选软件包,然后使用pip从该类别安装这些软件包:

# setup.py
from setuptools import setup
setup(
   name="FOO"
   ...
   extras_require = {
       'dev': ['pylint'],
       'build': ['requests']
   }
   ...
)

然后在需求文件中:

# install packages in the [build] category, from setup.py
# (path/to/mypkg is the directory where setup.py is)
-e path/to/mypkg[build]

这会将所有依赖项列表保留在setup.py中。

注意:通常,您可以从沙箱中执行pip和setup.py,例如使用program创建的virtualenv。这样可以避免在项目开发环境的上下文之外安装python软件包。

The short answer is that requirements.txt is for listing package requirements only. setup.py on the other hand is more like an installation script. If you don’t plan on installing the python code, typically you would only need requirements.txt.

The file setup.py describes, in addition to the package dependencies, the set of files and modules that should be packaged (or compiled, in the case of native modules (i.e., written in C)), and metadata to add to the python package listings (e.g. package name, package version, package description, author, …).

Because both files list dependencies, this can lead to a bit of duplication. Read below for details.

requirements.txt


This file lists python package requirements. It is a plain text file (optionally with comments) that lists the package dependencies of your python project (one per line). It does not describe the way in which your python package is installed. You would generally consume the requirements file with pip install -r requirements.txt.

The filename of the text file is arbitrary, but is often requirements.txt by convention. When exploring source code repositories of other python packages, you might stumble on other names, such as dev-dependencies.txt or dependencies-dev.txt. Those serve the same purpose as dependencies.txt but generally list additional dependencies of interest to developers of the particular package, namely for testing the source code (e.g. pytest, pylint, etc.) before release. Users of the package generally wouldn’t need the entire set of developer dependencies to run the package.

If multiplerequirements-X.txt variants are present, then usually one will list runtime dependencies, and the other build-time, or test dependencies. Some projects also cascade their requirements file, i.e. when one requirements file includes another file (example). Doing so can reduce repetition.

setup.py


This is a python script which uses the setuptools module to define a python package (name, files included, package metadata, and installation). It will, like requirements.txt, also list runtime dependencies of the package. Setuptools is the de-facto way to build and install python packages, but it has its shortcomings, which over time have sprouted the development of new “meta-package managers”, like pip. Example shortcomings of setuptools are its inability to install multiple versions of the same package, and lack of an uninstall command.

When a python user does pip install ./pkgdir_my_module (or pip install my-module), pip will run setup.py in the given directory (or module). Similarly, any module which has a setup.py can be pip-installed, e.g. by running pip install . from the same folder.

Do I really need both?


Short answer is no, but it’s nice to have both. They achieve different purposes, but they can both be used to list your dependencies.

There is one trick you may consider to avoid duplicating your list of dependencies between requirements.txt and setup.py. If you have written a fully working setup.py for your package already, and your dependencies are mostly external, you could consider having a simple requirements.txt with only the following:

 # requirements.txt
 #
 # installs dependencies from ./setup.py, and the package itself,
 # in editable mode
 -e .

 # (the -e above is optional). you could also just install the package
 # normally with just the line below (after uncommenting)
 # .

The -e is a special pip install option which installs the given package in editable mode. When pip -r requirements.txt is run on this file, pip will install your dependencies via the list in ./setup.py. The editable option will place a symlink in your install directory (instead of an egg or archived copy). It allows developers to edit code in place from the repository without reinstalling.

You can also take advantage of what’s called “setuptools extras” when you have both files in your package repository. You can define optional packages in setup.py under a custom category, and install those packages from just that category with pip:

# setup.py
from setuptools import setup
setup(
   name="FOO"
   ...
   extras_require = {
       'dev': ['pylint'],
       'build': ['requests']
   }
   ...
)

and then, in the requirements file:

# install packages in the [build] category, from setup.py
# (path/to/mypkg is the directory where setup.py is)
-e path/to/mypkg[build]

This would keep all your dependency lists inside setup.py.

Note: You would normally execute pip and setup.py from a sandbox, such as those created with the program virtualenv. This will avoid installing python packages outside the context of your project’s development environment.


回答 2

为了完整起见,以下是我从3 4个不同角度看待它的方法。

  1. 他们的设计目的是不同的

这是官方文档(重点是我的)中引用的精确描述:

尽管install_requires(在setup.py中)定义了单个项目的依赖关系,但“需求文件”通常用于定义完整Python环境的需求。

尽管install_requires需求最少,但是需求文件通常包含固定版本的详尽列表,目的是实现完整环境的可重复安装。

但是它可能仍然不容易理解,因此在下一节中,将提供2个事实示例,以不同的方式演示应如何使用这两种方法。

  1. 因此,它们的实际用法(应该是)不同

    • 如果您的项目foo将作为独立的库发布(意味着其他人可能会这样做import foo),那么您(和下游用户)将希望有一个灵活的依赖声明,以使您的库不会(而且一定不能) )对您的依赖项的确切版本“保持警惕”。因此,通常,您的setup.py将包含以下行:

      install_requires=[
          'A>=1,<2',
          'B>=2'
      ]
    • 如果您只是想以某种方式为您的应用程序“记录”或“固定”您的EXACT当前环境bar,这意味着您或您的用户希望bar按原样使用您的应用程序,即运行python bar.py,您可能希望冻结您的环境,以便它总是表现相同。在这种情况下,您的需求文件将如下所示:

      A==1.2.3
      B==2.3.4
      # It could even contain some dependencies NOT strickly required by your library
      pylint==3.4.5
  2. 实际上,我该使用哪一个?

    • 如果您正在开发bar将由所使用的应用程序python bar.py,即使该应用程序只是“有趣的脚本”,仍然建议您使用requirements.txt,因为谁知道下周(恰好是圣诞节)您会收到新计算机作为礼物,因此您需要在此重新设置您的确切环境。

    • 如果您正在开发foo将由所使用的库,则必须import foo准备setup.py。期。但是您仍然可以选择同时提供require.txt,它可以:

      (a)采用任何一种A==1.2.3风格(如上文第2条所述);

      (b)或只包含一个魔法单曲 .

      .

      大致等于“基于setup.py安装要求”,而无需重复。我个人认为这是最后一种方法,模糊了界限,增加了混乱,并没有真正增加价值,但这仍然是Python包装维护商Donald在他的博客文章中提到的一种方法。

  3. 下限不同。

    即使遵循了以上3条条件,并正确地决定了您的库hybrid-engine仍将使用a setup.py声明其依赖关系engine>=1.2.0,而示例应用程序reliable-car仍将使用requirements.txt其声明其依赖关系engine>=1.2.3,即使最新版本的engine1.4.0也是如此。如您所见,您对它们的下限数字的选择仍然略有不同。这就是为什么。

    • hybrid-engineengine>=1.2.0假设是因为,假设地,首先引入了所需的“内部燃烧”功能engine 1.2.0,而该功能是必不可少的hybrid-engine,而不管该版本内部是否存在某些(较小的)错误,并已在后续版本1.2.1中进行了修复。 ,1.2.2和1.2.3。

    • reliable-car取决于,engine>=1.2.3因为到目前为止,这是没有已知问题的最早版本。当然,以后的版本中会有新功能,例如引入了“电动机”和引入了engine 1.3.0“核反应堆” engine 1.4.0,但是对于项目而言,它们并不是必需的reliable-car

For the sake of completeness, here is how I see it in 3 4 different angles.

  1. Their design purposes are different

This is the precise description quoted from the official documentation (emphasis mine):

Whereas install_requires (in setup.py) defines the dependencies for a single project, Requirements Files are often used to define the requirements for a complete Python environment.

Whereas install_requires requirements are minimal, requirements files often contain an exhaustive listing of pinned versions for the purpose of achieving repeatable installations of a complete environment.

But it might still not easy to be understood, so in next section, there come 2 factual examples to demonstrate how the 2 approaches are supposed to be used, differently.

  1. Their actual usages are therefore (supposed to be) different

    • If your project foo is going to be released as a standalone library (meaning, others would probably do import foo), then you (and your downstream users) would want to have a flexible declaration of dependency, so that your library would not (and it must not) be “picky” about what exact version of YOUR dependencies should be. So, typically, your setup.py would contain lines like this:

      install_requires=[
          'A>=1,<2',
          'B>=2'
      ]
      
    • If you just want to somehow “document” or “pin” your EXACT current environment for your application bar, meaning, you or your users would like to use your application bar as-is, i.e. running python bar.py, you may want to freeze your environment so that it would always behave the same. In such case, your requirements file would look like this:

      A==1.2.3
      B==2.3.4
      # It could even contain some dependencies NOT strickly required by your library
      pylint==3.4.5
      
  2. In reality, which one do I use?

    • If you are developing an application bar which will be used by python bar.py, even if that is “just script for fun”, you are still recommended to use requirements.txt because, who knows, next week (which happens to be Christmas) you would receive a new computer as a gift, so you would need to setup your exact environment there again.

    • If you are developing a library foo which will be used by import foo, you have to prepare a setup.py. Period. But you may still choose to also provide a requirements.txt at the same time, which can:

      (a) either be in the A==1.2.3 style (as explained in #2 above);

      (b) or just contain a magical single .

      .
      

      which would roughly equal to “install the requirements based on setup.py” while without duplication. Personally I consider this last approach kind of blurs the line, adds to the confusion and does NOT really add value, but it is nonetheless a trick derived from an approach mentioned by Python packaging maintainer Donald in his blog post.

  3. Different lower bounds.

    Even after you have followed the above 3 criteria and correctly decided that your library hybrid-engine would use a setup.py to declare its dependency engine>=1.2.0, and your sample application reliable-car would use requirements.txt to declare its dependency engine>=1.2.3, even though the latest version of engine is already at 1.4.0. As you see, your choice for their lower bound number are still subtly different. And here is why.

    • hybrid-engine depends on engine>=1.2.0 because, hypothetically speaking, the needed “internal combustion” capability was first introduced in engine 1.2.0, and that capability is the necessity of hybrid-engine, regardless of whether there might be some (minor) bugs inside such version and been fixed in subsequent versions 1.2.1, 1.2.2, and 1.2.3.

    • reliable-car depends on engine>=1.2.3 because that is the earliest version WITHOUT known issues, so far. Sure there are new capabilities in later versions, say, “electric motor” introduced in engine 1.3.0, and “nuclear reactor” introduced in engine 1.4.0, but they are not necessary for project reliable-car.


在requirements.txt中,代字号(〜=)是什么意思?

问题:在requirements.txt中,代字号(〜=)是什么意思?

requirements.txt我正在使用的Python库中,其中一项要求指定为:

mock-django~=0.6.10

什么~=意思

In the requirements.txt for a Python library I am using, one of the requirements is specified like:

mock-django~=0.6.10

What does ~= mean?


回答 0

这意味着它将选择软件包的最新版本,大于或等于0.6.10,但仍为0.6。*版本,因此不会下载0.7.0。如果程序包维护者遵循语义版本控制(这表明重大更改应仅在主要版本中进行),则它可以确保获得安全修复程序,但保持向后兼容性。

或者,如PEP 440所述:

对于给定的发布标识符VN,兼容的发布子句近似等于一对比较子句:

>= V.N, == V.*

It means it will select the latest version of the package, greater than or equal to 0.6.10, but still in the 0.6.* version, so it won’t download 0.7.0 for example. It ensures you will get security fixes but keep backward-compatibility, if the package maintainer respects the semantic versioning (which states that breaking changes should occur only in major versions).

Or, as said by PEP 440:

For a given release identifier V.N , the compatible release clause is approximately equivalent to the pair of comparison clauses:

>= V.N, == V.*


回答 1

那就是“兼容版本”版本说明符

它等效于:mock-django >= 0.6.10, == 0.6.*,并且是一种匹配预期兼容版本的简洁方法。用简单的英语来说,这有点像说:“我需要一个模拟Django的版本,该版本至少是0.6.10的新版本,但又不是太新以至于与它不兼容。”

如果您不确定所有这些版本号,请快速查看PEP440版本方案吧!

That’s the ‘compatible release’ version specifier.

It’s equivalent to: mock-django >= 0.6.10, == 0.6.*, and is a tidy way of matching a version which is expected to be compatible. In plain English, it’s a bit like saying: “I need a version of mock-django which is at least as new as 0.6.10, but not so new that it isn’t compatible with it.”

If you’re not sure about all this version number stuff, a quick look at the PEP440 version scheme should sort you out!


回答 2

〜=表示兼容版本。不小于0.6.10和更高(0.6。*)。

~= means a compatible version. Not less than 0.6.10 and higher (0.6.*).


回答 3

兼容的发布子句由兼容的发布操作符〜=和版本标识符组成。它与预期与指定版本兼容的任何候选版本匹配。

您可以在这里阅读更多信息:https : //www.python.org/dev/peps/pep-0440/#compatible-release

A compatible release clause consists of the compatible release operator ~= and a version identifier. It matches any candidate version that is expected to be compatible with the specified version.

You can read more here: https://www.python.org/dev/peps/pep-0440/#compatible-release


找不到满足要求的版本

问题:找不到满足要求的版本

我正在使用以下requirements.txt文件在Ubuntu 12.04中安装几个Python软件包:

numpy>=1.8.2,<2.0.0
matplotlib>=1.3.1,<2.0.0
scipy>=0.14.0,<1.0.0
astroML>=0.2,<1.0
scikit-learn>=0.14.1,<1.0.0
rpy2>=2.4.3,<3.0.0

和这两个命令:

$ pip install --download=/tmp -r requirements.txt
$ pip install --user --no-index --find-links=/tmp -r requirements.txt

(第一个下载软件包,第二个安装软件包)。

该过程经常因错误而停止:

  Could not find a version that satisfies the requirement <package> (from matplotlib<2.0.0,>=1.3.1->-r requirements.txt (line 2)) (from versions: )
No matching distribution found for <package> (from matplotlib<2.0.0,>=1.3.1->-r requirements.txt (line 2))

我用以下方法手动修复:

pip install --user <package>

然后pip install再次运行第二个命令。

但这仅适用于特定程序包。当我pip install再次运行第二个命令时,该过程现在停止,并抱怨另一个必需的程序包,我需要再次重复该过程,即:手动安装新的必需程序包(使用上面的命令),然后运行第二个pip install命令。

到目前为止,我不得不手动安装sixpytznose,现在它在抱怨需要mock

有没有办法告诉pip您自动安装所有需要的依赖项,所以我不必一个个手动地进行安装?

添加:这仅在Ubuntu 12.04 BTW中发生。在Ubuntu 14.04中,pip install应用于requirements.txt文件的命令可以正常工作。

I’m installing several Python packages in Ubuntu 12.04 using the following requirements.txt file:

numpy>=1.8.2,<2.0.0
matplotlib>=1.3.1,<2.0.0
scipy>=0.14.0,<1.0.0
astroML>=0.2,<1.0
scikit-learn>=0.14.1,<1.0.0
rpy2>=2.4.3,<3.0.0

and these two commands:

$ pip install --download=/tmp -r requirements.txt
$ pip install --user --no-index --find-links=/tmp -r requirements.txt

(the first one downloads the packages and the second one installs them).

The process is frequently stopped with the error:

  Could not find a version that satisfies the requirement <package> (from matplotlib<2.0.0,>=1.3.1->-r requirements.txt (line 2)) (from versions: )
No matching distribution found for <package> (from matplotlib<2.0.0,>=1.3.1->-r requirements.txt (line 2))

which I fix manually with:

pip install --user <package>

and then run the second pip install command again.

But that only works for that particular package. When I run the second pip install command again, the process is stopped now complaining about another required package and I need to repeat the process again, ie: install the new required package manually (with the command above) and then run the second pip install command.

So far I’ve had to manually install six, pytz, nose, and now it’s complaining about needing mock.

Is there a way to tell pip to automatically install all needed dependencies so I don’t have to do it manually one by one?

Add: This only happens in Ubuntu 12.04 BTW. In Ubuntu 14.04 the pip install commands applied on the requirements.txt file work without issues.


回答 0

仅当目录包含所有软件包时,此方法(在目录中具有所有依赖项,而不是从索引下载)才有效。因此,该目录应包含所有依赖项,还应包含这些依赖项所依赖的所有包(例如sixpytz等)。

因此,您应该手动将它们包括在其中requirements.txt(以便第一步明确下载它们),或者应该使用PyPI安装所有软件包,然后pip freeze > requirements.txt存储所需的所有软件包的列表。

This approach (having all dependencies in a directory and not downloading from an index) only works when the directory contains all packages. The directory should therefore contain all dependencies but also all packages that those dependencies depend on (e.g., six, pytz etc).

You should therefore manually include these in requirements.txt (so that the first step downloads them explicitly) or you should install all packages using PyPI and then pip freeze > requirements.txt to store the list of all packages needed.


回答 1

我已经安装了python3,但是/ usr / bin / python中的python仍然是旧的2.7版本

这个工作(<pkg>pyserial在我的情况):

python3 -m pip install <pkg>

I had installed python3 but my python in /usr/bin/python was still the old 2.7 version

This worked (<pkg> was pyserial in my case):

python3 -m pip install <pkg>

回答 2

经过2个小时的搜索,我找到了一种只需一行命令即可修复它的方法。您需要知道软件包的版本(只需搜索PACKAGE版本)。

命令:

python3 -m pip install --pre --upgrade PACKAGE==VERSION.VERSION.VERSION

After 2 hours of searching, I found a way to fix it with just one line of command. You need to know the version of the package (Just search up PACKAGE version).

Command:

python3 -m pip install --pre --upgrade PACKAGE==VERSION.VERSION.VERSION

回答 3

下面的命令为我工作-

python -m pip install flask

Below command worked for me –

python -m pip install flask

回答 4

尝试使用以下命令通过Powershell安装flask。

pip install --isolated Flask

这将允许安装以避免环境变量和用户配置。

Try installing flask through the powershell using the following command.

pip install --isolated Flask

This will allow installation to avoide environment variables and user configuration.


回答 5

并非总是如此,但是在某些情况下,该软件包已经存在。例如-getpass。它未在“点列表”中列出,但可以导入和使用:

如果我尝试通过pip install getpass进行安装,则会出现以下错误:“找不到满足要求getpass的版本”

Not always, but in some cases the package already exists. For example – getpass. It is not listed by “pip list” but it can be imported and used:

If I try to pip install getpass I get the following error: “Could not find a version that satisfies the requirement getpass”


回答 6

awscli在Windows 10上的anaconda(python 3.7)中安装时出现此错误。在进行故障排除时,我转到了答案https://stackoverflow.com/a/49991357/6862405,然后转到https://stackoverflow.com/a/54582701/6862405。最后发现,我需要安装库PyOpenSSLcryptographyenum34idnaipaddress。安装完这些(使用简单pip install命令)之后,我就可以安装了awscli

I got this error while installing awscli on Windows 10 in anaconda (python 3.7). While troubleshooting, I went to the answer https://stackoverflow.com/a/49991357/6862405 and then to https://stackoverflow.com/a/54582701/6862405. Finally found that I need to install the libraries PyOpenSSL, cryptography, enum34, idna and ipaddress. After installing these (using simply pip install command), I was able to install awscli.


回答 7

如果您在工作场所遇到此问题。这可能是您的解决方案。

pip install -U <package_name> --user --proxy=<your proxy>

If you facing this issue at the workplace. This might be the solution for you.

pip install -U <package_name> --user --proxy=<your proxy>

回答 8

只需遵循项目页面上列出的要求即可:https : //pypi.org/project/pgmagick/

Just follow the requirements listed on the project’s page: https://pypi.org/project/pgmagick/


回答 9

使用命令提示符,然后选择以管理员身份运行。

升级点子版本

要升级PIP,请键入以下命令,然后按Enter:

python.exe -m pip安装–upgrade pip

返回python路径C:\ Users \ Jack \ AppData \ Local \ Programs \ Python \ Python37 \ Scripts

类型jupyter笔记本

您将被重定向到http:// localhost:8888 / undefined / tree -Jupyter主页

希望能帮助到你 !!!!!!!!!!!

Use Command Prompt, and then select Run as administrator.

Upgrade the pip version

To upgrade PIP, type this command, and then press Enter:-

python.exe -m pip install –upgrade pip

Go Back to python path C:\Users\Jack\AppData\Local\Programs\Python\Python37\Scripts

Type jupyter notebook

You will be redirected to http://localhost:8888/undefined/tree – Jupyter Home Page

Hope it helps !!!!!!!!!!!


回答 10

可能有帮助

sudo pip install wheel == 0.29.0

might help

sudo pip install wheel==0.29.0


setuptools setup.py文件中install_requires kwarg的参考requirements.txt

问题:setuptools setup.py文件中install_requires kwarg的参考requirements.txt

我有一个requirements.txt与Travis-CI一起使用的文件。在requirements.txt和中都重复要求似乎很愚蠢setup.py,所以我希望将文件句柄传递给install_requiresin setuptools.setup

这可能吗?如果是这样,我应该怎么做呢?

这是我的requirements.txt文件:

guessit>=0.5.2
tvdb_api>=1.8.2
hachoir-metadata>=1.3.3
hachoir-core>=1.3.3
hachoir-parser>=1.3.4

I have a requirements.txt file that I’m using with Travis-CI. It seems silly to duplicate the requirements in both requirements.txt and setup.py, so I was hoping to pass a file handle to the install_requires kwarg in setuptools.setup.

Is this possible? If so, how should I go about doing it?

Here is my requirements.txt file:

guessit>=0.5.2
tvdb_api>=1.8.2
hachoir-metadata>=1.3.3
hachoir-core>=1.3.3
hachoir-parser>=1.3.4

回答 0

你可以翻转它周围,列表中的依赖关系setup.py,并有单字符-点.-在requirements.txt代替。


另外,即使不建议使用,也可以requirements.txt通过以下技巧(通过进行测试pip 9.0.1)来分析文件(如果它没有通过URL引用任何外部要求):

install_reqs = parse_requirements('requirements.txt', session='hack')

但是,这不会过滤环境标记


在pip的旧版本中(更具体地讲,版本早于6.0),可以使用公共API来实现此目的。需求文件可以包含注释(#),也可以包含其他一些文件(--requirement-r)。因此,如果您确实要解析a requirements.txt,则可以使用pip解析器:

from pip.req import parse_requirements

# parse_requirements() returns generator of pip.req.InstallRequirement objects
install_reqs = parse_requirements(<requirements_path>)

# reqs is a list of requirement
# e.g. ['django==1.5.1', 'mezzanine==1.4.6']
reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
)

You can flip it around and list the dependencies in setup.py and have a single character — a dot . — in requirements.txt instead.


Alternatively, even if not advised, it is still possible to parse the requirements.txt file (if it doesn’t refer any external requirements by URL) with the following hack (tested with pip 9.0.1):

install_reqs = parse_requirements('requirements.txt', session='hack')

This doesn’t filter environment markers though.


In old versions of pip, more specifically older than 6.0, there is a public API that can be used to achieve this. A requirement file can contain comments (#) and can include some other files (--requirement or -r). Thus, if you really want to parse a requirements.txt you can use the pip parser:

from pip.req import parse_requirements

# parse_requirements() returns generator of pip.req.InstallRequirement objects
install_reqs = parse_requirements(<requirements_path>)

# reqs is a list of requirement
# e.g. ['django==1.5.1', 'mezzanine==1.4.6']
reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
)

回答 1

在它面前,它似乎是requirements.txtsetup.py是愚蠢的重复,而是要明白,虽然形式是相似的,预定的功能有很大的不同是很重要的。

程序包作者在指定依赖项时的目的是说:“无论您在何处安装此程序包,都需要其他程序包,此程序包才能工作。”

相反,部署作者(可能在不同时间是同一个人)的工作不同,他们说:“这是我们收集并测试过的软件包列表,现在我需要安装”。

软件包作者针对各种各样的场景进行了写作,因为他们将自己的工作放到那里以他们可能不了解的方式使用,并且无法知道将在软件包旁边安装哪些软件包。为了成为一个好邻居并避免依赖版本与其他软件包冲突,他们需要指定尽可能广泛的依赖版本。这就是install_requiressetup.py做。

部署作者写的是一个非常不同,非常特定的目标:在特定计算机上安装的已安装应用程序或服务的单个实例。为了精确控制部署,并确保测试和部署了正确的软件包,部署作者必须指定要安装的每个软件包的确切版本和源位置,包括依赖关系和依赖关系。使用此规范,可以将部署重复地应用于多台计算机,或在测试计算机上进行测试,并且部署作者可以确信每次都部署了相同的程序包。这就是一个requirements.txt

因此,您可以看到,尽管它们看起来都像是一个很大的软件包和版本列表,但是这两件事的工作却截然不同。而且混合起来并弄错它肯定很容易!但是考虑这一点的正确方法是,requirements.txt对所有各种setup.py软件包文件中的需求提出的“问题”进行“解答” 。而不是手工编写,它通常是通过告诉pip查看setup.py一组所需软件包中的所有文件,找到它认为符合所有要求的一组软件包,然后在安装后冻结来生成的。 ”将软件包列表转换为文本文件(这就是pip freeze名称的来源)。

因此,外卖:

  • setup.py应该声明仍然可用的最宽松的依赖版本。它的工作是说特定的软件包可以使用什么。
  • requirements.txt是一个定义整个安装工作​​的部署清单,不应将其视为与任何一个软件包捆绑在一起。它的工作是为完成部署工作而声明所有必要软件包的详尽清单。
  • 由于这两件事具有如此不同的内容和存在的原因,因此简单地将其中一项复制到另一项中是不可行的。

参考文献:

On the face of it, it does seem that requirements.txt and setup.py are silly duplicates, but it’s important to understand that while the form is similar, the intended function is very different.

The goal of a package author, when specifying dependencies, is to say “wherever you install this package, these are the other packages you need, in order for this package to work.”

In contrast, the deployment author (which may be the same person at a different time) has a different job, in that they say “here’s the list of packages that we’ve gathered together and tested and that I now need to install”.

The package author writes for a wide variety of scenarios, because they’re putting their work out there to be used in ways they may not know about, and have no way of knowing what packages will be installed alongside their package. In order to be a good neighbor and avoid dependency version conflicts with other packages, they need to specify as wide a range of dependency versions as can possibly work. This is what install_requires in setup.py does.

The deployment author writes for a very different, very specific goal: a single instance of an installed application or service, installed on a particular computer. In order to precisely control a deployment, and be sure that the right packages are tested and deployed, the deployment author must specify the exact version and source-location of every package to be installed, including dependencies and dependency’s dependencies. With this spec, a deployment can be repeatably applied to several machines, or tested on a test machine, and the deployment author can be confident that the same packages are deployed every time. This is what a requirements.txt does.

So you can see that, while they both look like a big list of packages and versions, these two things have very different jobs. And it’s definitely easy to mix this up and get it wrong! But the right way to think about this is that requirements.txt is an “answer” to the “question” posed by the requirements in all the various setup.py package files. Rather than write it by hand, it’s often generated by telling pip to look at all the setup.py files in a set of desired packages, find a set of packages that it thinks fits all the requirements, and then, after they’re installed, “freeze” that list of packages into a text file (this is where the pip freeze name comes from).

So the takeaway:

  • setup.py should declare the loosest possible dependency versions that are still workable. Its job is to say what a particular package can work with.
  • requirements.txt is a deployment manifest that defines an entire installation job, and shouldn’t be thought of as tied to any one package. Its job is to declare an exhaustive list of all the necessary packages to make a deployment work.
  • Because these two things have such different content and reasons for existing, it’s not feasible to simply copy one into the other.

References:


回答 2

它不能使用文件句柄。该install_requires参数可以仅仅是一个字符串或字符串列表

当然,您可以在设置脚本中读取文件,并将其作为字符串列表传递给install_requires

import os
from setuptools import setup

with open('requirements.txt') as f:
    required = f.read().splitlines()

setup(...
install_requires=required,
...)

It can’t take a file handle. The install_requires argument can only be a string or a list of strings.

You can, of course, read your file in the setup script and pass it as a list of strings to install_requires.

import os
from setuptools import setup

with open('requirements.txt') as f:
    required = f.read().splitlines()

setup(...
install_requires=required,
...)

回答 3

需求文件使用扩展的pip格式,仅当您需要setup.py用更严格的约束来补充时(例如,指定某些依赖项必须来自的确切网址,或pip freeze将整个包冻结为已知工作的输出),该文件才有用版本。如果您不需要额外的约束,请仅使用setup.py。如果您觉得确实需要运送requirements.txt,可以将其放在一行中:

.

这将是有效的,并且完全引用setup.py同一目录中的内容。

Requirements files use an expanded pip format, which is only useful if you need to complement your setup.py with stronger constraints, for example specifying the exact urls some of the dependencies must come from, or the output of pip freeze to freeze the entire package set to known-working versions. If you don’t need the extra constraints, use only a setup.py. If you feel like you really need to ship a requirements.txt anyway, you can make it a single line:

.

It will be valid and refer exactly to the contents of the setup.py that is in the same directory.


回答 4

虽然不是该问题的确切答案,但我还是推荐Donald Stufft的博客文章,网址https://caremad.io/2013/07/setup-vs-requirement/,以很好地解决这个问题。我一直在使用它取得巨大的成功。

简而言之, requirements.txt这不是setup.py替代方案,而是部署的补充。在中保持适当的软件包依赖关系抽象setup.py。设置一个requirements.txt或多个’em以获取特定版本的软件包依赖项以进行开发,测试或生产。

例如,包含在回购下的软件包中 deps/

# fetch specific dependencies
--no-index
--find-links deps/

# install package
# NOTE: -e . for editable mode
.

pip执行包的程序setup.py并安装在中声明的依赖项的特定版本install_requires。没有重复性,并且保留了两个工件的目的。

While not an exact answer to the question, I recommend Donald Stufft’s blog post at https://caremad.io/2013/07/setup-vs-requirement/ for a good take on this problem. I’ve been using it to great success.

In short, requirements.txt is not a setup.py alternative, but a deployment complement. Keep an appropriate abstraction of package dependencies in setup.py. Set requirements.txt or more of ’em to fetch specific versions of package dependencies for development, testing, or production.

E.g. with packages included in the repo under deps/:

# fetch specific dependencies
--no-index
--find-links deps/

# install package
# NOTE: -e . for editable mode
.

pip executes package’s setup.py and installs the specific versions of dependencies declared in install_requires. There’s no duplicity and the purpose of both artifacts is preserved.


回答 5

使用parse_requirements存在问题,因为未公开记录和支持pip API。在第1.6点中,该功能实际上正在移动,因此该功能的现有用途可能会中断。

消除setup.py和之间重复的一种更可靠的方法requirements.txt是特定于您的依赖项setup.py,然后将其-e .放入requirements.txt文件中。从一个有些信息pip为什么这是去一个更好的办法开发人员可以在这里找到:https://caremad.io/blog/setup-vs-requirement/

Using parse_requirements is problematic because the pip API isn’t publicly documented and supported. In pip 1.6, that function is actually moving, so existing uses of it are likely to break.

A more reliable way to eliminate duplication between setup.py and requirements.txt is to specific your dependencies in setup.py and then put -e . into your requirements.txt file. Some information from one of the pip developers about why that’s a better way to go is available here: https://caremad.io/blog/setup-vs-requirement/


回答 6

以上大多数其他答案不适用于当前版本的pip API。这是使用当前版本的pip(在撰写本文时为6.0.8,在7.1.2中也可以使用。)的正确方法。您可以使用pip -V检查版本。

from pip.req import parse_requirements
from pip.download import PipSession

install_reqs = parse_requirements(<requirements_path>, session=PipSession())

reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
    ....
)

*正确,因为这是对当前点使用parse_requirements的方式。仍然可能不是最好的方法,因为正如上面的海报所述,pip并没有真正维护API。

Most of the other answers above don’t work with the current version of pip’s API. Here is the correct* way to do it with the current version of pip (6.0.8 at the time of writing, also worked in 7.1.2. You can check your version with pip -V).

from pip.req import parse_requirements
from pip.download import PipSession

install_reqs = parse_requirements(<requirements_path>, session=PipSession())

reqs = [str(ir.req) for ir in install_reqs]

setup(
    ...
    install_requires=reqs
    ....
)

* Correct, in that it is the way to use parse_requirements with the current pip. It still probably isn’t the best way to do it, since, as posters above said, pip doesn’t really maintain an API.


回答 7

在Travis中安装当前软件包。这样可以避免使用requirements.txt文件。例如:

language: python
python:
  - "2.7"
  - "2.6"
install:
  - pip install -q -e .
script:
  - python runtests.py

Install the current package in Travis. This avoids the use of a requirements.txt file. For example:

language: python
python:
  - "2.7"
  - "2.6"
install:
  - pip install -q -e .
script:
  - python runtests.py

回答 8

from pip.req import parse_requirements 不适用于我,我认为它适用于我的requirements.txt中的空白行,但是此功能确实有效

def parse_requirements(requirements):
    with open(requirements) as f:
        return [l.strip('\n') for l in f if l.strip('\n') and not l.startswith('#')]

reqs = parse_requirements(<requirements_path>)

setup(
    ...
    install_requires=reqs,
    ...
)

from pip.req import parse_requirements did not work for me and I think it’s for the blank lines in my requirements.txt, but this function does work

def parse_requirements(requirements):
    with open(requirements) as f:
        return [l.strip('\n') for l in f if l.strip('\n') and not l.startswith('#')]

reqs = parse_requirements(<requirements_path>)

setup(
    ...
    install_requires=reqs,
    ...
)

回答 9

如果您不想强迫用户安装pip,可以使用以下方法模拟其行为:

import sys

from os import path as p

try:
    from setuptools import setup, find_packages
except ImportError:
    from distutils.core import setup, find_packages


def read(filename, parent=None):
    parent = (parent or __file__)

    try:
        with open(p.join(p.dirname(parent), filename)) as f:
            return f.read()
    except IOError:
        return ''


def parse_requirements(filename, parent=None):
    parent = (parent or __file__)
    filepath = p.join(p.dirname(parent), filename)
    content = read(filename, parent)

    for line_number, line in enumerate(content.splitlines(), 1):
        candidate = line.strip()

        if candidate.startswith('-r'):
            for item in parse_requirements(candidate[2:].strip(), filepath):
                yield item
        else:
            yield candidate

setup(
...
    install_requires=list(parse_requirements('requirements.txt'))
)

If you don’t want to force your users to install pip, you can emulate its behavior with this:

import sys

from os import path as p

try:
    from setuptools import setup, find_packages
except ImportError:
    from distutils.core import setup, find_packages


def read(filename, parent=None):
    parent = (parent or __file__)

    try:
        with open(p.join(p.dirname(parent), filename)) as f:
            return f.read()
    except IOError:
        return ''


def parse_requirements(filename, parent=None):
    parent = (parent or __file__)
    filepath = p.join(p.dirname(parent), filename)
    content = read(filename, parent)

    for line_number, line in enumerate(content.splitlines(), 1):
        candidate = line.strip()

        if candidate.startswith('-r'):
            for item in parse_requirements(candidate[2:].strip(), filepath):
                yield item
        else:
            yield candidate

setup(
...
    install_requires=list(parse_requirements('requirements.txt'))
)

回答 10

以下界面在点10中已弃用:

from pip.req import parse_requirements
from pip.download import PipSession

所以我将其切换为简单的文本解析:

with open('requirements.txt', 'r') as f:
    install_reqs = [
        s for s in [
            line.split('#', 1)[0].strip(' \t\n') for line in f
        ] if s != ''
    ]

The following interface became deprecated in pip 10:

from pip.req import parse_requirements
from pip.download import PipSession

So I switched it just to simple text parsing:

with open('requirements.txt', 'r') as f:
    install_reqs = [
        s for s in [
            line.split('#', 1)[0].strip(' \t\n') for line in f
        ] if s != ''
    ]

回答 11

这种简单的方法从中读取需求文件setup.py。这是Dmitiry S.答案的变形。此答案仅与Python 3.6+兼容。

DSrequirements.txt可以记录与特定的版本号具体要求,而setup.py可以记录与宽松版范围抽象的要求。

以下是我的摘录setup.py

import distutils.text_file
from pathlib import Path
from typing import List

def _parse_requirements(filename: str) -> List[str]:
    """Return requirements from requirements file."""
    # Ref: https://stackoverflow.com/a/42033122/
    return distutils.text_file.TextFile(filename=str(Path(__file__).with_name(filename))).readlines()

setup(...
      install_requires=_parse_requirements('requirements.txt'),
   ...)

请注意,这distutils.text_file.TextFile将删除注释。而且,根据我的经验,您显然不需要采取任何特殊步骤将需求文件捆绑在一起。

This simple approach reads the requirements file from setup.py. It is a variation of the answer by Dmitiry S.. This answer is compatible only with Python 3.6+.

Per D.S., requirements.txt can document concrete requirements with specific version numbers, whereas setup.py can document abstract requirements with loose version ranges.

Below is an excerpt of my setup.py.

import distutils.text_file
from pathlib import Path
from typing import List

def _parse_requirements(filename: str) -> List[str]:
    """Return requirements from requirements file."""
    # Ref: https://stackoverflow.com/a/42033122/
    return distutils.text_file.TextFile(filename=str(Path(__file__).with_name(filename))).readlines()

setup(...
      install_requires=_parse_requirements('requirements.txt'),
   ...)

Note that distutils.text_file.TextFile will strip comments. Also, per my experience, you apparently do not need to take any special step to bundle in the requirements file.


回答 12

小心parse_requirements行为!

请注意,pip.req.parse_requirements下划线将变为短划线。在发现它之前,这让我很生气。示例说明:

from pip.req import parse_requirements  # tested with v.1.4.1

reqs = '''
example_with_underscores
example-with-dashes
'''

with open('requirements.txt', 'w') as f:
    f.write(reqs)

req_deps = parse_requirements('requirements.txt')
result = [str(ir.req) for ir in req_deps if ir.req is not None]
print result

产生

['example-with-underscores', 'example-with-dashes']

BEWARE OF parse_requirements BEHAVIOUR!

Please note that pip.req.parse_requirements will change underscores to dashes. This was enraging me for a few days before I discovered it. Example demonstrating:

from pip.req import parse_requirements  # tested with v.1.4.1

reqs = '''
example_with_underscores
example-with-dashes
'''

with open('requirements.txt', 'w') as f:
    f.write(reqs)

req_deps = parse_requirements('requirements.txt')
result = [str(ir.req) for ir in req_deps if ir.req is not None]
print result

produces

['example-with-underscores', 'example-with-dashes']

回答 13

我为此创建了一个可重用的函数。它实际上解析需求文件的整个目录,并将它们设置为extras_require。

最新的始终可用在这里:https : //gist.github.com/akatrevorjay/293c26fefa24a7b812f5

import glob
import itertools
import os

# This is getting ridiculous
try:
    from pip._internal.req import parse_requirements
    from pip._internal.network.session import PipSession
except ImportError:
    try:
        from pip._internal.req import parse_requirements
        from pip._internal.download import PipSession
    except ImportError:
        from pip.req import parse_requirements
        from pip.download import PipSession


def setup_requirements(
        patterns=[
            'requirements.txt', 'requirements/*.txt', 'requirements/*.pip'
        ],
        combine=True):
    """
    Parse a glob of requirements and return a dictionary of setup() options.
    Create a dictionary that holds your options to setup() and update it using this.
    Pass that as kwargs into setup(), viola

    Any files that are not a standard option name (ie install, tests, setup) are added to extras_require with their
    basename minus ext. An extra key is added to extras_require: 'all', that contains all distinct reqs combined.

    Keep in mind all literally contains `all` packages in your extras.
    This means if you have conflicting packages across your extras, then you're going to have a bad time.
    (don't use all in these cases.)

    If you're running this for a Docker build, set `combine=True`.
    This will set `install_requires` to all distinct reqs combined.

    Example:

    >>> import setuptools
    >>> _conf = dict(
    ...     name='mainline',
    ...     version='0.0.1',
    ...     description='Mainline',
    ...     author='Trevor Joynson <github@trevor.joynson,io>',
    ...     url='https://trevor.joynson.io',
    ...     namespace_packages=['mainline'],
    ...     packages=setuptools.find_packages(),
    ...     zip_safe=False,
    ...     include_package_data=True,
    ... )
    >>> _conf.update(setup_requirements())
    >>> # setuptools.setup(**_conf)

    :param str pattern: Glob pattern to find requirements files
    :param bool combine: Set True to set install_requires to extras_require['all']
    :return dict: Dictionary of parsed setup() options
    """
    session = PipSession()

    # Handle setuptools insanity
    key_map = {
        'requirements': 'install_requires',
        'install': 'install_requires',
        'tests': 'tests_require',
        'setup': 'setup_requires',
    }
    ret = {v: set() for v in key_map.values()}
    extras = ret['extras_require'] = {}
    all_reqs = set()

    files = [glob.glob(pat) for pat in patterns]
    files = itertools.chain(*files)

    for full_fn in files:
        # Parse
        reqs = {
            str(r.req)
            for r in parse_requirements(full_fn, session=session)
            # Must match env marker, eg:
            #   yarl ; python_version >= '3.0'
            if r.match_markers()
        }
        all_reqs.update(reqs)

        # Add in the right section
        fn = os.path.basename(full_fn)
        barefn, _ = os.path.splitext(fn)
        key = key_map.get(barefn)

        if key:
            ret[key].update(reqs)
            extras[key] = reqs

        extras[barefn] = reqs

    if 'all' not in extras:
        extras['all'] = list(all_reqs)

    if combine:
        extras['install'] = ret['install_requires']
        ret['install_requires'] = list(all_reqs)

    def _listify(dikt):
        ret = {}

        for k, v in dikt.items():
            if isinstance(v, set):
                v = list(v)
            elif isinstance(v, dict):
                v = _listify(v)
            ret[k] = v

        return ret

    ret = _listify(ret)

    return ret


__all__ = ['setup_requirements']

if __name__ == '__main__':
    reqs = setup_requirements()
    print(reqs)

I created a reusable function for this. It actually parses an entire directory of requirements files and sets them to extras_require.

Latest always available here: https://gist.github.com/akatrevorjay/293c26fefa24a7b812f5

import glob
import itertools
import os

# This is getting ridiculous
try:
    from pip._internal.req import parse_requirements
    from pip._internal.network.session import PipSession
except ImportError:
    try:
        from pip._internal.req import parse_requirements
        from pip._internal.download import PipSession
    except ImportError:
        from pip.req import parse_requirements
        from pip.download import PipSession


def setup_requirements(
        patterns=[
            'requirements.txt', 'requirements/*.txt', 'requirements/*.pip'
        ],
        combine=True):
    """
    Parse a glob of requirements and return a dictionary of setup() options.
    Create a dictionary that holds your options to setup() and update it using this.
    Pass that as kwargs into setup(), viola

    Any files that are not a standard option name (ie install, tests, setup) are added to extras_require with their
    basename minus ext. An extra key is added to extras_require: 'all', that contains all distinct reqs combined.

    Keep in mind all literally contains `all` packages in your extras.
    This means if you have conflicting packages across your extras, then you're going to have a bad time.
    (don't use all in these cases.)

    If you're running this for a Docker build, set `combine=True`.
    This will set `install_requires` to all distinct reqs combined.

    Example:

    >>> import setuptools
    >>> _conf = dict(
    ...     name='mainline',
    ...     version='0.0.1',
    ...     description='Mainline',
    ...     author='Trevor Joynson <github@trevor.joynson,io>',
    ...     url='https://trevor.joynson.io',
    ...     namespace_packages=['mainline'],
    ...     packages=setuptools.find_packages(),
    ...     zip_safe=False,
    ...     include_package_data=True,
    ... )
    >>> _conf.update(setup_requirements())
    >>> # setuptools.setup(**_conf)

    :param str pattern: Glob pattern to find requirements files
    :param bool combine: Set True to set install_requires to extras_require['all']
    :return dict: Dictionary of parsed setup() options
    """
    session = PipSession()

    # Handle setuptools insanity
    key_map = {
        'requirements': 'install_requires',
        'install': 'install_requires',
        'tests': 'tests_require',
        'setup': 'setup_requires',
    }
    ret = {v: set() for v in key_map.values()}
    extras = ret['extras_require'] = {}
    all_reqs = set()

    files = [glob.glob(pat) for pat in patterns]
    files = itertools.chain(*files)

    for full_fn in files:
        # Parse
        reqs = {
            str(r.req)
            for r in parse_requirements(full_fn, session=session)
            # Must match env marker, eg:
            #   yarl ; python_version >= '3.0'
            if r.match_markers()
        }
        all_reqs.update(reqs)

        # Add in the right section
        fn = os.path.basename(full_fn)
        barefn, _ = os.path.splitext(fn)
        key = key_map.get(barefn)

        if key:
            ret[key].update(reqs)
            extras[key] = reqs

        extras[barefn] = reqs

    if 'all' not in extras:
        extras['all'] = list(all_reqs)

    if combine:
        extras['install'] = ret['install_requires']
        ret['install_requires'] = list(all_reqs)

    def _listify(dikt):
        ret = {}

        for k, v in dikt.items():
            if isinstance(v, set):
                v = list(v)
            elif isinstance(v, dict):
                v = _listify(v)
            ret[k] = v

        return ret

    ret = _listify(ret)

    return ret


__all__ = ['setup_requirements']

if __name__ == '__main__':
    reqs = setup_requirements()
    print(reqs)

回答 14

另一种可能的解决方案…

def gather_requirements(top_path=None):
    """Captures requirements from repo.

    Expected file format is: requirements[-_]<optional-extras>.txt

    For example:

        pip install -e .[foo]

    Would require:

        requirements-foo.txt

        or

        requirements_foo.txt

    """
    from pip.download import PipSession
    from pip.req import parse_requirements
    import re

    session = PipSession()
    top_path = top_path or os.path.realpath(os.getcwd())
    extras = {}
    for filepath in tree(top_path):
        filename = os.path.basename(filepath)
        basename, ext = os.path.splitext(filename)
        if ext == '.txt' and basename.startswith('requirements'):
            if filename == 'requirements.txt':
                extra_name = 'requirements'
            else:
                _, extra_name = re.split(r'[-_]', basename, 1)
            if extra_name:
                reqs = [str(ir.req) for ir in parse_requirements(filepath, session=session)]
                extras.setdefault(extra_name, []).extend(reqs)
    all_reqs = set()
    for key, values in extras.items():
        all_reqs.update(values)
    extras['all'] = list(all_reqs)
    return extras

然后使用…

reqs = gather_requirements()
install_reqs = reqs.pop('requirements', [])
test_reqs = reqs.pop('test', [])
...
setup(
    ...
    'install_requires': install_reqs,
    'test_requires': test_reqs,
    'extras_require': reqs,
    ...
)

Another possible solution…

def gather_requirements(top_path=None):
    """Captures requirements from repo.

    Expected file format is: requirements[-_]<optional-extras>.txt

    For example:

        pip install -e .[foo]

    Would require:

        requirements-foo.txt

        or

        requirements_foo.txt

    """
    from pip.download import PipSession
    from pip.req import parse_requirements
    import re

    session = PipSession()
    top_path = top_path or os.path.realpath(os.getcwd())
    extras = {}
    for filepath in tree(top_path):
        filename = os.path.basename(filepath)
        basename, ext = os.path.splitext(filename)
        if ext == '.txt' and basename.startswith('requirements'):
            if filename == 'requirements.txt':
                extra_name = 'requirements'
            else:
                _, extra_name = re.split(r'[-_]', basename, 1)
            if extra_name:
                reqs = [str(ir.req) for ir in parse_requirements(filepath, session=session)]
                extras.setdefault(extra_name, []).extend(reqs)
    all_reqs = set()
    for key, values in extras.items():
        all_reqs.update(values)
    extras['all'] = list(all_reqs)
    return extras

and then to use…

reqs = gather_requirements()
install_reqs = reqs.pop('requirements', [])
test_reqs = reqs.pop('test', [])
...
setup(
    ...
    'install_requires': install_reqs,
    'test_requires': test_reqs,
    'extras_require': reqs,
    ...
)

回答 15

我不建议这样做。正如多次提到的install_requiresrequirements.txt绝对不应该是同一列表。但是,由于涉及pip的专用内部API的周围存在许多误导性答案,因此可能值得寻找更明智的选择…

不需要piprequirements.txtsetuptools setup.py脚本中解析文件。该setuptools的项目已经包含在了所有必要的工具顶层pkg_resources

它或多或少看起来像这样:

#!/usr/bin/env python3

import pathlib

import pkg_resources
import setuptools

with pathlib.Path('requirements.txt').open() as requirements_txt:
    install_requires = [
        str(requirement)
        for requirement
        in pkg_resources.parse_requirements(requirements_txt)
    ]

setuptools.setup(
    install_requires=install_requires,
)

I would not recommend doing such a thing. As mentioned multiple times install_requires and requirements.txt are definitely not supposed to be the same list. But since there are a lot of misleading answers all around involving private internal APIs of pip, it might be worth looking at saner alternatives…

There is no need for pip to parse a requirements.txt file from a setuptools setup.py script. The setuptools project already contains all the necessary tools in its top level package pkg_resources.

It could more or less look like this:

#!/usr/bin/env python3

import pathlib

import pkg_resources
import setuptools

with pathlib.Path('requirements.txt').open() as requirements_txt:
    install_requires = [
        str(requirement)
        for requirement
        in pkg_resources.parse_requirements(requirements_txt)
    ]

setuptools.setup(
    install_requires=install_requires,
)

Notes:


回答 16

这个SO问题交叉发布我的答案,以获得另一个简单的pip版本证明解决方案。

try:  # for pip >= 10
    from pip._internal.req import parse_requirements
    from pip._internal.download import PipSession
except ImportError:  # for pip <= 9.0.3
    from pip.req import parse_requirements
    from pip.download import PipSession

requirements = parse_requirements(os.path.join(os.path.dirname(__file__), 'requirements.txt'), session=PipSession())

if __name__ == '__main__':
    setup(
        ...
        install_requires=[str(requirement.req) for requirement in requirements],
        ...
    )

然后,将所有需求requirements.txt放在项目根目录下即可。

Cross posting my answer from this SO question for another simple, pip version proof solution.

try:  # for pip >= 10
    from pip._internal.req import parse_requirements
    from pip._internal.download import PipSession
except ImportError:  # for pip <= 9.0.3
    from pip.req import parse_requirements
    from pip.download import PipSession

requirements = parse_requirements(os.path.join(os.path.dirname(__file__), 'requirements.txt'), session=PipSession())

if __name__ == '__main__':
    setup(
        ...
        install_requires=[str(requirement.req) for requirement in requirements],
        ...
    )

Then just throw in all your requirements under requirements.txt under project root directory.


回答 17

我这样做:

import re

def requirements(filename):
    with open(filename) as f:
        ll = f.read().splitlines()
    d = {}
    for l in ll:
        k, v = re.split(r'==|>=', l)
        d[k] = v
    return d

def packageInfo():
    try:
        from pip._internal.operations import freeze
    except ImportError:
        from pip.operations import freeze

    d = {}
    for kv in freeze.freeze():
        k, v = re.split(r'==|>=', kv)
        d[k] = v
    return d

req = getpackver('requirements.txt')
pkginfo = packageInfo()

for k, v in req.items():
    print(f'{k:<16}: {v:<6} -> {pkginfo[k]}')

I did this:

import re

def requirements(filename):
    with open(filename) as f:
        ll = f.read().splitlines()
    d = {}
    for l in ll:
        k, v = re.split(r'==|>=', l)
        d[k] = v
    return d

def packageInfo():
    try:
        from pip._internal.operations import freeze
    except ImportError:
        from pip.operations import freeze

    d = {}
    for kv in freeze.freeze():
        k, v = re.split(r'==|>=', kv)
        d[k] = v
    return d

req = getpackver('requirements.txt')
pkginfo = packageInfo()

for k, v in req.items():
    print(f'{k:<16}: {v:<6} -> {pkginfo[k]}')

回答 18

另一个parse_requirements将环境标记解析为extras_require以下内容的黑客:

from collections import defaultdict
from pip.req import parse_requirements

requirements = []
extras = defaultdict(list)
for r in parse_requirements('requirements.txt', session='hack'):
    if r.markers:
        extras[':' + str(r.markers)].append(str(r.req))
    else:
        requirements.append(str(r.req))

setup(
    ...,
    install_requires=requirements,
    extras_require=extras
)

它应该同时支持sdist和二进制dists。

正如其他人所述,它parse_requirements有几个缺点,因此这不是您应该在公共项目上执行的操作,但对于内部/个人项目来说就足够了。

Yet another parse_requirements hack that also parses environment markers into extras_require:

from collections import defaultdict
from pip.req import parse_requirements

requirements = []
extras = defaultdict(list)
for r in parse_requirements('requirements.txt', session='hack'):
    if r.markers:
        extras[':' + str(r.markers)].append(str(r.req))
    else:
        requirements.append(str(r.req))

setup(
    ...,
    install_requires=requirements,
    extras_require=extras
)

It should support both sdist and binary dists.

As stated by others, parse_requirements has several shortcomings, so this is not what you should do on public projects, but it may suffice for internal/personal projects.


回答 19

这是pip 9.0.1根据Romain的答案(requirements.txt根据当前环境标记进行解析和过滤)的完整技巧(已通过测试):

from pip.req import parse_requirements

requirements = []
for r in parse_requirements('requirements.txt', session='hack'):
    # check markers, such as
    #
    #     rope_py3k    ; python_version >= '3.0'
    #
    if r.match_markers():
        requirements.append(str(r.req))

print(requirements)

Here is a complete hack (tested with pip 9.0.1) based on Romain’s answer that parses requirements.txt and filters it according to current environment markers:

from pip.req import parse_requirements

requirements = []
for r in parse_requirements('requirements.txt', session='hack'):
    # check markers, such as
    #
    #     rope_py3k    ; python_version >= '3.0'
    #
    if r.match_markers():
        requirements.append(str(r.req))

print(requirements)

如何在Requirements.txt中声明直接的github源

问题:如何在Requirements.txt中声明直接的github源

我已经使用以下命令安装了一个库

pip install git+git://github.com/mozilla/elasticutils.git

直接从Github存储库安装它。这工作正常,我想在我的requirements.txt。我看其他的票像这样但这并没有解决我的问题。如果我把像

-f git+git://github.com/mozilla/elasticutils.git
elasticutils==0.7.dev

requirements.txt文件中,pip install -r requirements.txt结果为以下输出:

Downloading/unpacking elasticutils==0.7.dev (from -r requirements.txt (line 20))
  Could not find a version that satisfies the requirement elasticutils==0.7.dev (from -r requirements.txt (line 20)) (from versions: )
No distributions matching the version for elasticutils==0.7.dev (from -r requirements.txt (line 20))

需求文件文档中没有提及使用git+git协议说明符的链接,因此也许只是不被支持。

有人能解决我的问题吗?

I’ve installed a library using the command

pip install git+git://github.com/mozilla/elasticutils.git

which installs it directly from a Github repository. This works fine and I want to have that dependency in my requirements.txt. I’ve looked at other tickets like this but that didn’t solve my problem. If I put something like

-f git+git://github.com/mozilla/elasticutils.git
elasticutils==0.7.dev

in the requirements.txt file, a pip install -r requirements.txt results in the following output:

Downloading/unpacking elasticutils==0.7.dev (from -r requirements.txt (line 20))
  Could not find a version that satisfies the requirement elasticutils==0.7.dev (from -r requirements.txt (line 20)) (from versions: )
No distributions matching the version for elasticutils==0.7.dev (from -r requirements.txt (line 20))

The documentation of the requirements file does not mention links using the git+git protocol specifier, so maybe this is just not supported.

Does anybody have a solution for my problem?


回答 0

“ Editable”包语法可用于requirements.txt从各种VCS(git,hg,bzr,svn)导入包:

-e git://github.com/mozilla/elasticutils.git#egg=elasticutils

另外,可以指向特定的提交:

-e git://github.com/mozilla/elasticutils.git@000b14389171a9f0d7d713466b32bc649b0bed8e#egg=elasticutils

“Editable” packages syntax can be used in requirements.txt to import packages from a variety of VCS (git, hg, bzr, svn):

-e git://github.com/mozilla/elasticutils.git#egg=elasticutils

Also, it is possible to point to particular commit:

-e git://github.com/mozilla/elasticutils.git@000b14389171a9f0d7d713466b32bc649b0bed8e#egg=elasticutils

回答 1

通常,您的requirements.txt文件如下所示:

package-one==1.9.4
package-two==3.7.1
package-three==1.0.1
...

要指定Github存储库,您不需要package-name==约定。

下面的示例更新 package-two使用GitHub存储库进行。@和之间的文字#表示包装的详细信息。

指定提交哈希(41b95ec在updated的上下文中requirements.txt):

package-one==1.9.4
git+git://github.com/path/to/package-two@41b95ec#egg=package-two
package-three==1.0.1

指定分支名称(master):

git+git://github.com/path/to/package-two@master#egg=package-two

指定标签(0.1):

git+git://github.com/path/to/package-two@0.1#egg=package-two

指定发布(3.7.1):

git+git://github.com/path/to/package-two@releases/tag/v3.7.1#egg=package-two

请注意,#egg=package-two此处不是注释,而是要明确说明软件包名称

这篇博客文章对此主题进行了更多讨论。

Normally your requirements.txt file would look something like this:

package-one==1.9.4
package-two==3.7.1
package-three==1.0.1
...

To specify a Github repo, you do not need the package-name== convention.

The examples below update package-two using a GitHub repo. The text between @ and # denotes the specifics of the package.

Specify commit hash (41b95ec in the context of updated requirements.txt):

package-one==1.9.4
git+git://github.com/path/to/package-two@41b95ec#egg=package-two
package-three==1.0.1

Specify branch name (master):

git+git://github.com/path/to/package-two@master#egg=package-two

Specify tag (0.1):

git+git://github.com/path/to/package-two@0.1#egg=package-two

Specify release (3.7.1):

git+git://github.com/path/to/package-two@releases/tag/v3.7.1#egg=package-two

Note that #egg=package-two is not a comment here, it is to explicitly state the package name

This blog post has some more discussion on the topic.


回答 2

requirements.txt从pip 7.0开始,可以通过以下方式指定对git存储库中软件包的依赖关系:1

[-e] git+git://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+https://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+ssh://git.myproject.org/SomeProject#egg=SomeProject
-e git+git@git.myproject.org:SomeProject#egg=SomeProject

对于Github,这意味着您可以做到(请注意,省略了-e):

git+git://github.com/mozilla/elasticutils.git#egg=elasticutils

为什么要额外回答?
-e在其他答案中对标志有些困惑,所以这是我的澄清:

-e或” --editable标志表示包装已安装在<venv path>/src/SomeProject深处,因此不会放入深处<venv path>/lib/pythonX.X/site-packages/SomeProject。否则,它将被放置在其中。2

文献资料

requirements.txt allows the following ways of specifying a dependency on a package in a git repository as of pip 7.0:1

[-e] git+git://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+https://git.myproject.org/SomeProject#egg=SomeProject
[-e] git+ssh://git.myproject.org/SomeProject#egg=SomeProject
-e git+git@git.myproject.org:SomeProject#egg=SomeProject

For Github that means you can do (notice the omitted -e):

git+git://github.com/mozilla/elasticutils.git#egg=elasticutils

Why the extra answer?
I got somewhat confused by the -e flag in the other answers so here’s my clarification:

The -e or --editable flag means that the package is installed in <venv path>/src/SomeProject and thus not in the deeply buried <venv path>/lib/pythonX.X/site-packages/SomeProject it would otherwise be placed in.2

Documentation


回答 3

首先,以任何已知的方式使用git+git或安装git+https。安装项目kronok的分支的示例brabeion

pip install -e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion

其次,使用pip freeze > requirements.txt来获取正确的东西requirements.txt。在这种情况下,您将获得

-e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion-master

三,测试结果:

pip uninstall brabeion
pip install -r requirements.txt

First, install with git+git or git+https, in any way you know. Example of installing kronok‘s branch of the brabeion project:

pip install -e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion

Second, use pip freeze > requirements.txt to get the right thing in your requirements.txt. In this case, you will get

-e git+https://github.com/kronok/brabeion.git@12efe6aa06b85ae5ff725d3033e38f624e0a616f#egg=brabeion-master

Third, test the result:

pip uninstall brabeion
pip install -r requirements.txt

回答 4

由于pip v1.5(发布于2014年1月1日:CHANGELOGPR),您还可以指定git repo的子目录来包含您的模块。语法如下所示:

pip install -e git+https://git.repo/some_repo.git#egg=my_subdir_pkg&subdirectory=my_subdir_pkg # install a python package from a repo subdirectory

注意:作为pip模块的作者,如果可能的话,理想情况下,您可能希望将模块发布到它自己的顶级仓库中。但是,此功能对于某些子目录中包含python模块的现有存储库很有帮助。如果它们也没有发布到pypi,则可能会被迫以这种方式安装它们。

Since pip v1.5, (released Jan 1 2014: CHANGELOG, PR) you may also specify a subdirectory of a git repo to contain your module. The syntax looks like this:

pip install -e git+https://git.repo/some_repo.git#egg=my_subdir_pkg&subdirectory=my_subdir_pkg # install a python package from a repo subdirectory

Note: As a pip module author, ideally you’d probably want to publish your module in it’s own top-level repo if you can. Yet this feature is helpful for some pre-existing repos that contain python modules in subdirectories. You might be forced to install them this way if they are not published to pypi too.


回答 5

我发现要获取pip3(v9.0.1,由Ubuntu 18.04的软件包管理器安装)来实际安装我告诉它要安装的东西有点棘手。我发布此答案是为了节省遇到此问题的任何人的时间。

将其放入Requirements.txt文件失败:

git+git://github.com/myname/myrepo.git@my-branch#egg=eggname

“失败”是指当它从Git下载代码时,它最终安装了PyPi上找到的代码的原始版本,而不是该分支上存储库中的代码。

但是,安装commmit而不是分支名称是可行的:

git+git://github.com/myname/myrepo.git@d27d07c9e862feb939e56d0df19d5733ea7b4f4d#egg=eggname

I’m finding that it’s kind of tricky to get pip3 (v9.0.1, as installed by Ubuntu 18.04’s package manager) to actually install the thing I tell it to install. I’m posting this answer to save anyone’s time who runs into this problem.

Putting this into a requirements.txt file failed:

git+git://github.com/myname/myrepo.git@my-branch#egg=eggname

By “failed” I mean that while it downloaded the code from Git, it ended up installing the original version of the code, as found on PyPi, instead of the code in the repo on that branch.

However, installing the commmit instead of the branch name works:

git+git://github.com/myname/myrepo.git@d27d07c9e862feb939e56d0df19d5733ea7b4f4d#egg=eggname