Spec-Zone.ru › Python 3.10

Использование importlib.metadata

Новая в версии 3.8.

Изменено в версии 3.10: importlib.metadata больше не является предварительной.

Исходный код: Lib/importlib/metadata/__init__.py

importlib.metadata — это библиотека, предоставляющая доступ к данным о метаданных установленных пакетов. В значительной степени основанная на импортирующей системе Python, эта библиотека предназначена для замены аналогичных возможностей в API точек входа и API метаданных pkg_resources. Наряду с importlib.resources в Python 3.7 и более поздних версиях (обратная совместимость с importlib_resources для более ранних версий Python), это позволяет избежать использования устаревшего и менее эффективного pkg_resources пакета.

Под «установленным пакетом» мы обычно подразумеваем сторонний пакет, установленный в директорию Python site-packages с помощью таких инструментов, как pip. Конкретно, это пакет, содержащий обнаруживаемый dist-info или egg-info директорию и метаданные, определённые в PEP 566 или его более ранних спецификациях. По умолчанию, метаданные пакетов могут находиться в файловой системе или в архивах zip в sys.path. Благодаря механизму расширения, метаданные могут храниться практически где угодно.

Обзор

Предположим, вы хотите получить строку версии пакета, установленного с помощью pip. Мы начнём с создания виртуальной среды и установки в неё чего-нибудь:

$ python -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

Этот пакет предоставляет следующие возможности через свой публичный 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 — произвольные значения, определённые автором пакета, и обычно клиент захочет разрешить все точки входа для конкретной группы. Для получения дополнительной информации о точках входа, их определении и использовании, обратитесь к документации setuptools.

Примечание по совместимости

«Выбираемые» точки входа были введены в importlib_metadata 3.6 и Python 3.10. До этих изменений, entry_points не принимал параметров и всегда возвращал словарь точек входа, сгруппированных по категориям. Для обеспечения совместимости, если в entry_points не передаются параметры, возвращается объект SelectableGroups, реализующий этот интерфейс словаря. В будущем, вызов entry_points без параметров будет возвращать объект EntryPoints. Пользователи должны полагаться на интерфейс выбора для извлечения точек входа по группам.

Метаданные дистрибутива

Каждый дистрибутив содержит определённые метаданные, которые можно извлечь с помощью функции metadata():

>>> wheel_metadata = metadata('wheel')  

Ключи возвращаемой структуры данных, 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.*'

Изменено в версии 3.10: Description теперь включен в метаданные при представлении через загрузку. Символы продолжения строки были удалены.

Новая в версии 3.10: Добавлен атрибут json.

Версии дистрибутива

Функция version() — самый быстрый способ получить номер версии дистрибутива в виде строки:

>>> version('wheel')  
'0.32.3'

Файлы дистрибутива

Вы также можете получить полный набор файлов, содержащихся в дистрибутиве. Функция files() принимает имя пакета дистрибутива и возвращает все файлы, установленные этим дистрибутивом. Каждый возвращаемый объект файла является 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')

В случае отсутствия файла-списка файлов в метаданных (RECORD или SOURCES.txt), files() вернёт None. Вызов files() может быть желательно обернуть в always_iterable или другим способом защититься от этого условия, если известно, что у целевого дистрибутива отсутствуют соответствующие метаданные.

Требования дистрибутива

Для получения полного набора требований для дистрибутива используйте функцию requires():

>>> requires('wheel')  
["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]

Пакетные дистрибутивы

Удобный метод для определения дистрибутива или дистрибутивов (в случае пакетного пространства имён) для верхнеуровневых пакетов или модулей Python:

>>> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}

Новая в версии 3.10.

Дистрибутивы

Хотя вышеописанный 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.

Расширение алгоритма поиска

Поскольку метаданные пакетов недоступны через поиски по 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()):
    """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().

© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/importlib.metadata.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API