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
.