Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
setuptools
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jérome Perrin
setuptools
Commits
f2564d7d
Commit
f2564d7d
authored
Aug 15, 2020
by
Jason R. Coombs
Committed by
GitHub
Aug 15, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2157 from alvyjudy/dependency
step 7 on 2093: dependency management guide ready
parents
a5b144e3
dee83be1
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
186 additions
and
129 deletions
+186
-129
docs/userguide/dependency_management.txt
docs/userguide/dependency_management.txt
+186
-129
No files found.
docs/userguide/dependency_management.txt
View file @
f2564d7d
...
@@ -2,71 +2,127 @@
...
@@ -2,71 +2,127 @@
Dependencies Management in Setuptools
Dependencies Management in Setuptools
=====================================
=====================================
Declaring Dependencies
There are three types of dependency styles offered by setuptools:
======================
1) build system requirement, required dependency and 3) optional
dependency.
``setuptools`` supports automatically installing dependencies when a package is
.. Note::
installed, and including information about dependencies in Python Eggs (so that
Packages that are added to dependency can be optionally specified with the
package management tools like pip can use the information).
version by following `PEP 440 <https://www.python.org/dev/peps/pep-0440/>`_
``setuptools`` and ``pkg_resources`` use a common syntax for specifying a
project's required dependencies. This syntax consists of a project's PyPI
name, optionally followed by a comma-separated list of "extras" in square
brackets, optionally followed by a comma-separated list of version
specifiers. A version specifier is one of the operators ``<``, ``>``, ``<=``,
``>=``, ``==`` or ``!=``, followed by a version identifier. Tokens may be
separated by whitespace, but any whitespace or nonstandard characters within a
project name or version identifier must be replaced with ``-``.
Version specifiers for a given project are internally sorted into ascending
.. contents::
version order, and used to establish what ranges of versions are acceptable.
Adjacent redundant conditions are also consolidated (e.g. ``">1, >2"`` becomes
``">2"``, and ``"<2,<3"`` becomes ``"<2"``). ``"!="`` versions are excised from
the ranges they fall within. A project's version is then checked for
membership in the resulting ranges. (Note that providing conflicting conditions
for the same version (e.g. "<2,>=2" or "==2,!=2") is meaningless and may
therefore produce bizarre results.)
Here are some example requirement specifiers::
Build system requirement
========================
docutils >= 0.3
Package requirement
-------------------
After organizing all the scripts and files and getting ready for packaging,
there needs to be a way to tell Python what programs it need to actually
do the packgaging (in our case, ``setuptools`` of course). Usually,
you also need the ``wheel`` package as well since it is recommended that you
upload a ``.whl`` file to PyPI alongside your ``.tar.gz`` file. Unlike the
other two types of dependency keyword, this one is specified in your
``pyproject.toml`` file (if you have forgot what this is, go to
:ref:`quickstart` or (WIP)):
# comment lines and \ continuations are allowed in requirement strings
.. code-block:: ini
BazSpam ==1.1, ==1.2, ==1.3, ==1.4, ==1.5, \
==1.6, ==1.7 # and so are line-end comments
PEAK[FastCGI, reST]>=0.5a4
[build-system]
requires = ["setuptools", "wheel"]
#...
setuptools==0.5a7
.. note::
This used to be accomplished with the ``setup_requires`` keyword but is
now considered deprecated in favor of the PEP 517 style described above.
To peek into how this legacy keyword is used, consult our :ref:`guide on
deprecated practice (WIP)`
The simplest way to include requirement specifiers is to use the
``install_requires`` argument to ``setup()``. It takes a string or list of
strings containing requirement specifiers. If you include more than one
requirement in a string, each requirement must begin on a new line.
This has three effects:
1. When your project is installed, either by using pip, ``setup.py install``,
Declaring required dependency
or ``setup.py develop``, all of the dependencies not already installed will
=============================
be located (via PyPI), downloaded, built (if necessary), and installed.
This is where a package declares its core dependencies, without which it won't
be able to run. ``setuptools`` support automatically download and install
these dependencies when the package is installed. Although there is more
finess to it, let's start with a simple example.
2. Any scripts in your project will be installed with wrappers that verify
.. code-block:: ini
the availability of the specified dependencies at runtime, and ensure that
the correct versions are added to ``sys.path`` (e.g. if multiple versions
have been installed).
3. Python Egg distributions will include a metadata file listing the
[options]
dependencies.
#...
install_requires =
docutils
BazSpam ==1.1
.. code-block:: python
setup(
#...,
install_requires = [
'docutils',
'BazSpam ==1.1'
]
)
When your project is installed (e.g. using pip), all of the dependencies not
already installed will be located (via PyPI), downloaded, built (if necessary),
and installed and 2) Any scripts in your project will be installed with wrappers
that verify the availability of the specified dependencies at runtime.
Platform specific dependencies
------------------------------
Setuptools offer the capability to evaluate certain conditions before blindly
installing everything listed in ``install_requires``. This is great for platform
specific dependencies. For example, the ``enum`` package was added in Python
3.4, therefore, package that depends on it can elect to install it only when
the Python version is older than 3.4. To accomplish this
.. code-block:: ini
[options]
#...
install_requires =
enum34;python_version<'3.4'
.. code-block:: python
setup(
#...
install_requires=[
"enum34;python_version<'3.4'",]
)
Similarly, if you also wish to declare ``pywin32`` with a minimal version of 1.0
and only install it if the user is using a Windows operating system:
.. code-block:: ini
[options]
#...
install_requires =
enum34;python_version<'3.4'
pywin32 >= 1.0;platform_system=='Windows'
.. code-block:: python
setup(
#...
install_requires=[
"enum34;python_version<'3.4'",
"pywin32 >= 1.0;platform_system=='Windows'"
]
)
The environmental markers that may be used for testing platform types are
detailed in `PEP 508 <https://www.python.org/dev/peps/pep-0508/>`_.
Note, by the way, that if you declare your dependencies in ``setup.py``, you do
*not* need to use the ``require()`` function in your scripts or modules, as
long as you either install the project or use ``setup.py develop`` to do
development work on it. (See `"Development Mode"`_ below for more details on
using ``setup.py develop``.)
Dependencies that aren't in PyPI
Dependencies that aren't in PyPI
--------------------------------
--------------------------------
.. warning::
.. warning::
Dependency links support has been dropped by pip starting with version
Dependency links support has been dropped by pip starting with version
19.0 (released 2019-01-22).
19.0 (released 2019-01-22).
...
@@ -122,69 +178,108 @@ temporary folder and run ``setup.py bdist_egg``.
...
@@ -122,69 +178,108 @@ temporary folder and run ``setup.py bdist_egg``.
The ``dependency_links`` option takes the form of a list of URL strings. For
The ``dependency_links`` option takes the form of a list of URL strings. For
example, this will cause a search of the specified page for eggs or source
example, this will cause a search of the specified page for eggs or source
distributions, if the package's dependencies aren't already installed::
distributions, if the package's dependencies aren't already installed:
.. code-block:: ini
[options]
#...
dependency_links = http://peak.telecommunity.com/snapshots/
.. code-block:: python
setup(
setup(
...
#
...
dependency_links=[
dependency_links=[
"http://peak.telecommunity.com/snapshots/"
"http://peak.telecommunity.com/snapshots/"
],
],
)
)
.. _Declaring Extras:
Optional dependencies
=====================
Setuptools allows you to declare dependencies that only get installed under
specific circumstances. These dependencies are specified with ``extras_require``
keyword and are only installed if another package depends on it (either
directly or indirectly) This makes it convenient to declare dependencies for
ancillary functions such as "tests" and "docs".
.. note::
``tests_require`` is now deprecated
For example, Package-A offers optional PDF support and requires two other
dependencies for it to work:
.. code-block:: ini
Declaring "Extras" (optional features with their own dependencies)
[metadata]
------------------------------------------------------------------
name = Package-A
Sometimes a project has "recommended" dependencies, that are not required for
[options.extras_require]
all uses of the project. For example, a project might offer optional PDF
PDF = ReportLab>=1.2; RXP
output if ReportLab is installed, and reStructuredText support if docutils is
installed. These optional features are called "extras", and setuptools allows
you to define their requirements as well. In this way, other projects that
require these optional features can force the additional requirements to be
installed, by naming the desired extras in their ``install_requires``.
For example, let's say that Project A offers optional PDF and reST support::
.. code-block:: python
setup(
setup(
name="Project-A",
name="Project-A",
...
#
...
extras_require={
extras_require={
"PDF": ["ReportLab>=1.2", "RXP"],
"PDF": ["ReportLab>=1.2", "RXP"],
"reST": ["docutils>=0.3"],
}
}
)
)
As you can see, the ``extras_require`` argument takes a dictionary mapping
The name ``PDF`` is an arbitary identifier of such a list of dependencies, to
names of "extra" features, to strings or lists of strings describing those
which other components can refer and have them installed. There are two common
features' requirements. These requirements will *not* be automatically
use cases.
installed unless another package depends on them (directly or indirectly) by
including the desired "extras" in square brackets after the associated project
First is the console_scripts entry point:
name. (Or if the extras were listed in a requirement spec on the "pip install"
command line.)
.. code-block:: ini
[metadata]
name = Project A
#...
Extras can be used by a project's `entry points`_ to specify dynamic
[options]
dependencies. For example, if Project A includes a "rst2pdf" script, it might
#...
declare it like this, so that the "PDF" requirements are only resolved if the
entry_points=
"rst2pdf" script is run::
[console_scripts]
rst2pdf = project_a.tools.pdfgen [PDF]
rst2html = project_a.tools.htmlgen
.. code-block:: python
setup(
setup(
name
="Project-A",
name
= "Project-A"
...
#...,
entry_points={
entry_points={
"console_scripts": [
"console_scripts": [
"rst2pdf = project_a.tools.pdfgen [PDF]",
"rst2pdf = project_a.tools.pdfgen [PDF]",
"rst2html = project_a.tools.htmlgen",
"rst2html = project_a.tools.htmlgen",
# more script entry points ...
],
],
}
}
)
)
Projects can also use another project's extras when specifying dependencies.
When the script ``rst2pdf`` is run, it will trigger the installation of
For example, if project B needs "project A" with PDF support installed, it
the two dependencies ``PDF`` maps to.
might declare the dependency like this::
The second use case is that other package can use this "extra" for their
own dependencies. For example, if "Project-B" needs "project A" with PDF support
installed, it might declare the dependency like this::
.. code-block:: ini
[metadata]
name = Project-B
#...
[options]
#...
install_requires =
Project-A[PDF]
.. code-block:: python
setup(
setup(
name="Project-B",
name="Project-B",
...
@@ -201,55 +296,17 @@ no longer needs ReportLab, or if it ends up needing other dependencies besides
...
@@ -201,55 +296,17 @@ no longer needs ReportLab, or if it ends up needing other dependencies besides
ReportLab in order to provide PDF support, Project B's setup information does
ReportLab in order to provide PDF support, Project B's setup information does
not need to change, but the right packages will still be installed if needed.
not need to change, but the right packages will still be installed if needed.
Note, by the way, that if a project ends up not needing any other packages to
.. note::
support a feature, it should keep an empty requirements list for that feature
Best practice: if a project ends up not needing any other packages to
in its ``extras_require`` argument, so that packages depending on that feature
support a feature, it should keep an empty requirements list for that feature
don't break (due to an invalid feature name). For example, if Project A above
in its ``extras_require`` argument, so that packages depending on that feature
builds in PDF support and no longer needs ReportLab, it could change its
don't break (due to an invalid feature name).
setup to this::
setup(
name="Project-A",
...
extras_require={
"PDF": [],
"reST": ["docutils>=0.3"],
}
)
so that Package B doesn't have to remove the ``[PDF]`` from its requirement
specifier.
.. _Platform Specific Dependencies:
Declaring platform specific dependencies
----------------------------------------
Sometimes a project might require a dependency to run on a specific platform.
Python requirement
This could to a package that back ports a module so that it can be used in
==================
older python versions. Or it could be a package that is required to run on a
In some cases, you might need to specify the minimum required python version.
specific operating system. This will allow a project to work on multiple
This is handled with the ``python_requires`` keyword supplied to ``setup.cfg``
different platforms without installing dependencies that are not required for
or ``setup.py``.
a platform that is installing the project.
For example, here is a project that uses the ``enum`` module and ``pywin32``::
setup(
name="Project",
...
install_requires=[
"enum34;python_version<'3.4'",
"pywin32 >= 1.0;platform_system=='Windows'"
]
)
Since the ``enum`` module was added in Python 3.4, it should only be installed
if the python version is earlier. Since ``pywin32`` will only be used on
windows, it should only be installed when the operating system is Windows.
Specifying version requirements for the dependencies is supported as normal.
The environmental markers that may be used for testing platform types are
detailed in `PEP 508`_.
.. _PEP 508: https://www.python.org/dev/peps/pep-0508/
Example WIP
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment