requirements.txt, alongside setup.py, is the most common -- yet imprecise -- approach to dependency management in python projects.
requirements.txt: Find all files matching the glob: req*.txt
setup.py: Find all files named setup.py
requirements.txt contains direct dependencies, and is parsed compliant to its file format spec.
pip-cli options, URLs, absolute paths, and relative paths are ignored -- though this may be revisited in the future.
Dependencies found in requirements.txt have a spec defined by PEP-508. Dependencies often have version ranges and environment markers (e.g. python version, OS, ...). The resulting graph contains packages tagged with environment markers.
setup.py is naively scanned for its install_requires=[...] field, which often
fails on projects encountered in the wild. Short of implementing a robust python
parser, or running a python script in their environment (which may have
unintended consequences!), reliable output from setup.py is difficult to obtain.
Entries in the install_requires array are parsed compliant to the
PEP-508 spec, similar to requirements.txt
- Python requirements files and setup.py files do not provide any data about edges between dependencies.
- Requirements files can be completely different than an existing setup.py specification, as there is no built-in synchronization between them.
- Since we don't completely parse the python files, any programmability done in the
setup.pyfile will hide the trueinstall_requireslist from our view. However, we do catch variables namedinstall_requiresas well, as long as they are declared earlier in the file than theinstall_requireskeyword argument tosetup. - Often, the
requirements.txtfile entirely overlaps thesetup.pyfile. This is almost always by design.
Given the following files:
setup.py (manually created):
setup(
name='Foo-project',
version='1.0',
description='Python example project',
author='Jeff Jefferson',
author_email='bug-catcher@butterfly.net',
url='https://this.url/means#nothing',
packages=['foo'],
# And now the important part...
install_requires=[
"requests",
],
)requirements.txt (obtained by running pip install requests && pip freeze > requirements.txt):
Note: your requirements file may have different versions. This file is just a reference example.
certifi==2021.5.30
chardet==4.0.0
idna==2.10
requests==2.25.1
urllib3==1.26.6We will produce a list of these direct dependencies with no edges between them (see #limitations):
certifi==2021.5.30
chardet==4.0.0
idna==2.10
requests==2.25.1
urllib3==1.26.6