使用 importlib.metadata
¶
注解
此功能是临时的,可能会偏离标准库的常规版本语义。
importlib.metadata
提供对已安装包元数据的访问的库。这个库是在python的导入系统中内置的,它打算替换 entry point API 和 metadata API 属于 pkg_resources
. 随着 importlib.resources
在Python3.7和更新版本中(后端口为 importlib_resources 对于旧版本的python),这可以消除使用旧版本和效率较低的 pkg_resources
包裹。
“已安装包”通常指安装在python中的第三方包。 site-packages
通过诸如 pip . 具体来说,它是指具有可发现的 dist-info
或 egg-info
目录和元数据由定义 PEP 566 或其旧规格。默认情况下,包元数据可以位于文件系统上,也可以位于 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 物体。
你可以得到 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()
>>> 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
是由包作者定义的任意值,通常客户机希望解析特定组的所有入口点。读 the setuptools docs 有关入口点、其定义和用法的详细信息。
分发元数据¶
每个发行版都包含一些元数据,您可以使用 metadata()
功能:
>>> wheel_metadata = metadata('wheel')
返回的数据结构的键,即 PackageMetadata
,命名元数据关键字,则从分发元数据返回未经解析的值::
>>> wheel_metadata['Requires-Python']
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
分发版本¶
这个 version()
函数是以字符串形式获取分发版本号的最快方法:
>>> version('wheel')
'0.32.3'
分发文件¶
您还可以获取包含在分发中的完整文件集。这个 files()
函数获取分发包名称并返回此分发安装的所有文件。返回的每个文件对象都是 PackagePath
,A 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 或者,如果不知道目标分发版中存在元数据,请防范此情况。
分发要求¶
要获取分发的完整要求集,请使用 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
通过导入系统搜索或直接加载包的元数据 finders . 要查找分发包的元数据, importlib.metadata
查询的列表 meta path finders 在 sys.meta_path
.
默认值 PathFinder
for Python包含一个钩子,它调用 importlib.metadata.MetadataPathFinder
用于查找从典型的基于文件系统的路径加载的发行版。
抽象类 importlib.abc.MetaPathFinder
定义python的导入系统所需的finder接口。 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()
方法。
脚注