1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
|
.. _pyproject.toml config:
-----------------------------------------------------
Configuring setuptools using ``pyproject.toml`` files
-----------------------------------------------------
.. note:: New in 61.0.0
.. important::
If compatibility with legacy builds or versions of tools that don't support
certain packaging standards (e.g. :pep:`517` or :pep:`660`), a simple ``setup.py``
script can be added to your project [#setupcfg-caveats]_
(while keeping the configuration in ``pyproject.toml``):
.. code-block:: python
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.
:pypi:`build` or :pypi:`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 the
:doc:`PyPUG:guides/writing-pyproject-toml` guide.
.. _example-pyproject-config:
.. code-block:: toml
[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"
[project]
name = "my_package"
authors = [
{name = "Josiah Carberry", email = "josiah_carberry@brown.edu"},
]
description = "My package description"
readme = "README.rst"
requires-python = ">=3.8"
keywords = ["one", "two"]
license = "BSD-3-Clause"
classifiers = [
"Framework :: Django",
"Programming Language :: Python :: 3",
]
dependencies = [
"requests",
'importlib-metadata; python_version<"3.10"',
]
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 listed in:
# https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
.. important::
Support for
:external+PyPUG:ref:`project.license-files <license-files>`
and SPDX license expressions in
:external+PyPUG:ref:`project.license <license>` (:pep:`639`)
were introduced in version 77.0.0.
.. _setuptools-table:
Setuptools-specific configuration
=================================
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 :doc:`/references/keywords` used by the ``setup.py``
file, and can be set via the ``tool.setuptools`` table:
========================= =========================== =========================
Key Value Type (TOML) Notes
========================= =========================== =========================
``py-modules`` array See tip below.
``ext-modules`` array of **Experimental** - Each item corresponds to a
tables/inline-tables :class:`setuptools.Extension` object and may define
the associated parameters in :wiki:`kebab-case`.
``packages`` array or ``find`` directive See tip below.
``package-dir`` table/inline-table Used when explicitly/manually listing ``packages``.
------------------------- --------------------------- -------------------------
``package-data`` table/inline-table See :doc:`/userguide/datafiles`.
``include-package-data`` boolean ``True`` by default (only when using ``pyproject.toml`` project metadata/config).
See :doc:`/userguide/datafiles`.
``exclude-package-data`` table/inline-table Empty by default. See :doc:`/userguide/datafiles`.
------------------------- --------------------------- -------------------------
``license-files`` array of glob patterns **Deprecated** - use ``project.license-files`` instead. See
:external+PyPUG:ref:`Writing your pyproject.toml <license-files>`
(by default: ``['LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*']``)
``data-files`` table/inline-table **Discouraged** - check :doc:`/userguide/datafiles`.
Whenever possible, consider using data files inside the package directories.
``script-files`` array **Discouraged** - equivalent to the ``script`` keyword in ``setup.py``.
Whenever possible, please use ``project.scripts`` instead.
------------------------- --------------------------- -------------------------
``provides`` array *ignored by pip when installing packages*
``obsoletes`` array *ignored by pip when installing packages*
``platforms`` array Sets the ``Platform`` :doc:`core-metadata <PyPUG:specifications/core-metadata>` field
(*ignored by pip when installing packages*).
------------------------- --------------------------- -------------------------
``zip-safe`` boolean **Obsolete** - only relevant for ``pkg_resources``, ``easy_install`` and ``setup.py install``
in the context of :doc:`eggs </deprecated/python_eggs>` (deprecated).
``eager-resources`` array **Obsolete** - only relevant for ``pkg_resources``, ``easy_install`` and ``setup.py install``
in the context of :doc:`eggs </deprecated/python_eggs>` (deprecated).
``namespace-packages`` array **Deprecated** - use implicit namespaces instead (:pep:`420`).
========================= =========================== =========================
.. note::
The `TOML value types`_ ``array`` and ``table/inline-table`` are roughly
equivalent to the Python's :obj:`list` and :obj:`dict` data types, respectively.
Please note that some of these configurations are deprecated, obsolete or at least
discouraged, but they are made available to ensure portability.
Deprecated and obsolete configurations may be removed in future versions of ``setuptools``.
New packages should avoid relying on discouraged fields if possible, and
existing packages should consider migrating to alternatives.
.. tip::
When both ``py-modules`` and ``packages`` are left unspecified,
``setuptools`` will attempt to perform :ref:`auto-discovery`, which should
cover most popular project directory organization techniques, such as the
:ref:`src-layout` and the :ref:`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 [#directives]_ as shown below:
.. code-block:: toml
[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:
.. code-block:: toml
[tool.setuptools]
packages = ["my_package"]
If you want to publish a distribution that does not include any Python module
(e.g. a "meta-distribution" that just aggregate dependencies), please
consider something like the following:
.. code-block:: toml
[tool.setuptools]
packages = []
.. _dynamic-pyproject-config:
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`` :wiki:`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
[#entry-points]_. For example:
.. code-block:: toml
# ...
[project]
name = "my_package"
dynamic = ["version", "readme"]
# ...
[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"} # any module attribute compatible with ast.literal_eval
readme = {file = ["README.rst", "USAGE.rst"]}
In the ``dynamic`` table, the ``attr`` directive [#directives]_ will read an
attribute from the given module [#attr]_, while ``file`` will read the contents
of all given files and concatenate them in a single string.
========================== =================== =================================================================================================
Key Directive Notes
========================== =================== =================================================================================================
``version`` ``attr``, ``file``
``readme`` ``file`` Here you can also set ``"content-type"``:
``readme = {file = ["README.txt", "USAGE.txt"], content-type = "text/plain"}``
If ``content-type`` is not given, ``"text/x-rst"`` is used by default.
``description`` ``file`` One-line text (no line breaks)
``classifiers`` ``file`` Multi-line text with one classifier per line
``entry-points`` ``file`` INI format following :doc:`PyPUG:specifications/entry-points`
(``console_scripts`` and ``gui_scripts`` can be included)
``dependencies`` ``file`` *subset* of the ``requirements.txt`` format
(``#`` comments and blank lines excluded) **BETA**
``optional-dependencies`` ``file`` *subset* of the ``requirements.txt`` format per group
(``#`` comments and blank lines excluded) **BETA**
========================== =================== =================================================================================================
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`` specific syntaxes, e.g. ``-c/-r/-e`` and other flags, are not supported).
.. note::
If you are using an old version of ``setuptools``, you might need to ensure
that all files referenced by the ``file`` directive are included in the ``sdist``
(you can do that via ``MANIFEST.in`` or using plugins such as ``setuptools-scm``,
please have a look on :doc:`/userguide/miscellaneous` for more information).
.. versionchanged:: 66.1.0
Newer versions of ``setuptools`` will automatically add these files to the ``sdist``.
It is advisable to use literal values together with ``attr`` (e.g. ``str``,
``tuple[str]``, see :func:`ast.literal_eval`). This is recommend
in order to support the common case of a literal value assigned to a variable
in a module containing (directly or indirectly) third-party imports.
``attr`` first tries to read the value from the module by examining the
module's AST. If that fails, ``attr`` falls back to importing the module,
using :func:`importlib.util.spec_from_file_location` recommended recipe
(see :ref:`example on Python docs <python:importlib-examples>`
about "Importing a source file directly").
Note however that importing the module is error prone since your package is
not installed yet. You may also need to manually add the project directory to
``sys.path`` (via ``setup.py``) in order to be able to do that.
----
.. rubric:: Notes
.. [#setupcfg-caveats] ``pip`` may allow editable install only with ``pyproject.toml``
and ``setup.cfg``. However, this behavior may not be consistent over various ``pip``
versions and other packaging-related tools
(``setup.py`` is more reliable on those scenarios).
.. [#entry-points] Dynamic ``scripts`` and ``gui-scripts`` are a special case.
When resolving these metadata keys, ``setuptools`` will look for
``tool.setuptools.dynamic.entry-points``, and use the values of the
``console_scripts`` and ``gui_scripts`` :doc:`entry-point groups
<PyPUG:specifications/entry-points>`.
.. [#directives] In the context of this document, *directives* are special TOML
values that are interpreted differently by ``setuptools`` (usually triggering an
associated function). Most of the times they correspond to a special TOML table
(or inline-table) with a single top-level key.
For example, you can have the ``{find = {where = ["src"], exclude=["tests*"]}}``
directive for ``tool.setuptools.packages``, or ``{attr = "mymodule.attr"}``
directive for ``tool.setuptools.dynamic.version``.
.. [#attr] ``attr`` is meant to be used when the module attribute is statically
specified (e.g. as a string). As a rule of thumb, the
attribute should be able to be parsed with :func:`ast.literal_eval`, and
should not be modified or re-assigned.
.. _TOML value types: https://toml.io/en/v1.0.0
|