Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 102 additions & 40 deletions Doc/library/importlib.metadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ Entry points
:meth:`!select` method for comparison to the attributes of
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`
Note: to query for entry points based on :attr:`!EntryPoint.dist` attribute,
use :meth:`Distribution.entry_points` instead (as different :class:`Distribution`
instances do not currently compare equal, even if they have the same attributes)

.. class:: EntryPoints
Expand Down Expand Up @@ -291,7 +291,7 @@ Distribution files
.. function:: files(distribution_name)

Return the full set of files contained within the named
distribution package.
distribution package as :class:`PackagePath` instances.

Raises :exc:`PackageNotFoundError` if the named distribution
package is not installed in the current Python environment.
Expand All @@ -304,12 +304,22 @@ Distribution files

A :class:`pathlib.PurePath` derived object with additional ``dist``,
``size``, and ``hash`` properties corresponding to the distribution
package's installation metadata for that file.
package's installation metadata for that file, also:

.. method:: locate()

If possible, return the concrete :class:`SimplePath` allowing to access data,
or raise a :exc:`NotImplementedError` otherwise.

.. class:: SimplePath

A protocol representing a minimal subset of :class:`pathlib.Path` that allows to
check if it ``exists()``, to traverse using ``joinpath()`` and ``parent``,
and to retrieve data using ``read_text()`` and ``read_bytes()``.

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::
name and returns all of the files installed by this distribution. For example::

>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP
>>> util # doctest: +SKIP
Expand Down Expand Up @@ -402,6 +412,18 @@ function is not reliable with such installs.
Distributions
=============

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 concrete :class:`!Distribution` subclass instance for an installed
distribution package by calling the :func:`distribution` function::

>>> from importlib.metadata import distribution # doctest: +SKIP
>>> dist = distribution('wheel') # doctest: +SKIP
>>> type(dist) # doctest: +SKIP
<class 'importlib.metadata.PathDistribution'>

.. function:: distribution(distribution_name)

Return a :class:`Distribution` instance describing the named
Expand All @@ -410,6 +432,14 @@ Distributions
Raises :exc:`PackageNotFoundError` if the named distribution
package is not installed in the current Python environment.

Thus, an alternative way to get e.g. the version number is through the
:attr:`Distribution.version` attribute::

>>> dist.version # doctest: +SKIP
'0.32.3'

The same applies for :func:`entry_points` and :func:`files`.

.. class:: Distribution

Details of an installed distribution package.
Expand All @@ -418,53 +448,85 @@ Distributions
equal, even if they relate to the same installed distribution and
accordingly have the same attributes.

.. method:: discover(cls, *, context=None, **kwargs)
.. staticmethod:: at(path)
.. classmethod:: from_name(name)

Return a :class:`!Distribution` instance at the given path or
with the given name.

Returns an iterable of :class:`Distribution` instances for all packages.
.. classmethod:: discover(*, context=None, **kwargs)

Returns an iterable of :class:`!Distribution` instances for all packages
(see distribution-discovery_).

The optional argument *context* is a :class:`DistributionFinder.Context`
instance, used to modify the search for distributions. Alternatively,
*kwargs* may contain keyword arguments for constructing a new
:class:`!DistributionFinder.Context`.

.. attribute:: metadata
:type: PackageMetadata

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 concrete :class:`!Distribution` subclass instance for an installed
distribution package by calling the :func:`distribution` function::
There are all kinds of additional metadata available on :class:`!Distribution`
instances as a :class:`PackageMetadata` instance::

>>> from importlib.metadata import distribution # doctest: +SKIP
>>> dist = distribution('wheel') # doctest: +SKIP
>>> type(dist) # doctest: +SKIP
<class 'importlib.metadata.PathDistribution'>
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> dist.metadata['License'] # doctest: +SKIP
'MIT'

Thus, an alternative way to get the version number is through the
:class:`!Distribution` instance::
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.

>>> dist.version # doctest: +SKIP
'0.32.3'
.. attribute:: name
:type: str
.. attribute:: requires
:type: list[str]
.. attribute:: version
:type: str

There are all kinds of additional metadata available on :class:`!Distribution`
instances::
A few metadata fields are also available as shortcut properties.

>>> dist.metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> dist.metadata['License'] # doctest: +SKIP
'MIT'
.. versionadded:: 3.10

For editable packages, an ``origin`` property may present :pep:`610`
metadata::
The ``name`` shortcut was added.

>>> dist.origin.url
'file:///path/to/wheel-0.32.3.editable-py3-none-any.whl'
.. attribute:: origin

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.
For editable packages, an ``origin`` property may present :pep:`610`
metadata (for non-editable packages, ``origin`` is :const:`None`)::

>>> dist.origin.url
'file:///path/to/wheel-0.32.3.editable-py3-none-any.whl'

The ``origin`` object follows the `Direct URL Data Structure
<https://packaging.python.org/en/latest/specifications/direct-url-data-structure/>`_.

.. versionadded:: 3.13

.. attribute:: entry_points
:type: EntryPoints

The entry points provided by this distribution package.

.. attribute:: files
:type: list[PackagePath] | None

All files contained in this distribution package.
Like :func:`files`, this returns :const:`None` if there are no records.

The following two abstract methods need to be implemented when implementing-custom-providers_:

.. method:: locate_file(path)

Like :meth:`!PackagePath.locate`, return a :class:`SimplePath` for the given path.
Takes a :class:`os.PathLike` or a :class:`str`.

.. method:: read_text(filename)

A shortcut for ``distribution.locate_file(filename).read_text()``.

.. versionadded:: 3.13
The ``.origin`` property was added.
.. _distribution-discovery:

Distribution Discovery
======================
Expand Down Expand Up @@ -575,8 +637,8 @@ consumer.

In practice, to support finding distribution package
metadata in locations other than the file system, subclass
``Distribution`` and implement the abstract methods. Then from
a custom finder, return instances of this derived ``Distribution`` in the
:class:`!Distribution` and implement the abstract methods. Then from
a custom finder, return instances of this derived :class:`!Distribution` in the
``find_distributions()`` method.

Example
Expand Down Expand Up @@ -653,8 +715,8 @@ packages served by the ``DatabaseImporter``, assuming that the
``.entry_points`` attributes.

The ``DatabaseDistribution`` may also provide other metadata files, like
``RECORD`` (required for ``Distribution.files``) or override the
implementation of ``Distribution.files``. See the source for more inspiration.
``RECORD`` (required for :attr:`!Distribution.files`) or override the
implementation of :attr:`!Distribution.files`. See the source for more inspiration.


.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
Expand Down
1 change: 1 addition & 0 deletions Lib/importlib/metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
'DistributionFinder',
'PackageMetadata',
'PackageNotFoundError',
'PackagePath',
'SimplePath',
'distribution',
'distributions',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Document rest of full public :class:`importlib.metadata.Distribution` API. Also add the (already documented) :class:`~importlib.metadata.PackagePath` to ``__all__``.
Loading