aboutsummaryrefslogtreecommitdiff
path: root/docs/userguide/dependency_management.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/userguide/dependency_management.rst')
-rw-r--r--docs/userguide/dependency_management.rst443
1 files changed, 443 insertions, 0 deletions
diff --git a/docs/userguide/dependency_management.rst b/docs/userguide/dependency_management.rst
new file mode 100644
index 0000000..279f794
--- /dev/null
+++ b/docs/userguide/dependency_management.rst
@@ -0,0 +1,443 @@
+=====================================
+Dependencies Management in Setuptools
+=====================================
+
+There are three types of dependency styles offered by setuptools:
+1) build system requirement, 2) required dependency and 3) optional
+dependency.
+
+.. Note::
+ Packages that are added to dependency can be optionally specified with the
+ version by following `PEP 440 <https://www.python.org/dev/peps/pep-0440/>`_
+
+
+Build system requirement
+========================
+
+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 needs to actually
+do the packaging (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
+:doc:`quickstart` or (WIP)):
+
+.. code-block:: ini
+
+ [build-system]
+ requires = ["setuptools"]
+ #...
+
+.. 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 :doc:`guide on
+ deprecated practice (WIP) <../deprecated/index>`
+
+
+.. _Declaring Dependencies:
+
+Declaring required dependency
+=============================
+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
+finesse to it, let's start with a simple example.
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [options]
+ #...
+ install_requires =
+ docutils
+ BazSpam ==1.1
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ ...,
+ install_requires=[
+ 'docutils',
+ 'BazSpam ==1.1',
+ ],
+ )
+
+.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
+
+ .. code-block:: toml
+
+ [project]
+ # ...
+ dependencies = [
+ "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
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [options]
+ #...
+ install_requires =
+ enum34;python_version<'3.4'
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ ...,
+ install_requires=[
+ "enum34;python_version<'3.4'",
+ ],
+ )
+
+.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
+
+ .. code-block:: toml
+
+ [project]
+ # ...
+ dependencies = [
+ "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:
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [options]
+ #...
+ install_requires =
+ enum34;python_version<'3.4'
+ pywin32 >= 1.0;platform_system=='Windows'
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ ...,
+ install_requires=[
+ "enum34;python_version<'3.4'",
+ "pywin32 >= 1.0;platform_system=='Windows'",
+ ],
+ )
+
+.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
+
+ .. code-block:: toml
+
+ [project]
+ # ...
+ dependencies = [
+ "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/>`_.
+
+
+Dependencies that aren't in PyPI
+--------------------------------
+.. warning::
+ Dependency links support has been dropped by pip starting with version
+ 19.0 (released 2019-01-22).
+
+If your project depends on packages that don't exist on PyPI, you may still be
+able to depend on them, as long as they are available for download as:
+
+- an egg, in the standard distutils ``sdist`` format,
+- a single ``.py`` file, or
+- a VCS repository (Subversion, Mercurial, or Git).
+
+You just need to add some URLs to the ``dependency_links`` argument to
+``setup()``.
+
+The URLs must be either:
+
+1. direct download URLs,
+2. the URLs of web pages that contain direct download links, or
+3. the repository's URL
+
+In general, it's better to link to web pages, because it is usually less
+complex to update a web page than to release a new version of your project.
+You can also use a SourceForge ``showfiles.php`` link in the case where a
+package you depend on is distributed via SourceForge.
+
+If you depend on a package that's distributed as a single ``.py`` file, you
+must include an ``"#egg=project-version"`` suffix to the URL, to give a project
+name and version number. (Be sure to escape any dashes in the name or version
+by replacing them with underscores.) EasyInstall will recognize this suffix
+and automatically create a trivial ``setup.py`` to wrap the single ``.py`` file
+as an egg.
+
+In the case of a VCS checkout, you should also append ``#egg=project-version``
+in order to identify for what package that checkout should be used. You can
+append ``@REV`` to the URL's path (before the fragment) to specify a revision.
+Additionally, you can also force the VCS being used by prepending the URL with
+a certain prefix. Currently available are:
+
+- ``svn+URL`` for Subversion,
+- ``git+URL`` for Git, and
+- ``hg+URL`` for Mercurial
+
+A more complete example would be:
+
+ ``vcs+proto://host/path@revision#egg=project-version``
+
+Be careful with the version. It should match the one inside the project files.
+If you want to disregard the version, you have to omit it both in the
+``requires`` and in the URL's fragment.
+
+This will do a checkout (or a clone, in Git and Mercurial parlance) to a
+temporary folder and run ``setup.py bdist_egg``.
+
+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
+distributions, if the package's dependencies aren't already installed:
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [options]
+ #...
+ dependency_links = http://peak.telecommunity.com/snapshots/
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ ...,
+ dependency_links=[
+ "http://peak.telecommunity.com/snapshots/",
+ ],
+ )
+
+
+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:
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [metadata]
+ name = Package-A
+
+ [options.extras_require]
+ PDF = ReportLab>=1.2; RXP
+
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ name="Project-A",
+ ...,
+ extras_require={
+ "PDF": ["ReportLab>=1.2", "RXP"],
+ },
+ )
+
+.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
+
+ .. code-block:: toml
+
+ # ...
+ [project.optional-dependencies]
+ PDF = ["ReportLab>=1.2", "RXP"]
+
+The name ``PDF`` is an arbitrary identifier of such a list of dependencies, to
+which other components can refer and have them installed.
+
+A use case for this approach 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:
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [metadata]
+ name = Project-B
+ #...
+
+ [options]
+ #...
+ install_requires =
+ Project-A[PDF]
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ name="Project-B",
+ install_requires=["Project-A[PDF]"],
+ ...,
+ )
+
+.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
+
+ .. code-block:: toml
+
+ [project]
+ name = "Project-B"
+ # ...
+ dependencies = [
+ "Project-A[PDF]"
+ ]
+
+This will cause ReportLab to be installed along with project A, if project B is
+installed -- even if project A was already installed. In this way, a project
+can encapsulate groups of optional "downstream dependencies" under a feature
+name, so that packages that depend on it don't have to know what the downstream
+dependencies are. If a later version of Project A builds in PDF support and
+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
+not need to change, but the right packages will still be installed if needed.
+
+.. note::
+ Best practice: if a project ends up no longer needing any other packages to
+ support a feature, it should keep an empty requirements list for that feature
+ in its ``extras_require`` argument, so that packages depending on that feature
+ don't break (due to an invalid feature name).
+
+Historically ``setuptools`` also used to support extra dependencies in console
+scripts, for example:
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [metadata]
+ name = Project A
+ #...
+
+ [options]
+ #...
+ entry_points=
+ [console_scripts]
+ rst2pdf = project_a.tools.pdfgen [PDF]
+ rst2html = project_a.tools.htmlgen
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ name="Project-A",
+ ...,
+ entry_points={
+ "console_scripts": [
+ "rst2pdf = project_a.tools.pdfgen [PDF]",
+ "rst2html = project_a.tools.htmlgen",
+ ],
+ },
+ )
+
+This syntax indicates that the entry point (in this case a console script)
+is only valid when the PDF extra is installed. It is up to the installer
+to determine how to handle the situation where PDF was not indicated
+(e.g. omit the console script, provide a warning when attempting to load
+the entry point, assume the extras are present and let the implementation
+fail later).
+
+.. warning::
+ ``pip`` and other tools might not support this use case for extra
+ dependencies, therefore this practice is considered **deprecated**.
+ See :doc:`PyPUG:specifications/entry-points`.
+
+
+Python requirement
+==================
+In some cases, you might need to specify the minimum required python version.
+This can be configured as shown in the example below.
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [metadata]
+ name = Project-B
+ #...
+
+ [options]
+ #...
+ python_requires = >=3.6
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ name="Project-B",
+ python_requires=">=3.6",
+ ...,
+ )
+
+
+.. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_
+
+ .. code-block:: toml
+
+ [project]
+ name = "Project-B"
+ requires-python = ">=3.6"
+ # ...
+
+----
+
+.. rubric:: Notes
+
+.. [#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 (or be completely removed) in future releases.
+ See :doc:`/userguide/pyproject_config`.