236

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?

init_js
  • 4,143
  • 2
  • 23
  • 53
lucy
  • 4,136
  • 5
  • 30
  • 47
  • 1
    Have you searched the web using your exact title? [This article](https://caremad.io/posts/2013/07/setup-vs-requirement/) (the first hit when I searched) is the best I've read on the subject. – ChrisGPT was on strike Apr 27 '17 at 13:25
  • 3
    This article could be useful: https://caremad.io/posts/2013/07/setup-vs-requirement/ (sorry, too lazy to extract essentials into a proper answer). Another thing is, some tools (e.g. testing) may have their biases towards one or another - but don't let it bother you if you've just started working on Python. – drdaeman Apr 27 '17 at 13:25
  • What is the advantage of that (either `setup.py` or `requirements.txt`) vs just having a `.sh` script were I conda/pip install each package? – Charlie Parker Apr 23 '21 at 17:52
  • Also see [install-requires-vs-requirements](https://packaging.python.org/en/latest/discussions/install-requires-vs-requirements/) – djvg Dec 13 '22 at 09:11
  • related: https://stackoverflow.com/q/6947988, https://stackoverflow.com/q/14399534 – djvg Dec 13 '22 at 10:26

4 Answers4

159

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

It can be produced easily by pip itself:

pip freeze > requirements.txt

pip automatically tries to only add packages that are not installed by default, so the produced file is pretty minimal.


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.

AndreasT
  • 9,417
  • 11
  • 46
  • 60
  • 8
    In which cases would I have only one of them? In which would I have both? – Martin Thoma Feb 24 '18 at 22:00
  • 58
    Erm... you just script for fun on your local machine: Neither. Script is developed on multiple machines/vitualenvs but not redistributed: requirements.txt. Script is developed only on your machine but should be redistributed: setup.py. Script will be redistributed and developed in multiple environments: Both. – AndreasT Feb 26 '18 at 10:20
  • Could you add this to the answer? – Martin Thoma Feb 26 '18 at 11:54
  • 1
    Would you ever really have `setup.py` without `requirements.txt`? Asking for a friend who totally doesn't understand this stuff. – eric Oct 21 '20 at 13:57
  • What is the advantage of that (either `setup.py` or `requirements.txt`) vs just having a `.sh` script were I conda/pip install each package? – Charlie Parker Apr 23 '21 at 17:52
  • @CharlieParker Well, setup.py is an integration into python's cross-platform setup and packaging machinery, and requirements.txt is mostly a convention. As is so often the case in foss: you can of course roll your own, but you probably shouldn't. – AndreasT Apr 24 '21 at 12:11
  • @AndreasT what does redistributed mean? – Charlie Parker Jul 13 '21 at 21:10
  • 3
    On developer end, why not use pip install -e . to match dependencies? – John Nov 18 '21 at 07:50
  • @eric yes, definitely. I usually never have a requirements.txt and I simply `pip install -e .` when I am doing dev work on a project. – juanpa.arrivillaga Apr 28 '22 at 21:44
  • @CharlieParker that this is totally non-portable. Also, it doesn't do the same thing as `pip install`, unless your `.sh` script re-implements what `pip` does – juanpa.arrivillaga Apr 28 '22 at 21:45
130

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.

init_js
  • 4,143
  • 2
  • 23
  • 53
  • 11
    and you can also have just `.` w/o `-e` inside `requirements.txt`. This method just delegates all the requirements to `setup.py` and you don't need to force anybody into the editable mode. Users can still do `pip install -e .` if they want to. – stason Oct 17 '18 at 06:42
  • 2
    Interesting trick with "-e ." in requirements.txt, but doesn't that defeat the purpose of requirements.txt being the exact system specifications? Why even have one in that case? – Ben Ogorek Feb 11 '20 at 03:21
  • You can have the exact system requirements inside setup.py. Having "." in requirements.txt makes it use the setup.py in the current folder. Using `-e .` also uses setup.py to find dependencies, but links the current folder (in place, with a symlink) in the pip install folder, rather than taking a copy -- you'd use `-e` generally only if you're developing the package. With `-e`, changes to your python package files (*.py) would take effect immediately in your pip environment, rather than having to force re-install the package after each change. – init_js Feb 22 '20 at 16:30
  • @init_js is the "current folder" relative to the requirements file or CWD from which pip is called? I.e. if you do `cd foo && pip install -r ./bar/requirements.txt` will it search for setup.py in `foo/bar` or `foo`? If the latter, is there a way to achieve the former? – Dan M. Jul 14 '20 at 10:37
  • `pip -r REQ` doesn't care about the directory in which REQ is. You can feed it from a fifo even if you want: `pip install -r <(echo "mylib1"; echo "mylib2";)`. Where `<(CMD)` is bash command substitution, not stdin redirection. – init_js Jul 15 '20 at 02:18
  • @stason. "you can also have just `.`, w/o -e" I agree. But when you say "users can still do pip install -e", you mean "developers" I think. Most _users_ will pip install from package repositories, or via easyinstall pypi. – init_js Jul 22 '20 at 16:39
  • What is the advantage of that (either `setup.py` or `requirements.txt`) vs just having a `.sh` script were I conda/pip install each package? – Charlie Parker Apr 23 '21 at 17:52
  • 1
    @BenOgorek Libraries need only setup.py, not requirements.txt. You don't want to be writing a library in an artificially constrained dev environment (with tighter version constraints coming from requirements.txt), because your users will not have such a tidy situation. They will experience life only through the lens of setup.py. But some CI systems demand a requirements.txt file. That's a situation where the dot trick helps. – FMc Apr 30 '21 at 05:32
  • Having the `-e` was critical for me. Without the `-e`, `pip install .` was creating a `build` dir. – wisbucky Jan 11 '22 at 05:02
38

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
    
  1. 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.

  2. 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.)

RayLuo
  • 17,257
  • 6
  • 88
  • 73
  • "your library would not (and it must not) be 'picky' about what exact version of YOUR dependencies should be." Could you elaborate on this point a bit? I guess your code is typically tested with only specific versions of dependencies, and this approach can be a bit dangerous. I assume a library should work with a range of versions because you do not want to install too many versions of dependencies? To save disk space? – Taro Kiritani Jul 23 '19 at 05:14
  • @TaroKiritani Actually I listed 2 different scenarios side-by-side, the library case and the application case. Perhaps you did not work on a library before? As a library, it is expected to be consumed by downstream packages. So if you are picky to pin YOUR dependency `A==1.2.3`, and then if your library's downstream package happens to depend on `A==1.2.4`, now there won't be a way to satisfy both. The solution to minimize this conflict is your library define a range that you know would work. Assuming many upstream library already follows [semver.org](http://semver.org), `A>=1,<2` would work. – RayLuo Jul 23 '19 at 07:14
  • I did not realize only one version of a package can be installed in a single environment. https://stackoverflow.com/a/6572017/5686692 Thanks for clarification. – Taro Kiritani Jul 23 '19 at 11:02
  • 1
    @TaroKiritani, yeah, otherwise how would your app know which version of `foo` does `import foo` give you? Those hacky accepted answer in [that link you provided](https://stackoverflow.com/questions/6570635/installing-multiple-versions-of-a-package-with-pip/6572017#6572017) serves as a perfect example of why package maintainer "should not and must not be picky". :-) Now may I have your upvote? – RayLuo Jul 23 '19 at 16:30
  • I suppose we then need to use tox or something in order to guarantee my library works on various combinations of dependencies. It can be quite costly to check all the combinations of dependency versions, though. I wish we had an option to import a specific version like `import foo==1.0` or something. – Taro Kiritani Jul 25 '19 at 08:19
  • 1
    I could also comment on that new thought but then this comments section is already going off-topic and difficult for new comers to follow. I would suggest you to ask a new question "Shall we use tox or something in order to guarantee my library works on various combinations of dependencies", and then people can chime in. – RayLuo Jul 25 '19 at 21:44
  • What is the advantage of that (either `setup.py` or `requirements.txt`) vs just having a `.sh` script were I conda/pip install each package? – Charlie Parker Apr 23 '21 at 17:53
  • 2
    @CharlieParker, "if you are developing a library foo which will be used by import foo, you have to prepare a `setup.py`. Period." Because your downstream library or application would be unable to trigger your `.sh` script. But, based on your question, I guess you are not a library developer. Then, yes, you can go whatever way you want, you just need to document the installation steps for your end user. I would still argue, though, that a one-dependency-per-line `requirements.txt` is more universal and pythonic than a `.sh`. What if your end user is on Windows that can not run `.sh`? – RayLuo Apr 23 '21 at 21:25
  • 1
    Very useful answer -- and link to Donald Stufft blog post. Solved a problem for me, so thank you. I do think you underrate the value for library developers (me) of using the magical-dot trick in requirements.txt. I don't need/want requirements.txt as a library developer, because my users will experience only setup.py. However, some CI systems demand it. So the magic dot will keep my life simpler by not needing to duplicate the list of dependencies. – FMc Apr 30 '21 at 05:23
  • @FMc, thanks for your upvote and feedback! I'm a library maintainer, too. I think what you said was right, so I updated my answer accordingly. Thank you! – RayLuo Apr 30 '21 at 09:14
7

TL;DR

  • requirements.txt lists concrete dependencies
  • setup.py lists abstract dependencies

A common misunderstanding with respect to dependency management in Python is whether you need to use a requirements.txt or setup.py file in order to handle dependencies.

The chances are you may have to use both in order to ensure that dependencies are handled appropriately in your Python project.

The requirements.txt file is supposed to list the concrete dependencies. In other words, it should list pinned dependencies (using the == specifier). This file will then be used in order to create a working virtual environment that will have all the dependencies installed, with the specified versions.

On the other hand, the setup.py file should list the abstract dependencies. This means that it should list the minimal dependencies for running the project. Apart from dependency management though, this file also serves the package distribution (say on PyPI).

For a more comprehensive read, you can read the article requirements.txt vs setup.py in Python on TDS.


Now going forward and as of PEP-517 and PEP-518, you may have to use a pyproject.toml in order to specify that you want to use setuptools as the build-tool and an additional setup.cfg file to specify the details. For more details you can read the article setup.py vs setup.cfg in Python.

Giorgos Myrianthous
  • 36,235
  • 20
  • 134
  • 156
  • Thanks @Giorgos - I read your excellent TDS article. One think you wrote I don't think is correct: "Note that if you want to install packages in editable mode (i.e. by running pip install -e .) you must have a valid setup.py file apart from setup.cfg and pyproject.toml". I am able to run "pip install -e ." and I just have `setup.cfg` and `pyproject.toml` files: https://github.com/Ishangoai/Ishango_Assessments I don't see any reason to use `setup.py` anymore... – Oliver Angelil Jul 27 '22 at 19:12
  • https://stackoverflow.com/a/66472800/5392289 – Oliver Angelil Jul 28 '22 at 05:05