mirror of
https://github.com/python/cpython.git
synced 2025-08-19 08:11:46 +00:00
[3.12] gh-125018: Add importlib.metadata semantic link targets (GH-125027) (#125048)
This allows direct intersphinx references to APIs via references
like `` :func:`importlib.metadata.version` ``.
---------
(cherry picked from commit cda3b5a576
)
Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) <wk.cvs.github@sydorenko.org.ua>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
This commit is contained in:
parent
36f9bbbdab
commit
fa32f007f0
2 changed files with 148 additions and 44 deletions
|
@ -100,6 +100,13 @@ You can also get a :ref:`distribution's version number <version>`, list its
|
||||||
:ref:`requirements`.
|
:ref:`requirements`.
|
||||||
|
|
||||||
|
|
||||||
|
.. exception:: PackageNotFoundError
|
||||||
|
|
||||||
|
Subclass of :class:`ModuleNotFoundError` raised by several functions in this
|
||||||
|
module when queried for a distribution package which is not installed in the
|
||||||
|
current Python environment.
|
||||||
|
|
||||||
|
|
||||||
Functional API
|
Functional API
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
@ -111,31 +118,53 @@ This package provides the following functionality via its public API.
|
||||||
Entry points
|
Entry points
|
||||||
------------
|
------------
|
||||||
|
|
||||||
The ``entry_points()`` function returns a collection of entry points.
|
.. function:: entry_points(**select_params)
|
||||||
Entry points are represented by ``EntryPoint`` instances;
|
|
||||||
each ``EntryPoint`` has a ``.name``, ``.group``, and ``.value`` attributes and
|
Returns a :class:`EntryPoints` instance describing entry points for the
|
||||||
a ``.load()`` method to resolve the value. There are also ``.module``,
|
current environment. Any given keyword parameters are passed to the
|
||||||
``.attr``, and ``.extras`` attributes for getting the components of the
|
:meth:`!~EntryPoints.select` method for comparison to the attributes of
|
||||||
``.value`` attribute.
|
the individual entry point definitions.
|
||||||
|
|
||||||
|
Note: it is not currently possible to query for entry points based on
|
||||||
|
their :attr:`!EntryPoint.dist` attribute (as different :class:`!Distribution`
|
||||||
|
instances do not currently compare equal, even if they have the same attributes)
|
||||||
|
|
||||||
|
.. class:: EntryPoints
|
||||||
|
|
||||||
|
Details of a collection of installed entry points.
|
||||||
|
|
||||||
|
Also provides a ``.groups`` attribute that reports all identifed entry
|
||||||
|
point groups, and a ``.names`` attribute that reports all identified entry
|
||||||
|
point names.
|
||||||
|
|
||||||
|
.. class:: EntryPoint
|
||||||
|
|
||||||
|
Details of an installed entry point.
|
||||||
|
|
||||||
|
Each :class:`!EntryPoint` instance has ``.name``, ``.group``, and ``.value``
|
||||||
|
attributes and a ``.load()`` method to resolve the value. There are also
|
||||||
|
``.module``, ``.attr``, and ``.extras`` attributes for getting the
|
||||||
|
components of the ``.value`` attribute, and ``.dist`` for obtaining
|
||||||
|
information regarding the distribution package that provides the entry point.
|
||||||
|
|
||||||
Query all entry points::
|
Query all entry points::
|
||||||
|
|
||||||
>>> eps = entry_points() # doctest: +SKIP
|
>>> eps = entry_points() # doctest: +SKIP
|
||||||
|
|
||||||
The ``entry_points()`` function returns an ``EntryPoints`` object,
|
The :func:`!entry_points` function returns a :class:`!EntryPoints` object,
|
||||||
a collection of all ``EntryPoint`` objects with ``names`` and ``groups``
|
a collection of all :class:`!EntryPoint` objects with ``names`` and ``groups``
|
||||||
attributes for convenience::
|
attributes for convenience::
|
||||||
|
|
||||||
>>> sorted(eps.groups) # doctest: +SKIP
|
>>> sorted(eps.groups) # doctest: +SKIP
|
||||||
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
|
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
|
||||||
|
|
||||||
``EntryPoints`` has a ``select`` method to select entry points
|
:class:`!EntryPoints` has a :meth:`!~EntryPoints.select` method to select entry points
|
||||||
matching specific properties. Select entry points in the
|
matching specific properties. Select entry points in the
|
||||||
``console_scripts`` group::
|
``console_scripts`` group::
|
||||||
|
|
||||||
>>> scripts = eps.select(group='console_scripts') # doctest: +SKIP
|
>>> scripts = eps.select(group='console_scripts') # doctest: +SKIP
|
||||||
|
|
||||||
Equivalently, since ``entry_points`` passes keyword arguments
|
Equivalently, since :func:`!entry_points` passes keyword arguments
|
||||||
through to select::
|
through to select::
|
||||||
|
|
||||||
>>> scripts = entry_points(group='console_scripts') # doctest: +SKIP
|
>>> scripts = entry_points(group='console_scripts') # doctest: +SKIP
|
||||||
|
@ -187,31 +216,41 @@ for compatibility options.
|
||||||
Distribution metadata
|
Distribution metadata
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Every `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_ includes some metadata,
|
.. function:: metadata(distribution_name)
|
||||||
which you can extract using the
|
|
||||||
``metadata()`` function::
|
Return the distribution metadata corresponding to the named
|
||||||
|
distribution package as a :class:`PackageMetadata` instance.
|
||||||
|
|
||||||
|
Raises :exc:`PackageNotFoundError` if the named distribution
|
||||||
|
package is not installed in the current Python environment.
|
||||||
|
|
||||||
|
.. class:: PackageMetadata
|
||||||
|
|
||||||
|
A concrete implementation of the
|
||||||
|
`PackageMetadata protocol <https://importlib-metadata.readthedocs.io/en/latest/api.html#importlib_metadata.PackageMetadata>`_.
|
||||||
|
|
||||||
|
In addition to providing the defined protocol methods and attributes, subscripting
|
||||||
|
the instance is equivalent to calling the :meth:`!~PackageMetadata.get` method.
|
||||||
|
|
||||||
|
Every `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_
|
||||||
|
includes some metadata, which you can extract using the :func:`!metadata` function::
|
||||||
|
|
||||||
>>> wheel_metadata = metadata('wheel') # doctest: +SKIP
|
>>> wheel_metadata = metadata('wheel') # doctest: +SKIP
|
||||||
|
|
||||||
The keys of the returned data structure, a ``PackageMetadata``,
|
The keys of the returned data structure name the metadata keywords, and
|
||||||
name the metadata keywords, and
|
|
||||||
the values are returned unparsed from the distribution metadata::
|
the values are returned unparsed from the distribution metadata::
|
||||||
|
|
||||||
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
|
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
|
||||||
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
||||||
|
|
||||||
``PackageMetadata`` also presents a ``json`` attribute that returns
|
:class:`PackageMetadata` also presents a :attr:`!~PackageMetadata.json` attribute that returns
|
||||||
all the metadata in a JSON-compatible form per :PEP:`566`::
|
all the metadata in a JSON-compatible form per :PEP:`566`::
|
||||||
|
|
||||||
>>> wheel_metadata.json['requires_python']
|
>>> wheel_metadata.json['requires_python']
|
||||||
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
||||||
|
|
||||||
.. note::
|
The full set of available metadata is not described here.
|
||||||
|
See the PyPA `Core metadata specification <https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata>`_ for additional details.
|
||||||
The actual type of the object returned by ``metadata()`` is an
|
|
||||||
implementation detail and should be accessed only through the interface
|
|
||||||
described by the
|
|
||||||
`PackageMetadata protocol <https://importlib-metadata.readthedocs.io/en/latest/api.html#importlib_metadata.PackageMetadata>`_.
|
|
||||||
|
|
||||||
.. versionchanged:: 3.10
|
.. versionchanged:: 3.10
|
||||||
The ``Description`` is now included in the metadata when presented
|
The ``Description`` is now included in the metadata when presented
|
||||||
|
@ -225,7 +264,15 @@ all the metadata in a JSON-compatible form per :PEP:`566`::
|
||||||
Distribution versions
|
Distribution versions
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
The ``version()`` function is the quickest way to get a
|
.. function:: version(distribution_name)
|
||||||
|
|
||||||
|
Return the installed distribution package version for the named
|
||||||
|
distribution package.
|
||||||
|
|
||||||
|
Raises :exc:`PackageNotFoundError` if the named distribution
|
||||||
|
package is not installed in the current Python environment.
|
||||||
|
|
||||||
|
The :func:`!version` function is the quickest way to get a
|
||||||
`Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_'s version
|
`Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_'s version
|
||||||
number, as a string::
|
number, as a string::
|
||||||
|
|
||||||
|
@ -238,12 +285,28 @@ number, as a string::
|
||||||
Distribution files
|
Distribution files
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
You can also get the full set of files contained within a distribution. The
|
.. function:: files(distribution_name)
|
||||||
``files()`` function takes a `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_ name
|
|
||||||
and returns all of the
|
Return the full set of files contained within the named
|
||||||
files installed by this distribution. Each file object returned is a
|
distribution package.
|
||||||
``PackagePath``, a :class:`pathlib.PurePath` derived object with additional ``dist``,
|
|
||||||
``size``, and ``hash`` properties as indicated by the metadata. For example::
|
Raises :exc:`PackageNotFoundError` if the named distribution
|
||||||
|
package is not installed in the current Python environment.
|
||||||
|
|
||||||
|
Returns :const:`None` if the distribution is found but the installation
|
||||||
|
database records reporting the files associated with the distribuion package
|
||||||
|
are missing.
|
||||||
|
|
||||||
|
.. class:: PackagePath
|
||||||
|
|
||||||
|
A :class:`pathlib.PurePath` derived object with additional ``dist``,
|
||||||
|
``size``, and ``hash`` properties corresponding to the distribution
|
||||||
|
package's installation metadata for that file.
|
||||||
|
|
||||||
|
The :func:`!files` function takes a
|
||||||
|
`Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_
|
||||||
|
name and returns all of the files installed by this distribution. Each file is reported
|
||||||
|
as a :class:`PackagePath` instance. For example::
|
||||||
|
|
||||||
>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP
|
>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP
|
||||||
>>> util # doctest: +SKIP
|
>>> util # doctest: +SKIP
|
||||||
|
@ -266,16 +329,16 @@ Once you have the file, you can also read its contents::
|
||||||
return s.encode('utf-8')
|
return s.encode('utf-8')
|
||||||
return s
|
return s
|
||||||
|
|
||||||
You can also use the ``locate`` method to get a the absolute path to the
|
You can also use the :meth:`!~PackagePath.locate` method to get the absolute
|
||||||
file::
|
path to the file::
|
||||||
|
|
||||||
>>> util.locate() # doctest: +SKIP
|
>>> util.locate() # doctest: +SKIP
|
||||||
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')
|
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')
|
||||||
|
|
||||||
In the case where the metadata file listing files
|
In the case where the metadata file listing files
|
||||||
(RECORD or SOURCES.txt) is missing, ``files()`` will
|
(``RECORD`` or ``SOURCES.txt``) is missing, :func:`!files` will
|
||||||
return ``None``. The caller may wish to wrap calls to
|
return :const:`None`. The caller may wish to wrap calls to
|
||||||
``files()`` in `always_iterable
|
:func:`!files` in `always_iterable
|
||||||
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable>`_
|
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable>`_
|
||||||
or otherwise guard against this condition if the target
|
or otherwise guard against this condition if the target
|
||||||
distribution is not known to have the metadata present.
|
distribution is not known to have the metadata present.
|
||||||
|
@ -285,8 +348,16 @@ distribution is not known to have the metadata present.
|
||||||
Distribution requirements
|
Distribution requirements
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
.. function:: requires(distribution_name)
|
||||||
|
|
||||||
|
Return the declared dependency specifiers for the named
|
||||||
|
distribution package.
|
||||||
|
|
||||||
|
Raises :exc:`PackageNotFoundError` if the named distribution
|
||||||
|
package is not installed in the current Python environment.
|
||||||
|
|
||||||
To get the full set of requirements for a `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_,
|
To get the full set of requirements for a `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_,
|
||||||
use the ``requires()``
|
use the :func:`!requires`
|
||||||
function::
|
function::
|
||||||
|
|
||||||
>>> requires('wheel') # doctest: +SKIP
|
>>> requires('wheel') # doctest: +SKIP
|
||||||
|
@ -299,6 +370,16 @@ function::
|
||||||
Mapping import to distribution packages
|
Mapping import to distribution packages
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
.. function:: packages_distributions()
|
||||||
|
|
||||||
|
Return a mapping from the top level module and import package
|
||||||
|
names found via :attr:`sys.meta_path` to the names of the distribution
|
||||||
|
packages (if any) that provide the corresponding files.
|
||||||
|
|
||||||
|
To allow for namespace packages (which may have members provided by
|
||||||
|
multiple distribution packages), each top level import name maps to a
|
||||||
|
list of distribution names rather than mapping directly to a single name.
|
||||||
|
|
||||||
A convenience method to resolve the `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_
|
A convenience method to resolve the `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_
|
||||||
name (or names, in the case of a namespace package)
|
name (or names, in the case of a namespace package)
|
||||||
that provide each importable top-level
|
that provide each importable top-level
|
||||||
|
@ -318,23 +399,42 @@ function is not reliable with such installs.
|
||||||
Distributions
|
Distributions
|
||||||
=============
|
=============
|
||||||
|
|
||||||
While the above API is the most common and convenient usage, you can get all
|
.. function:: distribution(distribution_name)
|
||||||
of that information from the ``Distribution`` class. A ``Distribution`` is an
|
|
||||||
abstract object that represents the metadata for
|
Return a :class:`Distribution` instance describing the named
|
||||||
a Python `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_. You can
|
distribution package.
|
||||||
get the ``Distribution`` instance::
|
|
||||||
|
Raises :exc:`PackageNotFoundError` if the named distribution
|
||||||
|
package is not installed in the current Python environment.
|
||||||
|
|
||||||
|
.. class:: Distribution
|
||||||
|
|
||||||
|
Details of an installed distribution package.
|
||||||
|
|
||||||
|
Note: different :class:`!Distribution` instances do not currently compare
|
||||||
|
equal, even if they relate to the same installed distribution and
|
||||||
|
accordingly have the same attributes.
|
||||||
|
|
||||||
|
While the module level API described above is the most common and convenient usage,
|
||||||
|
you can get all of that information from the :class:`!Distribution` class.
|
||||||
|
:class:`!Distribution` is an abstract object that represents the metadata for
|
||||||
|
a Python `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_.
|
||||||
|
You can get the concreate :class:`!Distribution` subclass instance for an installed
|
||||||
|
distribution package by calling the :func:`distribution` function::
|
||||||
|
|
||||||
>>> from importlib.metadata import distribution # doctest: +SKIP
|
>>> from importlib.metadata import distribution # doctest: +SKIP
|
||||||
>>> dist = distribution('wheel') # doctest: +SKIP
|
>>> dist = distribution('wheel') # doctest: +SKIP
|
||||||
|
>>> type(dist) # doctest: +SKIP
|
||||||
|
<class 'importlib.metadata.PathDistribution'>
|
||||||
|
|
||||||
Thus, an alternative way to get the version number is through the
|
Thus, an alternative way to get the version number is through the
|
||||||
``Distribution`` instance::
|
:class:`!Distribution` instance::
|
||||||
|
|
||||||
>>> dist.version # doctest: +SKIP
|
>>> dist.version # doctest: +SKIP
|
||||||
'0.32.3'
|
'0.32.3'
|
||||||
|
|
||||||
There are all kinds of additional metadata available on the ``Distribution``
|
There are all kinds of additional metadata available on :class:`!Distribution`
|
||||||
instance::
|
instances::
|
||||||
|
|
||||||
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
|
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
|
||||||
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
|
||||||
|
@ -342,7 +442,7 @@ instance::
|
||||||
'MIT'
|
'MIT'
|
||||||
|
|
||||||
The full set of available metadata is not described here.
|
The full set of available metadata is not described here.
|
||||||
See the `Core metadata specifications <https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata>`_ for additional details.
|
See the PyPA `Core metadata specification <https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata>`_ for additional details.
|
||||||
|
|
||||||
|
|
||||||
Distribution Discovery
|
Distribution Discovery
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
The :mod:`importlib.metadata` documentation now includes semantic
|
||||||
|
cross-reference targets for the significant documented APIs. This means
|
||||||
|
intersphinx references like :func:`importlib.metadata.version` will
|
||||||
|
now work as expected.
|
Loading…
Add table
Add a link
Reference in a new issue