Использование importlib.metadata
Исходный код: Lib/importlib/metadata.py
Новая в версии 3.8.
Примечание
Эта функциональность предварительная и может отличаться от обычных семантик версий стандартной библиотеки.
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. Мы начинаем с создания виртуальной среды и установки в неё чего-либо:
$ 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
Этот пакет предоставляет следующую функциональность через свой публичный API.
Точки входа
Функция entry_points() возвращает словарь всех точек входа, индексированный по группам. Точки входа представлены экземплярами EntryPoint; каждый экземпляр EntryPoint имеет атрибуты .name, .group, и .value и метод .load() для разрешения значения. Также есть атрибуты .module, .attr, и .extras для получения компонентов атрибута .value.
>>> 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>
group и name — произвольные значения, определённые автором пакета, и обычно клиент желает разрешить все точки входа для определённой группы. Для получения дополнительной информации о точках входа, их определении и использовании обратитесь к документации pkg_resources.
Метаданные дистрибутива
Каждый дистрибутив включает в себя некоторые метаданные, которые можно извлечь с помощью функции metadata():
>>> wheel_metadata = metadata('wheel')
Ключи возвращаемой структуры данных 1 представляют собой ключевые слова метаданных, а их значения возвращаются необработанными из метаданных дистрибутива:
>>> wheel_metadata['Requires-Python'] '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
Версии дистрибутива
Функция 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'"]
Дистрибутивы
Хотя вышеприведённый 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().
Примечания
-
1 -
Технически, возвращаемый объект метаданных дистрибутива — это экземпляр
email.message.EmailMessage, но это деталь реализации, а не часть стабильного API. Вы должны использовать только методы и синтаксис словаря для доступа к содержимому метаданных.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/library/importlib.metadata.html