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.