2019-05-24 20:59:01 -03:00
.. _using:
2019-12-29 13:26:35 -04:00
=================================
Using :mod: `!importlib.metadata`
=================================
2019-05-24 20:59:01 -03:00
2021-04-14 21:56:21 -03:00
.. module :: importlib.metadata
:synopsis: The implementation of the importlib metadata.
2021-04-16 20:13:38 -03:00
.. versionadded :: 3.8
2021-07-12 20:56:40 -03:00
.. versionchanged :: 3.10
`` importlib.metadata `` is no longer provisional.
2021-04-16 20:13:38 -03:00
2021-10-30 12:12:47 -03:00
**Source code:** :source: `Lib/importlib/metadata/__init__.py`
2021-04-14 21:56:21 -03:00
2022-10-06 16:25:24 -03:00
`` importlib_metadata `` is a library that provides access to
the metadata of an installed `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ ,
such as its entry points
or its top-level names (`Import Package <https://packaging.python.org/en/latest/glossary/#term-Import-Package> `_ \s, modules, if any).
Built in part on Python's import system, this library
2019-05-24 20:59:01 -03:00
intends to replace similar functionality in the `entry point
API`_ and `metadata API`_ of `` pkg_resources `` . Along with
2022-06-25 22:04:28 -03:00
:mod: `importlib.resources` ,
this package can eliminate the need to use the older and less efficient
2019-05-24 20:59:01 -03:00
`` pkg_resources `` package.
2022-10-06 16:25:24 -03:00
`` importlib_metadata `` operates on third-party *distribution packages*
installed into Python's `` site-packages `` directory via tools such as
`pip <https://pypi.org/project/pip/> `_ .
Specifically, it works with distributions with discoverable
`` dist-info `` or `` egg-info `` directories,
and metadata defined by the `Core metadata specifications <https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata> `_ .
.. important ::
These are *not* necessarily equivalent to or correspond 1:1 with
the top-level *import package* names
that can be imported inside Python code.
One *distribution package* can contain multiple *import packages*
(and single modules),
and one top-level *import package*
may map to multiple *distribution packages*
if it is a namespace package.
You can use :ref: `package_distributions() <package-distributions>`
to get a mapping between them.
By default, distribution metadata can live on the file system
or in zip archives on
2019-12-29 13:26:35 -04:00
:data: `sys.path` . Through an extension mechanism, the metadata can live almost
2019-05-24 20:59:01 -03:00
anywhere.
2022-06-25 22:04:28 -03:00
.. seealso ::
https://importlib-metadata.readthedocs.io/
The documentation for `` importlib_metadata `` , which supplies a
backport of `` importlib.metadata `` .
2022-10-06 16:25:24 -03:00
This includes an `API reference
<https://importlib-metadata.readthedocs.io/en/latest/api.html>`__
for this module's classes and functions,
as well as a `migration guide
<https://importlib-metadata.readthedocs.io/en/latest/migration.html>`__
for existing users of `` pkg_resources `` .
2022-06-25 22:04:28 -03:00
2019-05-24 20:59:01 -03:00
Overview
========
2022-10-06 16:25:24 -03:00
Let's say you wanted to get the version string for a
`Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ you've installed
2019-05-24 20:59:01 -03:00
using `` pip `` . We start by creating a virtual environment and installing
2019-05-26 11:30:52 -03:00
something into it:
2019-05-24 20:59:01 -03:00
2019-05-26 11:30:52 -03:00
.. code-block :: shell-session
2019-05-24 20:59:01 -03:00
$ python3 -m venv example
$ source example/bin/activate
2022-04-09 15:37:01 -03:00
(example) $ python -m pip install wheel
2019-05-24 20:59:01 -03:00
2019-05-26 11:30:52 -03:00
You can get the version string for `` wheel `` by running the following:
2019-05-24 20:59:01 -03:00
2019-05-26 11:30:52 -03:00
.. code-block :: pycon
2019-05-24 20:59:01 -03:00
(example) $ python
>>> from importlib.metadata import version # doctest: +SKIP
>>> version('wheel') # doctest: +SKIP
'0.32.3'
2022-06-25 22:04:28 -03:00
You can also get a collection of entry points selectable by properties of the EntryPoint (typically 'group' or 'name'), such as
2019-05-24 20:59:01 -03:00
`` console_scripts `` , `` distutils.commands `` and others. Each group contains a
2022-06-25 22:04:28 -03:00
collection of :ref: `EntryPoint <entry-points>` objects.
2019-05-24 20:59:01 -03:00
You can get the :ref: `metadata for a distribution <metadata>` ::
>>> list(metadata('wheel')) # doctest: +SKIP
['Metadata-Version', 'Name', 'Version', 'Summary', 'Home-page', 'Author', 'Author-email', 'Maintainer', 'Maintainer-email', 'License', 'Project-URL', 'Project-URL', 'Project-URL', 'Keywords', 'Platform', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Requires-Python', 'Provides-Extra', 'Requires-Dist', 'Requires-Dist']
You can also get a :ref: `distribution's version number <version>` , list its
:ref: `constituent files <files>` , and get a list of the distribution's
:ref: `requirements` .
Functional API
==============
This package provides the following functionality via its public API.
.. _entry-points:
Entry points
------------
2021-03-13 12:31:45 -04:00
The `` entry_points() `` function returns a collection of entry points.
Entry points are represented by `` EntryPoint `` instances;
2019-05-24 20:59:01 -03:00
each `` EntryPoint `` has a `` .name `` , `` .group `` , and `` .value `` attributes and
2020-06-05 17:34:16 -03:00
a `` .load() `` method to resolve the value. There are also `` .module `` ,
`` .attr `` , and `` .extras `` attributes for getting the components of the
2021-03-14 23:20:49 -03:00
`` .value `` attribute.
Query all entry points::
2019-05-24 20:59:01 -03:00
>>> eps = entry_points() # doctest: +SKIP
2021-03-14 23:20:49 -03:00
The `` entry_points() `` function returns an `` EntryPoints `` object,
2022-06-25 22:04:28 -03:00
a collection of all `` EntryPoint `` objects with `` names `` and `` groups ``
2021-03-14 23:20:49 -03:00
attributes for convenience::
2021-03-13 12:31:45 -04:00
>>> sorted(eps.groups) # doctest: +SKIP
2019-05-24 20:59:01 -03:00
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
2021-03-14 23:20:49 -03:00
`` EntryPoints `` has a `` select `` method to select entry points
matching specific properties. Select entry points in the
`` console_scripts `` group::
2021-03-13 12:31:45 -04:00
>>> scripts = eps.select(group='console_scripts') # doctest: +SKIP
2021-03-14 23:20:49 -03:00
Equivalently, since `` entry_points `` passes keyword arguments
through to select::
>>> scripts = entry_points(group='console_scripts') # doctest: +SKIP
Pick out a specific script named "wheel" (found in the wheel project)::
2021-03-13 12:31:45 -04:00
>>> 'wheel' in scripts.names # doctest: +SKIP
True
>>> wheel = scripts['wheel'] # doctest: +SKIP
2021-03-14 23:20:49 -03:00
Equivalently, query for that entry point during selection::
>>> (wheel,) = entry_points(group='console_scripts', name='wheel') # doctest: +SKIP
>>> (wheel,) = entry_points().select(group='console_scripts', name='wheel') # doctest: +SKIP
Inspect the resolved entry point::
2019-05-24 20:59:01 -03:00
>>> wheel # doctest: +SKIP
EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')
2020-06-05 17:34:16 -03:00
>>> wheel.module # doctest: +SKIP
'wheel.cli'
>>> wheel.attr # doctest: +SKIP
'main'
>>> wheel.extras # doctest: +SKIP
[]
2019-05-24 20:59:01 -03:00
>>> main = wheel.load() # doctest: +SKIP
>>> main # doctest: +SKIP
<function main at 0x103528488>
The `` group `` and `` name `` are arbitrary values defined by the package author
and usually a client will wish to resolve all entry points for a particular
group. Read `the setuptools docs
2022-06-21 15:55:18 -03:00
<https://setuptools.pypa.io/en/latest/userguide/entry_point.html> `_
2020-06-05 17:34:16 -03:00
for more information on entry points, their definition, and usage.
2019-05-24 20:59:01 -03:00
2021-03-14 23:20:49 -03:00
*Compatibility Note*
The "selectable" entry points were introduced in `` importlib_metadata ``
3.6 and Python 3.10. Prior to those changes, `` entry_points `` accepted
no parameters and always returned a dictionary of entry points, keyed
2022-10-06 16:25:24 -03:00
by group. With `` importlib_metadata `` 5.0 and Python 3.12,
`` entry_points `` always returns an `` EntryPoints `` object. See
`backports.entry_points_selectable <https://pypi.org/project/backports.entry_points_selectable> `_
for compatibility options.
2021-03-14 23:20:49 -03:00
2019-05-24 20:59:01 -03:00
.. _metadata:
Distribution metadata
---------------------
2022-10-06 16:25:24 -03:00
Every `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ includes some metadata,
which you can extract using the
2019-05-24 20:59:01 -03:00
`` metadata() `` function::
>>> wheel_metadata = metadata('wheel') # doctest: +SKIP
2020-12-31 13:56:43 -04:00
The keys of the returned data structure, a `` PackageMetadata `` ,
name the metadata keywords, and
the values are returned unparsed from the distribution metadata::
2019-05-24 20:59:01 -03:00
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
'>=2.7, !=3.0.*, !=3.1.* , !=3.2.*, !=3.3.* '
2021-05-02 18:03:40 -03:00
`` PackageMetadata `` also presents a `` json `` attribute that returns
all the metadata in a JSON-compatible form per :PEP: `566` ::
>>> wheel_metadata.json['requires_python']
'>=2.7, !=3.0.*, !=3.1.* , !=3.2.*, !=3.3.* '
2022-06-25 22:04:28 -03:00
.. note ::
The actual type of the object returned by `` metadata() `` is an
implementation detail and should be accessed only through the interface
described by the
2022-10-18 10:28:19 -03:00
`PackageMetadata protocol <https://importlib-metadata.readthedocs.io/en/latest/api.html#importlib_metadata.PackageMetadata> `_ .
2022-06-25 22:04:28 -03:00
2021-05-02 18:03:40 -03:00
.. versionchanged :: 3.10
The `` Description `` is now included in the metadata when presented
through the payload. Line continuation characters have been removed.
.. versionadded :: 3.10
The `` json `` attribute was added.
2019-05-24 20:59:01 -03:00
.. _version:
Distribution versions
---------------------
2022-10-06 16:25:24 -03:00
The `` version() `` function is the quickest way to get a
`Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ 's version
2019-05-24 20:59:01 -03:00
number, as a string::
>>> version('wheel') # doctest: +SKIP
'0.32.3'
.. _files:
Distribution files
------------------
You can also get the full set of files contained within a distribution. The
2022-10-06 16:25:24 -03:00
`` files() `` function takes a `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ name
and returns all of the
2019-05-24 20:59:01 -03:00
files installed by this distribution. Each file object returned is a
2021-04-28 20:27:37 -03:00
`` PackagePath `` , a :class: `pathlib.PurePath` derived object with additional `` dist `` ,
2019-05-24 20:59:01 -03:00
`` size `` , and `` hash `` properties as indicated by the metadata. For example::
>>> util = [p for p in files('wheel') if 'util.py' in str(p)][0] # doctest: +SKIP
>>> util # doctest: +SKIP
PackagePath('wheel/util.py')
>>> util.size # doctest: +SKIP
859
>>> util.dist # doctest: +SKIP
<importlib.metadata._hooks.PathDistribution object at 0x101e0cef0>
>>> util.hash # doctest: +SKIP
<FileHash mode: sha256 value: bYkw5oMccfazVCoYQwKkkemoVyMAFoR34mmKBx8R1NI>
Once you have the file, you can also read its contents::
>>> print(util.read_text()) # doctest: +SKIP
import base64
import sys
...
def as_bytes(s):
if isinstance(s, text_type):
return s.encode('utf-8')
return s
2021-04-28 20:27:37 -03:00
You can also use the `` locate `` method to get a the absolute path to the
file::
>>> util.locate() # doctest: +SKIP
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')
2019-09-02 12:08:03 -03:00
In the case where the metadata file listing files
(RECORD or SOURCES.txt) is missing, `` files() `` will
return `` None `` . The caller may wish to wrap calls to
`` files() `` in `always_iterable
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable> `_
or otherwise guard against this condition if the target
distribution is not known to have the metadata present.
2019-05-24 20:59:01 -03:00
.. _requirements:
Distribution requirements
-------------------------
2022-10-06 16:25:24 -03:00
To get the full set of requirements for a `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ ,
use the `` requires() ``
2019-09-10 10:53:31 -03:00
function::
2019-05-24 20:59:01 -03:00
2019-09-10 10:53:31 -03:00
>>> requires('wheel') # doctest: +SKIP
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
2019-05-24 20:59:01 -03:00
2022-10-06 16:25:24 -03:00
.. _package-distributions:
.. _import-distribution-package-mapping:
Mapping import to distribution packages
---------------------------------------
2021-03-13 12:31:45 -04:00
2022-10-06 16:25:24 -03:00
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)
that provide each importable top-level
Python module or `Import Package <https://packaging.python.org/en/latest/glossary/#term-Import-Package> `_ ::
2021-03-13 12:31:45 -04:00
>>> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}
2021-03-14 23:20:49 -03:00
.. versionadded :: 3.10
2022-03-13 16:53:29 -03:00
.. _distributions:
2021-03-13 12:31:45 -04:00
2019-05-24 20:59:01 -03:00
Distributions
=============
While the above API is the most common and convenient usage, you can get all
of that information from the `` Distribution `` class. A `` Distribution `` is an
2022-10-06 16:25:24 -03:00
abstract object that represents the metadata for
a Python `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ . You can
2019-05-24 20:59:01 -03:00
get the `` Distribution `` instance::
>>> from importlib.metadata import distribution # doctest: +SKIP
>>> dist = distribution('wheel') # doctest: +SKIP
Thus, an alternative way to get the version number is through the
`` Distribution `` instance::
>>> dist.version # doctest: +SKIP
'0.32.3'
There are all kinds of additional metadata available on the `` Distribution ``
instance::
2020-12-31 15:37:53 -04:00
>>> dist.metadata['Requires-Python'] # doctest: +SKIP
2019-05-24 20:59:01 -03:00
'>=2.7, !=3.0.*, !=3.1.* , !=3.2.*, !=3.3.* '
2020-12-31 15:37:53 -04:00
>>> dist.metadata['License'] # doctest: +SKIP
2019-05-24 20:59:01 -03:00
'MIT'
2022-10-06 16:25:24 -03:00
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.
2019-05-24 20:59:01 -03:00
2022-06-25 22:04:28 -03:00
Distribution Discovery
======================
2022-10-06 16:25:24 -03:00
By default, this package provides built-in support for discovery of metadata
for file system and zip file `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ \s.
This metadata finder search defaults to `` sys.path `` , but varies slightly in how it interprets those values from how other import machinery does. In particular:
2022-06-25 22:04:28 -03:00
- `` importlib.metadata `` does not honor :class: `bytes` objects on `` sys.path `` .
- `` importlib.metadata `` will incidentally honor :py:class: `pathlib.Path` objects on `` sys.path `` even though such values will be ignored for imports.
2019-05-24 20:59:01 -03:00
Extending the search algorithm
==============================
2022-10-06 16:25:24 -03:00
Because `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package> `_ metadata
is not available through :data: `sys.path` searches, or
package loaders directly,
the metadata for a distribution is found through import
2022-10-26 00:26:28 -03:00
system :ref: `finders <finders-and-loaders>` . To find a distribution package's metadata,
2019-12-29 13:26:35 -04:00
`` importlib.metadata `` queries the list of :term: `meta path finders <meta path finder>` on
:data: `sys.meta_path` .
2019-05-24 20:59:01 -03:00
2022-10-06 16:25:24 -03:00
By default `` importlib_metadata `` installs a finder for distribution packages
found on the file system.
This finder doesn't actually find any *distributions* ,
but it can find their metadata.
2019-05-24 20:59:01 -03:00
The abstract class :py:class: `importlib.abc.MetaPathFinder` defines the
interface expected of finders by Python's import system.
`` importlib.metadata `` extends this protocol by looking for an optional
`` find_distributions `` callable on the finders from
2019-12-29 13:26:35 -04:00
:data: `sys.meta_path` and presents this extended interface as the
2019-09-10 10:53:31 -03:00
`` DistributionFinder `` abstract base class, which defines this abstract
method::
2019-05-24 20:59:01 -03:00
2019-09-10 10:53:31 -03:00
@abc.abstractmethod
def find_distributions(context=DistributionFinder.Context()):
2019-05-24 20:59:01 -03:00
"""Return an iterable of all Distribution instances capable of
2019-09-10 10:53:31 -03:00
loading the metadata for packages for the indicated `` context `` .
2019-05-24 20:59:01 -03:00
"""
2019-09-10 10:53:31 -03:00
The `` DistributionFinder.Context `` object provides `` .path `` and `` .name ``
2020-06-05 17:34:16 -03:00
properties indicating the path to search and name to match and may
2019-09-10 10:53:31 -03:00
supply other relevant context.
2019-05-24 20:59:01 -03:00
What this means in practice is that to support finding distribution package
2019-12-10 21:05:10 -04:00
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
2019-09-10 10:53:31 -03:00
`` find_distributions() `` method.
2019-05-24 20:59:01 -03:00
.. _`entry point API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
.. _`metadata API`: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#metadata-api