diff --git a/source/discussions/install-requires-vs-requirements.rst b/source/discussions/install-requires-vs-requirements.rst index 99e1552b8..475e4610e 100644 --- a/source/discussions/install-requires-vs-requirements.rst +++ b/source/discussions/install-requires-vs-requirements.rst @@ -1,89 +1,102 @@ .. _`install_requires vs requirements files`: -====================================== -install_requires vs requirements files -====================================== +============================================ +Metadata dependencies vs. requirements files +============================================ +There are two main places where you will find list of "needed packages to +install", perhaps with version constraints, like ``requests`` or +``requests==2.31.0``. These are metadata dependencies, typically in a +:file:`pyproject.toml` (or :file:`setup.py`) file, and requirements files, often called +:file:`requirements.txt`. This page breaks down the differences. -install_requires ----------------- +Metadata dependencies +===================== -``install_requires`` is a :ref:`setuptools` :file:`setup.py` keyword that -should be used to specify what a project **minimally** needs to run correctly. -When the project is installed by :ref:`pip`, this is the specification that is -used to install its dependencies. +Packages can declare dependencies, i.e. other packages that they need to +function. The standard method to do so is to set the :ref:`dependencies key +` in the ``[project]`` section of a +:file:`pyproject.toml` file -- although other :term:`build backends ` +may use different methods. There can also be groups of optional dependencies, +also called "extras", which are typically specified in the +``optional-dependencies`` key of the ``[project]`` table. Both dependencies and +extras are ultimately written by the build backend to the package's distribution +metadata. On this page, we'll refer to these as "metadata dependencies". -For example, if the project requires A and B, your ``install_requires`` would be -like so: +When installing a package, installers like :ref:`pip` will automatically resolve +the metadata dependencies and install them. They should be used for packages that the project +**minimally** needs to run correctly. -:: +For example, suppose the project requires A and B. When using the ``[project]`` +table to declare metadata, the :file:`pyproject.toml` would be like so: - install_requires=[ - 'A', - 'B' - ] +.. code-block:: toml + + [project] + dependencies = ["A", "B"] Additionally, it's best practice to indicate any known lower or upper bounds. For example, it may be known, that your project requires at least v1 of 'A', and -v2 of 'B', so it would be like so: +v2 of 'B'. -:: +.. code-block:: toml - install_requires=[ - 'A>=1', - 'B>=2' - ] + [project] + dependencies = [ + "A >= 1", + "B >= 2" + ] It may also be known that project 'A' introduced a change in its v2 that breaks the compatibility of your project with v2 of 'A' and later, so it makes sense to not allow v2: -:: +.. code-block:: toml - install_requires=[ - 'A>=1,<2', - 'B>=2' - ] + [project] + dependencies = [ + "A >= 1, < 2", + "B >= 2" + ] -It is not considered best practice to use ``install_requires`` to pin -dependencies to specific versions, or to specify sub-dependencies -(i.e. dependencies of your dependencies). This is overly-restrictive, and +It is not considered best practice to use metadata dependencies to pin +dependencies to specific versions, or to specify transitive dependencies +(i.e. dependencies of your dependencies). This is overly restrictive, and prevents the user from gaining the benefit of dependency upgrades. -Lastly, it's important to understand that ``install_requires`` is a listing of -"Abstract" requirements, i.e just names and version restrictions that don't -determine where the dependencies will be fulfilled from (i.e. from what -index or source). The where (i.e. how they are to be made "Concrete") is to -be determined at install time using :ref:`pip` options. [1]_ +Lastly, it's important to understand that metadata dependencies are "abstract" +requirements, i.e. just names and version restrictions, but don't determine +where the dependencies will be fulfilled from (from what package index or +source). The where (i.e. how they are to be made "concrete") is to be determined +at install time, e.g. using :ref:`pip` options. [1]_ Requirements files ------------------- +================== -:ref:`Requirements Files ` described most simply, are +:ref:`Requirements Files `, described most simply, are just a list of :ref:`pip:pip install` arguments placed into a file. -Whereas ``install_requires`` defines the dependencies for a single project, -:ref:`Requirements Files ` are often used to define -the requirements for a complete Python environment. +Whereas metadata dependencies define the dependencies for a single +project, requirements files are often used to define the requirements +for a complete Python environment. -Whereas ``install_requires`` requirements are minimal, requirements files +Whereas metadata dependencies requirements are minimal, requirements files often contain an exhaustive listing of pinned versions for the purpose of achieving :ref:`repeatable installations ` of a complete environment. -Whereas ``install_requires`` requirements are "Abstract", i.e. not associated -with any particular index, requirements files often contain pip -options like ``--index-url`` or ``--find-links`` to make requirements -"Concrete", i.e. associated with a particular index or directory of -packages. [1]_ +Whereas metadata dependencies are "abstract", i.e. not associated with any +particular index, requirements files often contain pip options like +``--index-url`` or ``--find-links`` to make requirements "concrete", i.e. +associated with a particular index or directory of packages. [1]_ -Whereas ``install_requires`` metadata is automatically analyzed by pip during an +Whereas metadata dependencies are automatically analyzed by pip during an install, requirements files are not, and only are used when a user specifically -installs them using ``python -m pip install -r``. +installs them using :samp:`python -m pip install -r {requirement_file.txt}`. ---- -.. [1] For more on "Abstract" vs "Concrete" requirements, see +.. [1] For more on "abstract" vs "concrete" requirements, see https://caremad.io/posts/2013/07/setup-vs-requirement/. diff --git a/source/guides/distributing-packages-using-setuptools.rst b/source/guides/distributing-packages-using-setuptools.rst index f6e41075d..2125bb3b2 100644 --- a/source/guides/distributing-packages-using-setuptools.rst +++ b/source/guides/distributing-packages-using-setuptools.rst @@ -211,8 +211,6 @@ package, set ``py_modules`` to a list of the names of the modules (minus the minimally needs to run. When the project is installed by :ref:`pip`, this is the specification that is used to install its dependencies. -For more on using "install_requires" see :ref:`install_requires vs Requirements files`. - .. _`Package Data`: diff --git a/source/guides/writing-pyproject-toml.rst b/source/guides/writing-pyproject-toml.rst index 187a44d50..1c1dfb4ea 100644 --- a/source/guides/writing-pyproject-toml.rst +++ b/source/guides/writing-pyproject-toml.rst @@ -169,6 +169,8 @@ details. Dependencies and requirements ============================= +.. _writing-pyproject-toml-dependencies: + ``dependencies``/``optional-dependencies`` ------------------------------------------