Using importlib.metadata
¶
Source code: Lib/importlib/metadata.py
Нове в версії 3.8.
Примітка
This functionality is provisional and may deviate from the usual version semantics of the standard library.
importlib.metadata
is a library that provides for access to installed
package metadata. Built in part on Python’s import system, this library
intends to replace similar functionality in the entry point
API and metadata API of pkg_resources
. Along with
importlib.resources
in Python 3.7
and newer (backported as importlib_resources for older versions of
Python), this can eliminate the need to use the older and less efficient
pkg_resources
package.
By «installed package» we generally mean a third-party package installed into
Python’s site-packages
directory via tools such as pip. Specifically,
it means a package with either a discoverable dist-info
or egg-info
directory, and metadata defined by PEP 566 or its older specifications.
By default, package metadata can live on the file system or in zip archives on
sys.path
. Through an extension mechanism, the metadata can live almost
anywhere.
Огляд¶
Let’s say you wanted to get the version string for a package you’ve installed
using pip
. We start by creating a virtual environment and installing
something into it:
$ python3 -m venv example
$ source example/bin/activate
(example) $ pip install wheel
Ви можете отримати рядок версії для wheel
, виконавши наступне:
(example) $ python
>>> from importlib.metadata import version
>>> version('wheel')
'0.32.3'
You can also get the set of entry points keyed by group, such as
console_scripts
, distutils.commands
and others. Each group contains a
sequence of EntryPoint objects.
Ви можете отримати метадані для дистрибутива:
>>> 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']
Ви також можете отримати номер версії дистрибутива, перелічити його складові файли та отримати список Вимоги до розповсюдження дистрибутива.
Функціональний API¶
Цей пакет забезпечує такі функції через свій загальнодоступний API.
Точки входу¶
The entry_points()
function returns a dictionary of all entry points,
keyed by group. Entry points are represented by EntryPoint
instances;
each EntryPoint
has a .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:
>>> eps = entry_points()
>>> list(eps)
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
>>> scripts = eps['console_scripts']
>>> wheel = [ep for ep in scripts if ep.name == 'wheel'][0]
>>> wheel
EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')
>>> wheel.module
'wheel.cli'
>>> wheel.attr
'main'
>>> wheel.extras
[]
>>> main = wheel.load()
>>> main
<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
for more information on entry points, their definition, and usage.
Метадані розповсюдження¶
Every distribution includes some metadata, which you can extract using the
metadata()
function:
>>> wheel_metadata = metadata('wheel')
The keys of the returned data structure 1 name the metadata keywords, and their values are returned unparsed from the distribution metadata:
>>> wheel_metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
Версії розповсюдження¶
The version()
function is the quickest way to get a distribution’s version
number, as a string:
>>> version('wheel')
'0.32.3'
Файли розповсюдження¶
You can also get the full set of files contained within a distribution. The
files()
function takes a distribution package name and returns all of the
files installed by this distribution. Each file object returned is a
PackagePath
, a pathlib.PurePath
derived object with additional dist
,
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]
>>> util
PackagePath('wheel/util.py')
>>> util.size
859
>>> util.dist
<importlib.metadata._hooks.PathDistribution object at 0x101e0cef0>
>>> util.hash
<FileHash mode: sha256 value: bYkw5oMccfazVCoYQwKkkemoVyMAFoR34mmKBx8R1NI>
Отримавши файл, ви також можете прочитати його вміст:
>>> print(util.read_text())
import base64
import sys
...
def as_bytes(s):
if isinstance(s, text_type):
return s.encode('utf-8')
return s
You can also use the locate
method to get a the absolute path to the
file:
>>> util.locate()
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')
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
or otherwise guard against this condition if the target
distribution is not known to have the metadata present.
Вимоги до розповсюдження¶
To get the full set of requirements for a distribution, use the requires()
function:
>>> requires('wheel')
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
Розподіл¶
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
abstract object that represents the metadata for a Python package. You can
get the Distribution
instance:
>>> from importlib.metadata import distribution
>>> dist = distribution('wheel')
Thus, an alternative way to get the version number is through the
Distribution
instance:
>>> dist.version
'0.32.3'
There are all kinds of additional metadata available on the Distribution
instance:
>>> 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. See PEP 566 for additional details.
Розширення алгоритму пошуку¶
Because package metadata is not available through sys.path
searches, or
package loaders directly, the metadata for a package is found through import
system finders. To find a distribution package’s metadata,
importlib.metadata
queries the list of meta path finders on
sys.meta_path
.
The default PathFinder
for Python includes a hook that calls into
importlib.metadata.MetadataPathFinder
for finding distributions
loaded from typical file-system-based paths.
Абстрактний клас importlib.abc.MetaPathFinder
визначає інтерфейс, очікуваний від шукачів системою імпорту Python. importlib.metadata
розширює цей протокол, шукаючи необов’язковий find_distributions
, викликаний у шукачах з sys.meta_path
, і представляє цей розширений інтерфейс як DistributionFinder
абстрактний базовий клас, який визначає цей абстрактний метод:
@abc.abstractmethod
def find_distributions(context=DistributionFinder.Context()):
"""Return an iterable of all Distribution instances capable of
loading the metadata for packages for the indicated ``context``.
"""
Об’єкт DistributionFinder.Context
надає властивості .path
і .name
, що вказують шлях для пошуку та ім’я, яке відповідає, і може надати інший відповідний контекст.
На практиці це означає, що для підтримки пошуку метаданих пакетів дистрибутива в місцях, відмінних від файлової системи, створіть підклас Distribution
і реалізуйте абстрактні методи. Потім із спеціального засобу пошуку поверніть екземпляри цього похідного Distribution
у методі find_distributions()
.
Footnotes
- 1
Technically, the returned distribution metadata object is an
email.message.EmailMessage
instance, but this is an implementation detail, and not part of the stable API. You should only use dictionary-like methods and syntax to access the metadata contents.