Содержание страницы
Использование importlib.metadata¶Using importlib.metadata
Новое в версии 3.8.
Исходный код: Lib/importlib/metadata.py
Примечание
Эта функциональность является предварительной и может отклоняться от обычной семантики версий стандартной библиотеки.
importlib.metadata – это библиотека, обеспечивающая доступ к метаданным установленных
пакетов. Частично основанная на системе импорта Python, эта библиотека
призвана заменить аналогичную функциональность в точки входа
API и API метаданных из pkg_resources. Вместе с
importlib.resources (начиная с Python 3.7
и новее, с обратным портированием как importlib_resources для более старых версий
Python), это позволяет отказаться от использования устаревшего и менее эффективного
пакета pkg_resources.
Под «установленным пакетом» обычно понимается сторонний пакет, установленный в
каталог site-packages Python с помощью таких инструментов, как pip. В частности,
это пакет, имеющий либо обнаруживаемый каталог dist-info или egg-info
и метаданные, определённые PEP 566 или более старыми спецификациями.
По умолчанию метаданные пакета могут находиться в файловой системе или в zip-архивах на
sys.path. Благодаря механизму расширения метаданные могут находиться практически
где угодно.
Обзор¶Overview
Предположим, вы хотите получить строку версии для пакета, установленного
с помощью pip. Начнём с создания виртуального окружения и установки
чего-нибудь в него:
$ 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'
Также можно получить набор точек входа, разбитых по группам, таких как
console_scripts, distutils.commands и другие. Каждая группа содержит
последовательность объектов EntryPoint.
Вы можете получить метаданные для дистрибутива:
>>> 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¶Functional API
Этот пакет предоставляет следующие функции через свой публичный API.
Точки входа¶Entry points
Функция entry_points() возвращает словарь всех точек входа,
сгруппированных по группам. Точки входа представлены экземплярами EntryPoint;
каждый EntryPoint имеет атрибуты .name, .group и .value, а также
метод .load() для определения значения.
>>> 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')
>>> main = wheel.load()
>>> main
<function main at 0x103528488>
group и name – произвольные значения, определяемые автором пакета.
Обычно клиент хочет получить все точки входа для определённой
группы. Прочтите документацию setuptools,
чтобы узнать больше о точках входа, их определении и использовании.
Метаданные дистрибутива¶Distribution metadata
Каждый дистрибутив содержит некоторые метаданные, которые можно извлечь с помощью
функции metadata():
>>> wheel_metadata = metadata('wheel')
Ключи возвращаемой структуры данных 1 именуют ключевые слова метаданных, а их значения возвращаются без разбора из метаданных дистрибутива:
>>> wheel_metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
Версии дистрибутивов¶Distribution versions
Функция version() – это самый быстрый способ получить номер версии дистрибутива
в виде строки:
>>> version('wheel')
'0.32.3'
Файлы дистрибутива¶Distribution files
Также можно получить полный набор файлов, содержащихся в дистрибутиве. Функция
files() принимает имя пакета дистрибутива и возвращает все
файлы, установленные этим дистрибутивом. Каждый возвращаемый файловый объект – это
PackagePath, производный объект pathlib.Path с дополнительными свойствами dist,
size и hash, как указано в метаданных. Например:
>>> 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
В случае, если файл метаданных со списком файлов (RECORD или SOURCES.txt) отсутствует, files() вернёт None. Вызывающий код может обернуть вызовы files() в always_iterable или иным образом защититься от этой ситуации, если неизвестно, что целевой дистрибутив содержит метаданные.
Зависимости дистрибутивов¶Distribution requirements
Чтобы получить полный набор зависимостей для дистрибутива, используйте функцию
requires():
>>> requires('wheel')
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
Дистрибутивы¶Distributions
Хотя приведённый выше API является наиболее распространённым и удобным способом использования, всю эту информацию можно получить из класса Distribution. Distribution – это
абстрактный объект, представляющий метаданные для пакета Python. Можно
получить экземпляр Distribution:
>>> from importlib.metadata import distribution
>>> dist = distribution('wheel')
Таким образом, альтернативный способ получить номер версии – через экземпляр Distribution:
>>> dist.version
'0.32.3'
На экземпляре Distribution доступны всевозможные дополнительные метаданные:
>>> dist.metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> dist.metadata['License']
'MIT'
Полный набор доступных метаданных здесь не описан. Подробнее см. PEP 566 .
Расширение алгоритма поиска¶Extending the search algorithm
Поскольку метаданные пакета недоступны через поиск sys.path или
напрямую через загрузчики пакетов, метаданные пакета находятся через систему
импорта искатели. Чтобы найти метаданные пакета дистрибутива,
importlib.metadata запрашивает список искателей метапути в
sys.meta_path.
Стандартный PathFinder для Python включает хук, который вызывает
importlib.metadata.MetadataPathFinder для поиска дистрибутивов,
загруженных из типичных путей файловой системы.
Абстрактный класс importlib.abc.MetaPathFinder определяет интерфейс, ожидаемый от искателей системой импорта Python.
importlib.metadata расширяет этот протокол, проверяя наличие опционального вызываемого объекта find_distributions у искателей из sys.meta_path, и предоставляет этот расширенный интерфейс как абстрактный базовый класс DistributionFinder, который определяет следующий абстрактный метод:
@abc.abstractmethod
def find_distributions(context=DistributionFinder.Context()):
"""Возвращает итерируемый объект со всеми экземплярами Distribution, способными
загружать метаданные для пакетов для указанного ``context``.
"""
Объект DistributionFinder.Context предоставляет свойства .path и .name,
указывающие путь для поиска и имена для сопоставления, и может
предоставлять другой соответствующий контекст.
На практике это означает, что для поддержки поиска метаданных дистрибутивного пакета
в местах, отличных от файловой системы, нужно создать подкласс
Distribution и реализовать абстрактные методы. Затем из
пользовательского находильщика возвращать экземпляры этого производного Distribution в
методе find_distributions().
Сноски
- 1
Технически, возвращаемый объект метаданных дистрибутива является
email.message.EmailMessageэкземпляром, но это деталь реализации и не является частью стабильного API. Следует использовать только методы и синтаксис, подобные словарю, для доступа к содержимому метаданных.