Python offers several methods for specifying project dependencies, each suited for different use cases:
The traditional and simplest approach:
requests==2.28.1
numpy>=1.20.0
pandas~=1.5.0- Uses pip's format with version specifiers (
==,>=,~=,!=) - Common convention:
requirements.txtfor production,requirements-dev.txtfor development dependencies - Installed via
pip install -r requirements.txt
For creating installable packages:
setup(
name="mypackage",
install_requires=[
"requests>=2.20.0",
"numpy",
],
extras_require={
"dev": ["pytest", "black"],
}
)- Defines both package metadata and dependencies
- Supports optional dependency groups via
extras_require - Used when distributing packages to PyPI
The modern, standardized approach (PEP 518, 621):
[project]
dependencies = [
"requests>=2.20.0",
"numpy>=1.20",
]
[project.optional-dependencies]
dev = ["pytest", "black"]- Unified configuration file for build systems and tools
- Replaces
setup.pyfor many use cases - Supported by modern tools like Poetry, Flit, and pip
Used by Pipenv:
[packages]
requests = "*"
[dev-packages]
pytest = "*"- Separates abstract dependencies (Pipfile) from concrete locked versions (Pipfile.lock)
- Provides deterministic builds via lock file
Poetry's approach combines both:
- Dependencies specified in
pyproject.toml - Exact versions locked in
poetry.lock - Handles dependency resolution automatically
For conda environments:
dependencies:
- python=3.9
- numpy
- pip:
- requests- Can specify both conda and pip packages
- Useful for scientific computing with non-Python dependencies
==2.0.0- exact version>=1.5.0- minimum version~=1.5.0- compatible release (>=1.5.0, <1.6.0)>=1.0,<2.0- version range
Current trend: The ecosystem is moving toward pyproject.toml as the standard for all Python projects, with lock files (Poetry, PDM, or pip-tools) for reproducible environments.