Configuring setuptools using pyproject.toml
files#
Note
New in 61.0.0
Important
For the time being [1], pip
still might require a setup.py
file
to support editable installs [2].
A simple script will suffice, for example:
from setuptools import setup
setup()
Starting with PEP 621, the Python community selected pyproject.toml
as
a standard way of specifying project metadata.
Setuptools
has adopted this standard and will use the information contained
in this file as an input in the build process.
The example below illustrates how to write a pyproject.toml
file that can
be used with setuptools
. It contains two TOML tables (identified by the
[table-header]
syntax): build-system
and project
.
The build-system
table is used to tell the build frontend (e.g.
build or pip) to use setuptools
and any other plugins (e.g.
setuptools-scm
) to build the package.
The project
table contains metadata fields as described by
PyPUG:specifications/declaring-project-metadata guide.
[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"
[project]
name = "my_package"
description = "My package description"
readme = "README.rst"
requires-python = ">=3.7"
keywords = ["one", "two"]
license = {text = "BSD 3-Clause License"}
classifiers = [
"Framework :: Django",
"Programming Language :: Python :: 3",
]
dependencies = [
"requests",
'importlib-metadata; python_version<"3.8"',
]
dynamic = ["version"]
[project.optional-dependencies]
pdf = ["ReportLab>=1.2", "RXP"]
rest = ["docutils>=0.3", "pack ==1.1, ==1.3"]
[project.scripts]
my-script = "my_package.module:function"
# ... other project metadata fields as specified in:
# https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
Setuptools-specific configuration#
Warning
Support for declaring configurations not standardized by PEP 621
(i.e. the [tool.setuptools]
table),
is still in beta stage and might change in future releases.
While the standard project
table in the pyproject.toml
file covers most
of the metadata used during the packaging process, there are still some
setuptools
-specific configurations that can be set by users that require
customization.
These configurations are completely optional and probably can be skipped when
creating simple packages.
They are equivalent to the Keywords used by the setup.py
file, and can be set via the tool.setuptools
table:
Key |
Value Type (TOML) |
Notes |
---|---|---|
|
array |
|
|
boolean |
If not specified, |
|
array |
|
|
array |
See tip below |
|
array or |
See tip below |
|
table/inline-table |
Used when explicitly listing |
|
array |
Deprecated - Use implicit namespaces instead (PEP 420) |
|
table/inline-table |
|
|
boolean |
|
|
table/inline-table |
|
|
array of glob patterns |
Provisional - likely to change with PEP 639
(by default: |
|
table/inline-table |
Discouraged - check Data Files Support |
|
array |
Deprecated - equivalent to the |
|
array |
Ignored by pip |
|
array |
Ignored by pip |
Note
The TOML value types array
and table/inline-table
are roughly
equivalent to the Python’s dict
and list
data types.
Please note that some of these configurations are deprecated or at least discouraged, but they are made available to ensure portability. New packages should avoid relying on deprecated/discouraged fields, and existing packages should consider alternatives.
Tip
When both py-modules
and packages
are left unspecified,
setuptools
will attempt to perform Automatic discovery, which should
cover most popular project directory organization techniques, such as the
src-layout and the flat-layout.
However if your project does not follow these conventional layouts
(e.g. you want to use a flat-layout
but at the same time have custom
directories at the root of your project), you might need to use the find
directive [4] as shown below:
[tool.setuptools.packages.find]
where = ["src"] # list of folders that contain the packages (["."] by default)
include = ["my_package*"] # package names should match these glob patterns (["*"] by default)
exclude = ["my_package.tests*"] # exclude packages matching these glob patterns (empty by default)
namespaces = false # to disable scanning PEP 420 namespaces (true by default)
Note that the glob patterns in the example above need to be matched
by the entire package name. This means that if you specify exclude = ["tests"]
,
modules like tests.my_package.test1
will still be included in the distribution
(to remove them, add a wildcard to the end of the pattern: "tests*"
).
Alternatively, you can explicitly list the packages in modules:
[tool.setuptools]
packages = ["my_package"]
Dynamic Metadata#
Note that in the first example of this page we use dynamic
to identify
which metadata fields are dynamically computed during the build by either
setuptools
itself or the plugins installed via build-system.requires
(e.g. setuptools-scm
is capable of deriving the current project version
directly from the git
version control system).
Currently the following fields can be listed as dynamic: version
,
classifiers
, description
, entry-points
, scripts
,
gui-scripts
and readme
.
When these fields are expected to be provided by setuptools
a
corresponding entry is required in the tool.setuptools.dynamic
table
[3]. For example:
# ...
[project]
name = "my_package"
dynamic = ["version", "readme"]
# ...
[tool.setuptools.dynamic]
version = {attr = "my_package.VERSION"}
readme = {file = ["README.rst", "USAGE.rst"]}
In the dynamic
table, the attr
directive [4] will read an
attribute from the given module [5], while file
will read the contents
of all given files and concatenate them in a single string.
Key |
Directive |
Notes |
---|---|---|
|
|
|
|
|
|
|
|
One-line text |
|
|
Multi-line text with one classifier per line |
|
|
INI format following Entry points specification
( |
|
|
|
|
|
|
Supporting file
for dependencies is meant for a convenience for packaging
applications with possibly strictly versioned dependencies.
Library packagers are discouraged from using overly strict (or “locked”)
dependency versions in their dependencies
and optional-dependencies
.
Currently, when specifying optional-dependencies
dynamically, all of the groups
must be specified dynamically; one can not specify some of them statically and
some of them dynamically.
Also note that the file format for specifying dependencies resembles a requirements.txt
file,
however please keep in mind that all non-comment lines must conform with PEP 508
(pip
-specify syntaxes, e.g. -c/-r/-e
flags, are not supported).
Notes