1=====================================
2Dependencies Management in Setuptools
3=====================================
4
5There are three types of dependency styles offered by setuptools:
61) build system requirement, 2) required dependency and 3) optional
7dependency.
8
9.. Note::
10    Packages that are added to dependency can be optionally specified with the
11    version by following `PEP 440 <https://www.python.org/dev/peps/pep-0440/>`_
12
13
14Build system requirement
15========================
16
17Package requirement
18-------------------
19After organizing all the scripts and files and getting ready for packaging,
20there needs to be a way to tell Python what programs it needs to actually
21do the packaging (in our case, ``setuptools`` of course). Usually,
22you also need the ``wheel`` package as well since it is recommended that you
23upload a ``.whl`` file to PyPI alongside your ``.tar.gz`` file. Unlike the
24other two types of dependency keyword, this one is specified in your
25``pyproject.toml`` file (if you have forgot what this is, go to
26:doc:`quickstart` or (WIP)):
27
28.. code-block:: ini
29
30    [build-system]
31    requires = ["setuptools"]
32    #...
33
34.. note::
35    This used to be accomplished with the ``setup_requires`` keyword but is
36    now considered deprecated in favor of the PEP 517 style described above.
37    To peek into how this legacy keyword is used, consult our :doc:`guide on
38    deprecated practice (WIP) <../deprecated/index>`
39
40
41.. _Declaring Dependencies:
42
43Declaring required dependency
44=============================
45This is where a package declares its core dependencies, without which it won't
46be able to run. ``setuptools`` support automatically download and install
47these dependencies when the package is installed. Although there is more
48finesse to it, let's start with a simple example.
49
50.. tab:: setup.cfg
51
52    .. code-block:: ini
53
54        [options]
55        #...
56        install_requires =
57            docutils
58            BazSpam ==1.1
59
60.. tab:: setup.py
61
62    .. code-block:: python
63
64        setup(
65            ...,
66            install_requires=[
67                'docutils',
68                'BazSpam ==1.1',
69            ],
70        )
71
72.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
73
74    .. code-block:: toml
75
76        [project]
77        # ...
78        dependencies = [
79            "docutils",
80            "BazSpam == 1.1",
81        ]
82        # ...
83
84
85When your project is installed (e.g. using pip), all of the dependencies not
86already installed will be located (via PyPI), downloaded, built (if necessary),
87and installed and 2) Any scripts in your project will be installed with wrappers
88that verify the availability of the specified dependencies at runtime.
89
90
91Platform specific dependencies
92------------------------------
93Setuptools offer the capability to evaluate certain conditions before blindly
94installing everything listed in ``install_requires``. This is great for platform
95specific dependencies. For example, the ``enum`` package was added in Python
963.4, therefore, package that depends on it can elect to install it only when
97the Python version is older than 3.4. To accomplish this
98
99.. tab:: setup.cfg
100
101    .. code-block:: ini
102
103        [options]
104        #...
105        install_requires =
106            enum34;python_version<'3.4'
107
108.. tab:: setup.py
109
110    .. code-block:: python
111
112        setup(
113            ...,
114            install_requires=[
115                "enum34;python_version<'3.4'",
116            ],
117        )
118
119.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
120
121    .. code-block:: toml
122
123        [project]
124        # ...
125        dependencies = [
126            "enum34; python_version<'3.4'",
127        ]
128        # ...
129
130Similarly, if you also wish to declare ``pywin32`` with a minimal version of 1.0
131and only install it if the user is using a Windows operating system:
132
133.. tab:: setup.cfg
134
135    .. code-block:: ini
136
137        [options]
138        #...
139        install_requires =
140            enum34;python_version<'3.4'
141            pywin32 >= 1.0;platform_system=='Windows'
142
143.. tab:: setup.py
144
145    .. code-block:: python
146
147        setup(
148            ...,
149            install_requires=[
150                "enum34;python_version<'3.4'",
151                "pywin32 >= 1.0;platform_system=='Windows'",
152            ],
153        )
154
155.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
156
157    .. code-block:: toml
158
159        [project]
160        # ...
161        dependencies = [
162            "enum34; python_version<'3.4'",
163            "pywin32 >= 1.0; platform_system=='Windows'",
164        ]
165        # ...
166
167The environmental markers that may be used for testing platform types are
168detailed in `PEP 508 <https://www.python.org/dev/peps/pep-0508/>`_.
169
170
171Dependencies that aren't in PyPI
172--------------------------------
173.. warning::
174    Dependency links support has been dropped by pip starting with version
175    19.0 (released 2019-01-22).
176
177If your project depends on packages that don't exist on PyPI, you may still be
178able to depend on them, as long as they are available for download as:
179
180- an egg, in the standard distutils ``sdist`` format,
181- a single ``.py`` file, or
182- a VCS repository (Subversion, Mercurial, or Git).
183
184You just need to add some URLs to the ``dependency_links`` argument to
185``setup()``.
186
187The URLs must be either:
188
1891. direct download URLs,
1902. the URLs of web pages that contain direct download links, or
1913. the repository's URL
192
193In general, it's better to link to web pages, because it is usually less
194complex to update a web page than to release a new version of your project.
195You can also use a SourceForge ``showfiles.php`` link in the case where a
196package you depend on is distributed via SourceForge.
197
198If you depend on a package that's distributed as a single ``.py`` file, you
199must include an ``"#egg=project-version"`` suffix to the URL, to give a project
200name and version number.  (Be sure to escape any dashes in the name or version
201by replacing them with underscores.)  EasyInstall will recognize this suffix
202and automatically create a trivial ``setup.py`` to wrap the single ``.py`` file
203as an egg.
204
205In the case of a VCS checkout, you should also append ``#egg=project-version``
206in order to identify for what package that checkout should be used. You can
207append ``@REV`` to the URL's path (before the fragment) to specify a revision.
208Additionally, you can also force the VCS being used by prepending the URL with
209a certain prefix. Currently available are:
210
211-  ``svn+URL`` for Subversion,
212-  ``git+URL`` for Git, and
213-  ``hg+URL`` for Mercurial
214
215A more complete example would be:
216
217    ``vcs+proto://host/path@revision#egg=project-version``
218
219Be careful with the version. It should match the one inside the project files.
220If you want to disregard the version, you have to omit it both in the
221``requires`` and in the URL's fragment.
222
223This will do a checkout (or a clone, in Git and Mercurial parlance) to a
224temporary folder and run ``setup.py bdist_egg``.
225
226The ``dependency_links`` option takes the form of a list of URL strings.  For
227example, this will cause a search of the specified page for eggs or source
228distributions, if the package's dependencies aren't already installed:
229
230.. tab:: setup.cfg
231
232    .. code-block:: ini
233
234        [options]
235        #...
236        dependency_links = http://peak.telecommunity.com/snapshots/
237
238.. tab:: setup.py
239
240    .. code-block:: python
241
242        setup(
243            ...,
244            dependency_links=[
245                "http://peak.telecommunity.com/snapshots/",
246            ],
247        )
248
249
250Optional dependencies
251=====================
252Setuptools allows you to declare dependencies that only get installed under
253specific circumstances. These dependencies are specified with ``extras_require``
254keyword and are only installed if another package depends on it (either
255directly or indirectly) This makes it convenient to declare dependencies for
256ancillary functions such as "tests" and "docs".
257
258.. note::
259    ``tests_require`` is now deprecated
260
261For example, Package-A offers optional PDF support and requires two other
262dependencies for it to work:
263
264.. tab:: setup.cfg
265
266    .. code-block:: ini
267
268        [metadata]
269        name = Package-A
270
271        [options.extras_require]
272        PDF = ReportLab>=1.2; RXP
273
274
275.. tab:: setup.py
276
277    .. code-block:: python
278
279        setup(
280            name="Project-A",
281            ...,
282            extras_require={
283                "PDF": ["ReportLab>=1.2", "RXP"],
284            },
285        )
286
287.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
288
289    .. code-block:: toml
290
291        # ...
292        [project.optional-dependencies]
293        PDF = ["ReportLab>=1.2", "RXP"]
294
295The name ``PDF`` is an arbitrary identifier of such a list of dependencies, to
296which other components can refer and have them installed.
297
298A use case for this approach is that other package can use this "extra" for their
299own dependencies. For example, if "Project-B" needs "project A" with PDF support
300installed, it might declare the dependency like this:
301
302.. tab:: setup.cfg
303
304    .. code-block:: ini
305
306        [metadata]
307        name = Project-B
308        #...
309
310        [options]
311        #...
312        install_requires =
313            Project-A[PDF]
314
315.. tab:: setup.py
316
317    .. code-block:: python
318
319        setup(
320            name="Project-B",
321            install_requires=["Project-A[PDF]"],
322            ...,
323        )
324
325.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
326
327    .. code-block:: toml
328
329        [project]
330        name = "Project-B"
331        # ...
332        dependencies = [
333            "Project-A[PDF]"
334        ]
335
336This will cause ReportLab to be installed along with project A, if project B is
337installed -- even if project A was already installed.  In this way, a project
338can encapsulate groups of optional "downstream dependencies" under a feature
339name, so that packages that depend on it don't have to know what the downstream
340dependencies are.  If a later version of Project A builds in PDF support and
341no longer needs ReportLab, or if it ends up needing other dependencies besides
342ReportLab in order to provide PDF support, Project B's setup information does
343not need to change, but the right packages will still be installed if needed.
344
345.. note::
346    Best practice: if a project ends up no longer needing any other packages to
347    support a feature, it should keep an empty requirements list for that feature
348    in its ``extras_require`` argument, so that packages depending on that feature
349    don't break (due to an invalid feature name).
350
351Historically ``setuptools`` also used to support extra dependencies in console
352scripts, for example:
353
354.. tab:: setup.cfg
355
356    .. code-block:: ini
357
358        [metadata]
359        name = Project A
360        #...
361
362        [options]
363        #...
364        entry_points=
365            [console_scripts]
366            rst2pdf = project_a.tools.pdfgen [PDF]
367            rst2html = project_a.tools.htmlgen
368
369.. tab:: setup.py
370
371    .. code-block:: python
372
373        setup(
374            name="Project-A",
375            ...,
376            entry_points={
377                "console_scripts": [
378                    "rst2pdf = project_a.tools.pdfgen [PDF]",
379                    "rst2html = project_a.tools.htmlgen",
380                ],
381            },
382        )
383
384This syntax indicates that the entry point (in this case a console script)
385is only valid when the PDF extra is installed. It is up to the installer
386to determine how to handle the situation where PDF was not indicated
387(e.g. omit the console script, provide a warning when attempting to load
388the entry point, assume the extras are present and let the implementation
389fail later).
390
391.. warning::
392   ``pip`` and other tools might not support this use case for extra
393   dependencies, therefore this practice is considered **deprecated**.
394   See :doc:`PyPUG:specifications/entry-points`.
395
396
397Python requirement
398==================
399In some cases, you might need to specify the minimum required python version.
400This can be configured as shown in the example below.
401
402.. tab:: setup.cfg
403
404    .. code-block:: ini
405
406        [metadata]
407        name = Project-B
408        #...
409
410        [options]
411        #...
412        python_requires = >=3.6
413
414.. tab:: setup.py
415
416    .. code-block:: python
417
418        setup(
419            name="Project-B",
420            python_requires=">=3.6",
421            ...,
422        )
423
424
425.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
426
427    .. code-block:: toml
428
429        [project]
430        name = "Project-B"
431        requires-python = ">=3.6"
432        # ...
433
434----
435
436.. rubric:: Notes
437
438.. [#experimental]
439   While the ``[build-system]`` table should always be specified in the
440   ``pyproject.toml`` file, support for adding package metadata and build configuration
441   options via the ``[project]`` and ``[tool.setuptools]`` tables is still
442   experimental and might change (or be completely removed) in future releases.
443   See :doc:`/userguide/pyproject_config`.
444