setup.py for setuptools-based Python packages can be reduced to a one-line file for simple Python packages, by putting the project
metadata in setup.cfg.
The example setup.cfg file below is associated with a setup.py file containing merely:
from setuptools import setup; setup()
This is installed as usual like:
python -m pip install -e .
It can be most effective to put all project configuration, including Python package prerequisites in setup.cfg instead of setup.py. setup.cfg is human-readable and machine-parseable without first installing the package. Putting as many parameters as possible into setup.cfg instead of setup.py is important and beneficial for reasons including:
- reproducible results
- security risk mitigation
- getting package prerequisite tree list
This is an example of best practices (since 2016) of minimal
It does not use
setup.cfg holds the machine-readable configuration, easy for humans too:
[metadata] name = mycoolpkg author = Joe Smith author_email = firstname.lastname@example.org description = My awesome program prints cool messages version = file: __init__.py url = https://github.com/joe/mycoolpkg keywords = cool printing networking classifiers = Development Status :: 4 - Beta Intended Audience :: Science/Research Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Topic :: Scientific/Engineering long_description = file: README.md long_description_content_type = text/markdown license_files = LICENSE.txt [options] python_requires = >= 3.7 packages = find: zip_safe = False install_requires = # numpy [options.extras_require] tests = pytest flake8 mypy [options.entry_points] console_scripts = # joesprog = joesprog:main
The companion to setup.cfg is pyproject.toml.
pyproject.toml is used in general for Python project settings, including ones not using setuptools.
The standard way to communicate that setuptools is used for a Python project is with pyproject.toml containing:
[build-system] requires = ["setuptools", "wheel"] [tool.pytest.ini_options] addopts = "-ra -v"
PyTest is also configured in pyproject.toml instead of pytest.ini or setup.cfg.
Test coverage is configured in
[run] cover_pylib = false omit = /home/travis/virtualenv/* */site-packages/* [report] exclude_lines = pragma: no cover def __repr__ RuntimeError NotImplementedError FileNotFoundError ImportError
PEP8 / Type hinting checks
PEP8 checking via
flake8 is configured in
[flake8] max-line-length = 132 exclude = .git,__pycache__,doc/,docs/,build/,dist/,archive/ per-file-ignores = __init__.py:F401
MyPy type hint checking is configured via .mypy.ini.
MANIFEST.in is usually not necessary. It’s better in general to specify scripts and data files in setup.cfg.
file:is not in the setup.cfg install_requires input types
console_scriptsexpects a file
joesprog.pywith the function
maindesigned to accept command line input, perhaps using
python_requiresparameter avoids user confusion if they have an old Python version. Instead of them opening a GitHub issue or just not using your program at all, they’ll get a useful error message.
Classifiers are optional, but help your project be indexed better in PyPi (and hence search engines). Classifiers must be from this official classifiers list or they will fail when uploading your package to PyPi.
- setup.py reference (excellent)
- setup.py notes from core Python developer
- don’t use requirements.txt for general prereqs