Python Packaging
As of 2020 (PEP 621), the standard way
of packging a python project is by using a pyproject.toml file. Using setup.cfg
as config file for building a python project is deprecated. You can still
use setup.py (if you use setuptools as your build backend) as your build config
file, but it is recommended to not use it as a command line tool. For example,
instead of using python setup.py install, use pip install .. For details
see here.
If you still prefer using setup.py as your build configuration file and
setuptools as your build backend, it is still recommended to have a pyproject.toml
file with the [build-system] section specifing the use of setuptools as your
build backend. Here, I choose to use hatchling as the build backend.
Below is a minimum pyproject.toml file for packaging a python project
Minimal pyproject.toml file
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my_project"
version = "1.0"
The [build-system] section is required, and there are many build-backends
available. In the requires key, we should specify all the dependencies
required at build time. If we are simply running pip install in
non-editable mode these build dependencies will be install in an isolated
build environment. For the build-backend field, we specify the module to be
called to build the project.
There are many other build backend we can use. For a pure python project, hatchling is a good choice as is has some good defaults out of the box.
For projects with C/C++/Cython extensions, we can use meson-python (if you prefer meson as your C/C++ build system) or scikit-build-core (if you prefer CMake as your C/C++ build system). I will probably cover this in another post.
Other useful sections
For a complete example of pyproject.toml, see
here.
Here, I want to just highlight a few sections that I find useful.
[project]
requires-python = ">= 3.10"
dependencies = [
"numpy",
"pandas<2.0",
]
The above specifies the minimum python supported by your project and the run time dependencies of your project.
[project.scripts]
command-one = "my_proj:main"
command-two = "my_proj.my_module:func"
The [project.scripts] section lets you sepcify specific functions in your
package to expose as command-line executables. In the example above, after
installing your package, running command-one directly from the command line
will call your main function in the my_proj module. Similarly command-two
executes your function func in the module my_proj.my_module.