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
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
|
==========================
``setuptools`` Quickstart
==========================
Installation
============
To install the latest version of setuptools, use::
pip install --upgrade setuptools
Python packaging at a glance
============================
The landscape of Python packaging is shifting and ``Setuptools`` has evolved to
only provide backend support, no longer being the de-facto packaging tool in
the market. Every python package must provide a ``pyproject.toml`` and specify
the backend (build system) it wants to use. The distribution can then
be generated with whatever tool that provides a ``build sdist``-like
functionality. While this may appear cumbersome, given the added pieces,
it in fact tremendously enhances the portability of your package. The
change is driven under :pep:`PEP 517 <517#build-requirements>`. To learn more about Python packaging in general,
navigate to the :ref:`bottom <packaging-resources>` of this page.
Basic Use
=========
For basic use of setuptools, you will need a ``pyproject.toml`` with the
exact following info, which declares you want to use ``setuptools`` to
package your project:
.. code-block:: toml
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
Then, you will need to specify your package information such as metadata,
contents, dependencies, etc.
Setuptools currently supports configurations from either ``setup.cfg``,
``setup.py`` or ``pyproject.toml`` [#experimental]_ files, however, configuring new
projects via ``setup.py`` is discouraged [#setup.py]_.
The following example demonstrates a minimum configuration:
.. tab:: setup.cfg
.. code-block:: ini
[metadata]
name = mypackage
version = 0.0.1
[options]
packages = mypackage
install_requires =
requests
importlib-metadata; python_version < "3.8"
See :doc:`/userguide/declarative_config` for more information.
.. tab:: setup.py [#setup.py]_
.. code-block:: python
from setuptools import setup
setup(
name='mypackage',
version='0.0.1',
packages=['mypackage'],
install_requires=[
'requests',
'importlib-metadata; python_version == "3.8"',
],
)
See :doc:`/references/keywords` for more information.
.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
.. code-block:: toml
[project]
name = "mypackage"
version = "0.0.1"
dependencies = [
"requests",
'importlib-metadata; python_version<"3.8"',
]
See :doc:`/userguide/pyproject_config` for more information.
This is what your project would look like::
~/mypackage/
pyproject.toml
setup.cfg # or setup.py
mypackage/__init__.py
Then, you need a builder, such as :std:doc:`PyPA build <pypa-build:index>`
which you can obtain via ``pip install build``. After downloading it, invoke
the builder::
python -m build
You now have your distribution ready (e.g. a ``tar.gz`` file and a ``.whl``
file in the ``dist`` directory), which you can upload to PyPI!
Of course, before you release your project to PyPI, you'll want to add a bit
more information to your setup script to help people find or learn about your
project. And maybe your project will have grown by then to include a few
dependencies, and perhaps some data files and scripts. In the next few sections,
we will walk through the additional but essential information you need
to specify to properly package your project.
Automatic package discovery
===========================
For simple projects, it's usually easy enough to manually add packages to
the ``packages`` keyword in ``setup.cfg``. However, for very large projects,
it can be a big burden to keep the package list updated.
Therefore, ``setuptools`` provides a convenient way to automatically list all
the packages in your project directory:
.. tab:: setup.cfg
.. code-block:: ini
[options]
packages = find: # OR `find_namespaces:` if you want to use namespaces
[options.packages.find] (always `find` even if `find_namespaces:` was used before)
# This section is optional
# Each entry in this section is optional, and if not specified, the default values are:
# `where=.`, `include=*` and `exclude=` (empty).
include=mypackage*
exclude=mypackage.tests*
.. tab:: setup.py [#setup.py]_
.. code-block:: python
from setuptools import find_packages # or find_namespace_packages
setup(
# ...
packages=find_packages(
where='.',
include=['mypackage*'], # ["*"] by default
exclude=['mypackage.tests'], # empty by default
),
# ...
)
.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
.. code-block:: toml
# ...
[tool.setuptools.packages]
find = {} # Scan the project directory with the default parameters
# OR
[tool.setuptools.packages.find]
where = ["src"] # ["."] by default
include = ["mypackage*"] # ["*"] by default
exclude = ["mypackage.tests*"] # empty by default
namespaces = false # true by default
When you pass the above information, alongside other necessary information,
``setuptools`` walks through the directory specified in ``where`` (omitted
here as the package resides in the current directory) and filters the packages
it can find following the ``include`` (defaults to none), then removes
those that match the ``exclude`` and returns a list of Python packages. The above
setup also allows you to adopt a ``src/`` layout. For more details and advanced
use, go to :ref:`package_discovery`.
.. tip::
Starting with version 61.0.0, setuptools' automatic discovery capabilities
have been improved to detect popular project layouts (such as the
:ref:`flat-layout` and :ref:`src-layout`) without requiring any
special configuration. Check out our :ref:`reference docs <package_discovery>`
for more information, but please keep in mind that this functionality is
still considered **experimental** and might change (or even be removed) in
future releases.
Entry points and automatic script creation
===========================================
Setuptools supports automatic creation of scripts upon installation, that runs
code within your package if you specify them as :doc:`entry points
<PyPUG:specifications/entry-points>`.
This is what allows you to run commands like ``pip install`` instead of having
to type ``python -m pip install``.
The following configuration examples show how to accomplish this:
.. tab:: setup.cfg
.. code-block:: ini
[options.entry_points]
console_scripts =
cli-name = mypkg.mymodule:some_func
.. tab:: setup.py [#setup.py]_
.. code-block:: python
setup(
# ...
entry_points={
'console_scripts': [
'cli-name = mypkg.mymodule:some_func',
]
}
)
.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
.. code-block:: toml
[project.scripts]
cli-name = "mypkg.mymodule:some_func"
When this project is installed, a ``cli-name`` executable will be created.
``cli-name`` will invoke the function ``some_func`` in the
``mypkg/mymodule.py`` file when called by the user.
Note that you can also use the ``entry-points`` mechanism to advertise
components between installed packages and implement plugin systems.
For detailed usage, go to :doc:`entry_point`.
Dependency management
=====================
Packages built with ``setuptools`` can specify dependencies to be automatically
installed when the package itself is installed.
The example below show how to configure this kind of dependencies:
.. tab:: setup.cfg
.. code-block:: ini
[options]
install_requires =
docutils
requests <= 0.4
.. tab:: setup.py [#setup.py]_
.. code-block:: python
setup(
# ...
install_requires=["docutils", "requests <= 0.4"],
# ...
)
.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
.. code-block:: toml
[project]
# ...
dependencies = [
"docutils",
"requires <= 0.4",
]
# ...
Each dependency is represented by a string that can optionally contain version requirements
(e.g. one of the operators <, >, <=, >=, == or !=, followed by a version identifier),
and/or conditional environment markers, e.g. ``sys_platform == "win32"``
(see :doc:`PyPUG:specifications/version-specifiers` for more information).
When your project is installed, all of the dependencies not already installed
will be located (via PyPI), downloaded, built (if necessary), and installed.
This, of course, is a simplified scenario. You can also specify groups of
extra dependencies that are not strictly required by your package to work, but
that will provide additional functionalities.
For more advanced use, see :doc:`dependency_management`.
.. _Including Data Files:
Including Data Files
====================
The distutils have traditionally allowed installation of "data files", which
are placed in a platform-specific location. Setuptools offers three ways to
specify data files to be included in your packages. For the simplest use, you
can simply use the ``include_package_data`` keyword:
.. tab:: setup.cfg
.. code-block:: ini
[options]
include_package_data = True
.. tab:: setup.py [#setup.py]_
.. code-block:: python
setup(
# ...
include_package_data=True,
# ...
)
.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
.. code-block:: toml
[tool.setuptools]
include-package-data = true
# This is already the default behaviour if your are using
# pyproject.toml to configure your build.
# You can deactivate that with `include-package-data = false`
This tells setuptools to install any data files it finds in your packages.
The data files must be specified via the distutils' |MANIFEST.in|_ file
or automatically added by a :ref:`Revision Control System plugin
<Adding Support for Revision Control Systems>`.
For more details, see :doc:`datafiles`.
Development mode
================
``setuptools`` allows you to install a package without copying any files
to your interpreter directory (e.g. the ``site-packages`` directory).
This allows you to modify your source code and have the changes take
effect without you having to rebuild and reinstall.
Here's how to do it::
pip install --editable .
This creates a link file in your interpreter site package directory which
associate with your source code. For more information, see :doc:`development_mode`.
.. tip::
Prior to :ref:`pip v21.1 <pip:v21-1>`, a ``setup.py`` script was
required to be compatible with development mode. With late
versions of pip, ``setup.cfg``-only projects may be installed in this mode.
If you are experimenting with :doc:`configuration using <pyproject_config>`,
or have version of ``pip`` older than v21.1, you might need to keep a
``setup.py`` file in file in your repository if you want to use editable
installs (for the time being).
A simple script will suffice, for example:
.. code-block:: python
from setuptools import setup
setup()
You can still keep all the configuration in :doc:`setup.cfg </userguide/declarative_config>`
(or :doc:`pyproject.toml </userguide/pyproject_config>`).
Uploading your package to PyPI
==============================
After generating the distribution files, the next step would be to upload your
distribution so others can use it. This functionality is provided by
:pypi:`twine` and is documented in the :doc:`Python packaging tutorial
<PyPUG:tutorials/packaging-projects>`.
Transitioning from ``setup.py`` to ``setup.cfg``
================================================
To avoid executing arbitrary scripts and boilerplate code, we are transitioning
into a full-fledged ``setup.cfg`` to declare your package information instead
of running ``setup()``. This inevitably brings challenges due to a different
syntax. :doc:`Here </userguide/declarative_config>` we provide a quick guide to
understanding how ``setup.cfg`` is parsed by ``setuptools`` to ease the pain of
transition.
.. _packaging-resources:
Resources on Python packaging
=============================
Packaging in Python can be hard and is constantly evolving.
`Python Packaging User Guide <https://packaging.python.org>`_ has tutorials and
up-to-date references that can help you when it is time to distribute your work.
.. |MANIFEST.in| replace:: ``MANIFEST.in``
.. _MANIFEST.in: https://packaging.python.org/en/latest/guides/using-manifest-in/
----
.. rubric:: Notes
.. [#setup.py]
The ``setup.py`` file should be used only when custom scripting during the
build is necessary.
Examples are kept in this document to help people interested in maintaining or
contributing to existing packages that use ``setup.py``.
Note that you can still keep most of configuration declarative in
:doc:`setup.cfg <declarative_config>` or :doc:`pyproject.toml
<pyproject_config>` and use ``setup.py`` only for the parts not
supported in those files (e.g. C extensions).
.. [#experimental]
While the ``[build-system]`` table should always be specified in the
``pyproject.toml`` file, support for adding package metadata and build configuration
options via the ``[project]`` and ``[tool.setuptools]`` tables is still
experimental and might change in future releases.
See :doc:`/userguide/pyproject_config`.
|