importlib.metadata
– 访问包元数据¶
在版本 3.8 中添加。
在版本 3.10 中更改: importlib.metadata
不再是临时的。
源代码: Lib/importlib/metadata/__init__.py
importlib.metadata
是一个库,它提供对已安装 发行版包 的元数据的访问,例如它的入口点或它的顶级名称 (导入包、模块,如果有的话)。该库部分基于 Python 的导入系统,旨在替换 入口点 API 和 元数据 API 中的类似功能 pkg_resources
。与 importlib.resources
一起,这个包可以消除使用旧的、效率较低的 pkg_resources
包的需要。
importlib.metadata
对通过 pip 等工具安装到 Python 的 site-packages
目录中的第三方发行版包进行操作。具体来说,它适用于具有可发现的 dist-info
或 egg-info
目录以及由 核心元数据规范 定义的元数据的发行版。
重要
这些不一定等同于或与可以在 Python 代码中导入的顶级导入包名称一一对应。一个发行版包可以包含多个导入包(和单个模块),而一个顶级导入包如果是一个命名空间包,则可能映射到多个发行版包。您可以使用 package_distributions() 来获取它们之间的映射。
默认情况下,发行版元数据可以位于 sys.path
上的文件系统或 zip 存档中。通过扩展机制,元数据几乎可以位于任何地方。
另请参阅
- https://importlib-metadata.readthedocs.io/
有关
importlib_metadata
的文档,它提供了importlib.metadata
的移植。这包括该模块的类和函数的 API 参考,以及针对pkg_resources
的现有用户的 迁移指南。
概述¶
假设您想获取使用 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'
您还可以获取可通过 EntryPoint 属性(通常是“group”或“name”)选择的入口点集合,例如 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
将关键字参数传递给 select
>>> 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
不接受任何参数,并且始终返回一个入口点字典,以组为键。使用 importlib_metadata
5.0 和 Python 3.12,entry_points
始终返回一个 EntryPoints
对象。有关兼容性选项,请参阅 backports.entry_points_selectable。
发行版元数据¶
每个 发行版包 都包含一些元数据,您可以使用 metadata()
函数提取这些元数据。
>>> wheel_metadata = metadata('wheel')
返回的数据结构(一个 PackageMetadata
)的键命名元数据关键字,值从发行版元数据中未解析地返回。
>>> wheel_metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
PackageMetadata
还提供了一个 json
属性,该属性根据 PEP 566 以 JSON 兼容的形式返回所有元数据。
>>> wheel_metadata.json['requires_python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
注意
metadata()
返回的对象的实际类型是实现细节,应该只通过 PackageMetadata 协议 描述的接口访问。
在版本 3.10 中更改: 现在,通过有效负载呈现时,元数据中包含 Description
。行延续字符已被删除。
添加了 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'
此处未描述所有可用的元数据。有关更多详细信息,请参阅 核心元数据规范。
发行版发现¶
默认情况下,此包为文件系统和 zip 文件 发行版包 的元数据发现提供内置支持。此元数据查找器搜索默认设置为 sys.path
,但它解释这些值的细微差别与其他导入机制略有不同。特别是
importlib.metadata
不尊重sys.path
上的bytes
对象。importlib.metadata
偶然会尊重sys.path
上的pathlib.Path
对象,即使这些值将被忽略以进行导入。
扩展搜索算法¶
因为 发行版包 元数据无法通过 sys.path
搜索或包加载器直接获得,因此发行版包的元数据是通过导入系统 查找器 找到的。为了找到发行版包的元数据,importlib.metadata
查询 元路径查找器 在 sys.meta_path
上的列表。
默认情况下,importlib.metadata
为文件系统上找到的发行版包安装一个查找器。此查找器实际上不会找到任何发行版,但它可以找到它们的元数据。
抽象类 importlib.abc.MetaPathFinder
定义了 Python 导入系统对查找器的预期接口。 importlib.metadata
通过在 sys.meta_path
中的查找器上查找可选的 find_distributions
可调用函数来扩展此协议,并将此扩展的接口呈现为 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
并实现抽象方法。然后从自定义查找器中,在 find_distributions()
方法中返回此派生 Distribution
的实例。