我开始使用Python。我已经添加了requirements.txt和setup.py到我的项目中。但是,我仍然对这两个文件的目的感到困惑。我读过setup.py是为可重分发的东西而设计的,requirements.txt是为不可重分发的东西而设计的。但我不确定这是准确的。

这两个文件究竟应该如何使用?


让:

这将帮助您设置开发环境。

像pip这样的程序可以用来一下子安装文件中列出的所有包。在那之后,你可以开始开发你的python脚本。如果您计划让其他人参与开发或使用虚拟环境,这尤其有用。 下面是它的用法:

pip install -r requirements.txt

它可以很容易地由pip本身产生:

pip freeze > requirements.txt

PIP自动尝试只添加默认情况下没有安装的包,因此生成的文件非常小。


setup . py:

这可以帮助您创建可以重新分发的包。

setup.py脚本的目的是在最终用户的系统上安装软件包,而不是像pip install -r requirements.txt那样准备开发环境。有关setup.py的更多细节,请参阅这个答案。


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


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

除了包依赖关系之外,setup.py文件还描述了应该打包的文件和模块集(或者在本机模块的情况下编译(即用C编写)),以及要添加到python包列表中的元数据(例如包名、包版本、包描述、作者等等)。

因为两个文件都列出了依赖项,这可能会导致一些重复。阅读下面的细节。


该文件列出了python包的要求。它是一个纯文本文件(可选带有注释),列出了python项目的包依赖项(每行一个)。它没有描述python包的安装方式。您通常会使用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.

如果存在多路需求x .txt变体,那么通常一个将列出运行时依赖项,而另一个将列出构建时依赖项,或测试依赖项。有些项目还会级联它们的需求文件,例如,当一个需求文件包含另一个文件时(例如)。这样做可以减少重复。

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.

当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额外功能”。你可以在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,比如那些用virtualenv程序创建的沙箱。这将避免在项目开发环境的上下文之外安装python包。


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

它们的设计目的不同

这是从官方文件中引用的精确描述(强调我):

install_requires(在setup.py中)定义了单个项目的依赖关系,而Requirements Files通常用于定义完整Python环境的需求。

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

但它可能仍然不容易理解,所以在下一节中,有两个实际的例子来说明这两种方法应该如何使用,不同的。

因此,它们的实际用法是不同的

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

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 . . The latter is essentially using the conventional requirements.txt habit to document your installation step is pip install ., which means 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, but it is nonetheless a convenient way to explicitly opt out for dependency pinning when running in a CI environment. The trick was derived from an approach mentioned by Python packaging maintainer Donald in his blog post. Different lower bounds. Assuming there is an existing engine library with this history: engine 1.1.0 Use steam ... engine 1.2.0 Internal combustion is invented engine 1.2.1 Fix engine leaking oil engine 1.2.2 Fix engine overheat engine 1.2.3 Fix occasional engine stalling engine 2.0.0 Introducing nuclear reactor You follow the above 3 criteria and correctly decided that your new library hybrid-engine would use a setup.py to declare its dependency engine>=1.2.0,<2, and then your separated application reliable-car would use requirements.txt to declare its dependency engine>=1.2.3,<2 (or you may want to just pin engine==1.2.3). As you see, your choice for their lower bound number are still subtly different, and neither of them uses the latest engine==2.0.0. And here is why. hybrid-engine depends on engine>=1.2.0 because, the needed add_fuel() API 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, i.e. "nuclear reactor" introduced in engine 2.0.0, but they are not necessarily desirable for project reliable-car. (Your yet another new project time-machine would likely use engine>=2.0.0, but that is a different topic, though.)


博士TL;

txt列出了具体的依赖关系 py列出抽象依赖项


关于Python中的依赖关系管理,一个常见的误解是你是否需要使用requirements.txt或setup.py文件来处理依赖关系。

你可能不得不同时使用这两种方法,以确保在你的Python项目中恰当地处理依赖关系。

txt文件应该列出具体的依赖关系。换句话说,它应该列出固定依赖项(使用==说明符)。然后将使用该文件创建一个工作的虚拟环境,其中将安装所有依赖项,并使用指定的版本。

另一方面,setup.py文件应该列出抽象依赖项。这意味着它应该列出运行项目的最小依赖项。除了依赖项管理,这个文件还用于包分发(比如在PyPI上)。

要更全面地阅读,您可以在TDS上阅读文章requirements.txt vs setup.py。


现在,从PEP-517和PEP-518开始,你可能不得不使用pyproject。为了指定您想要使用setuptools作为构建工具,并使用额外的setup.cfg文件指定详细信息。 有关更多细节,您可以阅读文章setup.py vs setup.cfg in Python。