许多第三方 Python 模块都有一个保存模块版本信息的属性(通常类似于module.VERSION
or module.__version__
),但有些没有。
此类模块的特定示例是 libxslt 和 libxml2。
我需要检查这些模块的正确版本是否在运行时使用。有没有办法做到这一点?
一个潜在的解决方案是在运行时读取源代码,对其进行哈希处理,然后将其与已知版本的哈希值进行比较,但这很讨厌。
有没有更好的解决方案?
使用pkg_resources。从 PyPI 安装的任何东西至少应该有一个版本号。
>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'
如果您使用的是 python >=3.8
,则可以使用内置库中的模块。要检查包的版本(在此示例中lxml
),请运行:
>>> from importlib.metadata import version
>>> version('lxml')
'4.3.1'
此功能也已移植到旧版本的 python ( <3.8
) 中,但您需要先安装一个单独的库:
pip install importlib_metadata
然后检查一个包的版本(在这个例子中lxml
)运行:
>>> from importlib_metadata import version
>>> version('lxml')
'4.3.1'
请记住,这只适用于从 PyPI 安装的包。此外,您必须将包名称作为参数传递给version
方法,而不是该包提供的模块名称(尽管它们通常相同)。
我会远离散列。正在使用的 libxslt 版本可能包含不影响您使用它的某种类型的补丁。
作为替代方案,我建议您不要在运行时检查(不知道这是否是硬性要求)。对于我编写的具有外部依赖项(第 3 方库)的 python 内容,我编写了一个脚本,用户可以运行该脚本来检查他们的 python 安装,以查看是否安装了适当版本的模块。
对于没有定义“版本”属性的模块,您可以检查它包含的接口(类和方法)并查看它们是否与预期的接口匹配。然后在您正在处理的实际代码中,假设第 3 方模块具有您期望的接口。
一些想法:
您可以使用
pip freeze
以需求格式查看已安装的软件包。
我发现使用各种可用的工具(包括这个其他答案pkg_resources
提到的最好的工具)非常不可靠,因为它们中的大多数并不涵盖所有情况。例如
由于我们需要一种可靠的方法来获取任何包、模块或子模块的版本,因此我最终编写了getversion。使用起来非常简单:
from getversion import get_module_version
import foo
version, details = get_module_version(foo)
有关详细信息,请参阅文档。
对于不提供__version__
以下内容的模块是丑陋但有效的:
#!/usr/bin/env python3.6
import sys
import os
import subprocess
import re
sp = subprocess.run(["pip3", "show", "numpy"], stdout=subprocess.PIPE)
ver = sp.stdout.decode('utf-8').strip().split('\n')[1]
res = re.search('^Version:\ (.*)$', ver)
print(res.group(1))
或者
#!/usr/bin/env python3.7
import sys
import os
import subprocess
import re
sp = subprocess.run(["pip3", "show", "numpy"], capture_output=True)
ver = sp.stdout.decode('utf-8').strip().split('\n')[1]
res = re.search('^Version:\ (.*)$', ver)
print(res.group(1))