On this page
Using importlib.metadata
Note
此Function是临时的,可能会偏离标准库的常规版本语义。
importlib.metadata
是用于访问已安装的软件包元数据的库。该库部分构建在 Python 的导入系统上,旨在替换pkg_resources
的入口点 API和metadata API中的类似Function。与Python 3.7 及更高版本中的importlib.resources
(对于较旧版本的 Python 反向移植为importlib_resources)一起,这可以消除使用较旧且效率较低的pkg_resources
软件包的需要。
“安装的软件包”通常是指pass诸如pip之类的工具安装到 Python 的site-packages
目录中的第三方软件包。具体来说,它表示具有可发现的dist-info
或egg-info
目录以及由PEP 566或其较旧规范定义的元数据的软件包。默认情况下,程序包元数据可以存在于文件系统上,也可以存在于sys.path
的 zip 归档文件中。pass扩展机制,元数据几乎可以存在于任何地方。
Overview
假设您想获取使用pip
安装的软件包的版本字符串。我们首先创建一个虚拟环境并在其中安装一些东西:
$ python3 -m venv example
$ source example/bin/activate
(example) $ pip install wheel
您可以pass运行以下命令获取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']
您还可以获取发行版本号,列出其constituent files,并获取发行版的Distribution requirements的列表。
Functional API
该软件包pass其公共 API 提供以下Function。
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
是程序包作者定义的任意值,通常 Client 会希望解析特定组的所有入口点。阅读setuptools 文档以获取有关入口点,它们的定义和用法的更多信息。
Distribution metadata
每个发行版都包含一些元数据,您可以使用metadata()
函数提取这些元数据:
>>> wheel_metadata = metadata('wheel')
返回的数据结构[1]的键命名为 metadata 关键字,并且它们的值是从分发元数据中解析而来的:
>>> 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')
因此,获取版本号的另一种方法是passDistribution
实例:
>>> dist.version
'0.32.3'
Distribution
实例上还有各种其他可用的元数据:
>>> d.metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
>>> d.metadata['License']
'MIT'
这里没有描述完整的可用元数据集。有关更多详细信息,请参见PEP 566。
扩展搜索算法
由于无法passsys.path
搜索或直接从软件包加载程序获得软件包元数据,因此可以pass导入系统finders找到软件包的元数据。要查找分发程序包的元数据,importlib.metadata
在sys.meta_path上查询元路径发现者的列表。
Python 的默认PathFinder
包含一个钩子,该钩子调用importlib.metadata.MetadataPathFinder
来查找从典型的基于文件系统的路径加载的发行版。
抽象类importlib.abc.MetaPathFinder定义了 Python 导入系统期望的查找器接口。 importlib.metadata
pass在sys.meta_path
上的查找器上查找可选的find_distributions
来扩展此协议,并将此扩展接口作为DistributionFinder
抽象 Base Class 呈现,该抽象 Base Class 定义了此抽象方法:
@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
的实例。
Footnotes
- [1]
- 从技术上讲,返回的分发元数据对象是email.message.Message实例,但这是实现的详细信息,而不是稳定 API 的一部分。您只应使用类似于字典的方法和语法来访问元数据内容。