importlib.metadata
– Доступ к метаданным пакета¶
Добавлено в версии 3.8.
Изменено в версии 3.10: importlib.metadata
больше не является временным.
Исходный код: Lib/importlib/metadata/__init__.py
importlib.metadata
- это библиотека, которая предоставляет доступ к метаданным установленного Distribution Package, таким как его точки входа или имена верхнего уровня (Import Package, модули, если таковые имеются). Частично основанная на системе импорта Python, эта библиотека предназначена для замены аналогичной функциональности в entry point API и metadata API из pkg_resources
. Наряду с importlib.resources
, этот пакет может избавить от необходимости использовать более старый и менее эффективный пакет pkg_resources
.
importlib.metadata
работает на сторонних дистрибутивах, установленных в каталог Python site-packages
с помощью таких инструментов, как pip. В частности, он работает с дистрибутивами с доступными для обнаружения каталогами dist-info
или egg-info
и метаданными, определенными в Core metadata specifications.
Важно
Они не обязательно эквивалентны или соответствуют 1:1 именам пакетов импорта верхнего уровня, которые могут быть импортированы внутри кода Python. Один дистрибутивный пакет может содержать несколько импортных пакетов (и отдельных модулей), а один импортный пакет верхнего уровня может быть сопоставлен нескольким дистрибутивным пакетам, если это пакет пространства имен. Вы можете использовать package_distributions(), чтобы получить сопоставление между ними.
По умолчанию метаданные распространения могут храниться в файловой системе или в zip-архивах на sys.path
. Благодаря механизму расширения метаданные могут храниться практически в любом месте.
См.также
- https://importlib-metadata.readthedocs.io/
Документация для
importlib_metadata
, которая предоставляет исходный кодimportlib.metadata
. Это включает в себя API reference для классов и функций этого модуля, а также migration guide для существующих пользователейpkg_resources
.
Обзор¶
Допустим, вы хотите получить строку версии для Distribution Package, которую вы установили с помощью pip
. Мы начинаем с создания виртуальной среды и установки в нее чего-либо:
$ python -m venv example
$ source example/bin/activate
(example) $ python -m pip install wheel
Вы можете получить строку версии для wheel
, выполнив следующее:
(example) $ python
>>> from importlib.metadata import version
>>> version('wheel')
'0.32.3'
Вы также можете получить набор точек входа, выбираемых по свойствам точки входа (обычно это «группа» или «имя»), например console_scripts
, distutils.commands
и другие. Каждая группа содержит коллекцию EntryPoint объектов.
Вы можете получить metadata 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']
Вы также можете получить distribution’s version number, перечислить его constituent files и получить список дистрибутивов Требования к распространению.
Функциональный API¶
Этот пакет предоставляет следующие функциональные возможности через свой общедоступный API.
Точки входа¶
Функция entry_points()
возвращает набор точек входа. Точки входа представлены экземплярами EntryPoint
; каждый экземпляр EntryPoint
имеет атрибуты .name
, .group
, и .value
, а также метод .load()
для определения значения. Существуют также атрибуты .module
, .attr
, и .extras
для получения компонентов атрибута .value
.
Запросите все точки входа:
>>> eps = entry_points()
Функция entry_points()
возвращает объект EntryPoints
, представляющий собой набор всех объектов EntryPoint
с атрибутами names
и groups
для удобства:
>>> sorted(eps.groups)
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
EntryPoints
содержит метод select
для выбора точек входа, соответствующих определенным свойствам. Выберите точки входа в группе console_scripts
:
>>> scripts = eps.select(group='console_scripts')
Эквивалентно, поскольку entry_points
передает аргументы ключевого слова для выбора:
>>> scripts = entry_points(group='console_scripts')
Выберите конкретный скрипт с именем «wheel» (находится в проекте wheel).:
>>> 'wheel' in scripts.names
True
>>> wheel = scripts['wheel']
Аналогично, запросите эту точку входа во время выбора:
>>> (wheel,) = entry_points(group='console_scripts', name='wheel')
>>> (wheel,) = entry_points().select(group='console_scripts', name='wheel')
Проверьте разрешенную точку входа:
>>> 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>
group
и name
являются произвольными значениями, определенными автором пакета, и обычно клиент желает разрешить все точки входа для определенной группы. Прочитайте the setuptools docs для получения дополнительной информации о точках входа, их определении и использовании.
Примечание о совместимости
«Выбираемые» точки входа были введены в importlib_metadata
3.6 и Python 3.10. До этих изменений entry_points
не принимал никаких параметров и всегда возвращал словарь точек входа, заданный по группам. Для обеспечения совместимости, если в entry_points не передаются параметры, возвращается объект SelectableGroups
, реализующий этот интерфейс dict. В будущем при вызове entry_points
без параметров будет возвращен объект EntryPoints
. Пользователи должны полагаться на интерфейс выбора для поиска точек входа по группам.
Метаданные распространения¶
Каждый Distribution Package содержит некоторые метаданные, которые вы можете извлечь с помощью функции metadata()
:
>>> wheel_metadata = metadata('wheel')
Ключи возвращаемой структуры данных, a PackageMetadata
, называются ключевыми словами метаданных, а значения возвращаются в разобранном виде из метаданных распространения:
>>> wheel_metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
PackageMetadata
также содержит атрибут json
, который возвращает все метаданные в JSON-совместимой форме для каждого PEP 566:
>>> wheel_metadata.json['requires_python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
Примечание
Фактический тип объекта, возвращаемый metadata()
, является деталью реализации и должен быть доступен только через интерфейс, описанный PackageMetadata protocol.
Изменено в версии 3.10: Символ Description
теперь включается в метаданные при представлении через полезную нагрузку. Символы продолжения строки были удалены.
Был добавлен атрибут json
.
Версии дистрибутива¶
Функция version()
- это самый быстрый способ получить номер версии Distribution Package в виде строки:
>>> version('wheel')
'0.32.3'
Файлы распространения¶
Вы также можете получить полный набор файлов, содержащихся в дистрибутиве. Функция files()
принимает имя Distribution Package и возвращает все файлы, установленные в этом дистрибутиве. Каждый возвращаемый файловый объект является PackagePath
, pathlib.PurePath
производным объектом с дополнительными свойствами 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
Вы также можете использовать метод locate
, чтобы получить абсолютный путь к файлу:
>>> util.locate()
PosixPath('/home/gustav/example/lib/site-packages/wheel/util.py')
В случае, если файл метаданных, содержащий список файлов (ЗАПИСЬ или SOURCES.txt), отсутствует, files()
вернет None
. Вызывающий может захотеть обернуть вызовы files()
в always_iterable или иным образом защититься от этого условия, если известно, что метаданные отсутствуют в целевом распределении.
Требования к распространению¶
Чтобы получить полный набор требований для Distribution Package, используйте функцию requires()
:
>>> requires('wheel')
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
Сопоставление импорта с пакетами распространения¶
Удобный метод для разрешения Distribution Package имени (или имен, в случае пакета пространства имен), которые предоставляют каждый импортируемый модуль Python верхнего уровня или Import Package:
>>> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}
Добавлено в версии 3.10.
Распределения¶
Хотя вышеуказанный API является наиболее распространенным и удобным для использования, вы можете получить всю эту информацию из класса Distribution
. A Distribution
- это абстрактный объект, который представляет метаданные для Python Distribution Package. Вы можете получить экземпляр 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'
Полный набор доступных метаданных здесь не описан. Дополнительные сведения см. в Core metadata specifications.
Обнаружение распространения¶
По умолчанию этот пакет предоставляет встроенную поддержку для обнаружения метаданных для файловой системы и zip-файла Distribution Packages. Этот поисковик метаданных по умолчанию использует значение sys.path
, но интерпретация этих значений немного отличается от того, как это делают другие механизмы импорта. В частности:
importlib.metadata
не учитываетbytes
объектов наsys.path
.importlib.metadata
, кстати, будет учитыватьpathlib.Path
объекты вsys.path
, даже если такие значения будут игнорироваться при импорте.
Расширение алгоритма поиска¶
Поскольку метаданные Distribution Package недоступны с помощью поиска sys.path
или прямых загрузчиков пакетов, метаданные для дистрибутива можно найти с помощью системы импорта finders. Чтобы найти метаданные дистрибутивного пакета, importlib.metadata
запрашивает список из meta path finders в sys.meta_path
.
По умолчанию importlib.metadata
устанавливает программу поиска дистрибутивов, найденных в файловой системе. На самом деле эта программа не находит никаких дистрибутивов, но может находить их метаданные.
Абстрактный класс importlib.abc.MetaPathFinder
определяет интерфейс, ожидаемый от finders системой импорта Python. importlib.metadata
расширяет этот протокол, ища необязательный find_distributions
, вызываемый в finders из 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
и реализовать абстрактные методы. Затем из пользовательского finder верните экземпляры этого производного Distribution
в методе find_distributions()
.