Usingimportlib.metadata¶
New in version 3.8.
Source code:Lib/importlib/metadata.py
Note
This functionality is provisional and may deviate from the usualversion semantics of the standard library.
importlib.metadata is a library that provides for access to installedpackage metadata. Built in part on Python’s import system, this libraryintends to replace similar functionality in theentry pointAPI andmetadata API ofpkg_resources. Along withimportlib.resources in Python 3.7and newer (backported asimportlib_resources for older versions ofPython), this can eliminate the need to use the older and less efficientpkg_resources package.
By “installed package” we generally mean a third-party package installed intoPython’ssite-packages directory via tools such aspip. Specifically,it means a package with either a discoverabledist-info oregg-infodirectory, and metadata defined byPEP 566 or its older specifications.By default, package metadata can live on the file system or in zip archives onsys.path. Through an extension mechanism, the metadata can live almostanywhere.
Overview¶
Let’s say you wanted to get the version string for a package you’ve installedusingpip. We start by creating a virtual environment and installingsomething into it:
$python3-mvenvexample$sourceexample/bin/activate(example)$pipinstallwheel
You can get the version string forwheel by running the following:
(example) $ python>>>fromimportlib.metadataimportversion>>>version('wheel')'0.32.3'
You can also get the set of entry points keyed by group, such asconsole_scripts,distutils.commands and others. Each group contains asequence ofEntryPoint objects.
You can get themetadata for a distribution:
>>>list(metadata('wheel'))['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 adistribution’s version number, list itsconstituent files, and get a list of the distribution’sDistribution requirements.
Functional API¶
This package provides the following functionality via its public API.
Entry points¶
Theentry_points() function returns a dictionary of all entry points,keyed by group. Entry points are represented byEntryPoint instances;eachEntryPoint has a.name,.group, and.value attributes anda.load() method to resolve the value.
>>>eps=entry_points()>>>list(eps)['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']>>>scripts=eps['console_scripts']>>>wheel=[epforepinscriptsifep.name=='wheel'][0]>>>wheelEntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')>>>main=wheel.load()>>>main<function main at 0x103528488>
Thegroup andname are arbitrary values defined by the package authorand usually a client will wish to resolve all entry points for a particulargroup. Readthe setuptools docsfor more information on entrypoints, their definition, and usage.
Distribution metadata¶
Every distribution includes some metadata, which you can extract using themetadata() function:
>>>wheel_metadata=metadata('wheel')
The keys of the returned data structure1 name the metadata keywords, andtheir values are returned unparsed from the distribution metadata:
>>>wheel_metadata['Requires-Python']'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
Distribution versions¶
Theversion() function is the quickest way to get a distribution’s versionnumber, as a string:
>>>version('wheel')'0.32.3'
Distribution files¶
You can also get the full set of files contained within a distribution. Thefiles() function takes a distribution package name and returns all of thefiles installed by this distribution. Each file object returned is aPackagePath, apathlib.Path derived object with additionaldist,size, andhash properties as indicated by the metadata. For example:
>>>util=[pforpinfiles('wheel')if'util.py'instr(p)][0]>>>utilPackagePath('wheel/util.py')>>>util.size859>>>util.dist<importlib.metadata._hooks.PathDistribution object at 0x101e0cef0>>>>util.hash<FileHash mode: sha256 value: bYkw5oMccfazVCoYQwKkkemoVyMAFoR34mmKBx8R1NI>
Once you have the file, you can also read its contents:
>>>print(util.read_text())import base64import sys...def as_bytes(s): if isinstance(s, text_type): return s.encode('utf-8') return s
In the case where the metadata file listing files(RECORD or SOURCES.txt) is missing,files() willreturnNone. The caller may wish to wrap calls tofiles() inalways_iterableor otherwise guard against this condition if the targetdistribution is not known to have the metadata present.
Distribution requirements¶
To get the full set of requirements for a distribution, use therequires()function:
>>>requires('wheel')["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
Distributions¶
While the above API is the most common and convenient usage, you can get allof that information from theDistribution class. ADistribution is anabstract object that represents the metadata for a Python package. You canget theDistribution instance:
>>>fromimportlib.metadataimportdistribution>>>dist=distribution('wheel')
Thus, an alternative way to get the version number is through theDistribution instance:
>>>dist.version'0.32.3'
There are all kinds of additional metadata available on theDistributioninstance:
>>>dist.metadata['Requires-Python']'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'>>>dist.metadata['License']'MIT'
The full set of available metadata is not described here. SeePEP 566for additional details.
Extending the search algorithm¶
Because package metadata is not available throughsys.path searches, orpackage loaders directly, the metadata for a package is found through importsystemfinders. To find a distribution package’s metadata,importlib.metadata queries the list ofmeta path finders onsys.meta_path.
The defaultPathFinder for Python includes a hook that calls intoimportlib.metadata.MetadataPathFinder for finding distributionsloaded from typical file-system-based paths.
The abstract classimportlib.abc.MetaPathFinder defines theinterface expected of finders by Python’s import system.importlib.metadata extends this protocol by looking for an optionalfind_distributions callable on the finders fromsys.meta_path and presents this extended interface as theDistributionFinder abstract base class, which defines this abstractmethod:
@abc.abstractmethoddeffind_distributions(context=DistributionFinder.Context()):"""Return an iterable of all Distribution instances capable of loading the metadata for packages for the indicated ``context``. """
TheDistributionFinder.Context object provides.path and.nameproperties indicating the path to search and names to match and maysupply other relevant context.
What this means in practice is that to support finding distribution packagemetadata in locations other than the file system, subclassDistribution and implement the abstract methods. Then froma custom finder, return instances of this derivedDistribution in thefind_distributions() method.
Footnotes
- 1
Technically, the returned distribution metadata object is an
email.message.EmailMessageinstance, but this is an implementation detail, and not part of thestable API. You should only use dictionary-like methods and syntaxto access the metadata contents.