在运行时检查 Python 模块版本

Posted

技术标签:

【中文标题】在运行时检查 Python 模块版本【英文标题】:Checking a Python module version at runtime 【发布时间】:2010-10-17 04:08:34 【问题描述】:

许多第三方 Python 模块都有一个保存模块版本信息的属性(通常类似于 module.VERSIONmodule.__version__),但有些没有。

此类模块的特定示例是 libxslt 和 libxml2。

我需要检查这些模块的正确版本是否在运行时使用。有没有办法做到这一点?

一个潜在的解决方案是在运行时读取源代码,对其进行哈希处理,然后将其与已知版本的哈希值进行比较,但这很讨厌。

有没有更好的解决方案?

【问题讨论】:

【参考方案1】:

使用pkg_resources。从 PyPI 安装的任何东西至少应该有一个版本号。

>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'

【讨论】:

另外注意,包名必须是PyPI入口的。所以像“pkg_resources.get_distribution('mysqldb').version”这样的东西不起作用,但“pkg_resources.get_distribution('mysql-python').version”会。 如果您使用绝对文件名运行,pkg_resources 可能会选择一个不同的版本来隐藏您实际运行的版本,因为它比您的 PYTHONPATH 或类似名称具有更高的优先级。 如果有人想知道如何制作__version__ 属性:***.com/q/17583443/562769 pkg_resources 链接是错误 404 不幸的是,这有很多限制。见***.com/a/56910431/7262247【参考方案2】:

如果您使用的是 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 方法,而不是此包提供的模块名称(尽管它们通常相同)。

【讨论】:

【参考方案3】:

我会远离散列。正在使用的 libxslt 版本可能包含不影响您使用它的某种类型的补丁。

作为替代方案,我建议您不要在运行时检查(不知道这是否是硬性要求)。对于我编写的具有外部依赖项(第 3 方库)的 python 内容,我编写了一个脚本,用户可以运行该脚本来检查他们的 python 安装以查看是否安装了适当版本的模块。

对于没有定义“版本”属性的模块,您可以检查它包含的接口(类和方法),看看它们是否与预期的接口匹配。然后在您正在处理的实际代码中,假设第 3 方模块具有您期望的接口。

【讨论】:

【参考方案4】:

一些想法:

    尝试检查所需版本中存在或不存在的函数。 如果没有函数差异,请检查函数参数和签名。 如果您无法从函数签名中找出原因,请在导入时设置一些存根调用并检查它们的行为。

【讨论】:

包应该指定它们的版本。对于通常(估计有 99% 的情况)检查版本的简单任务,这些想法完全是矫枉过正。【参考方案5】:

你可以使用

pip freeze

以需求格式查看已安装的包。

【讨论】:

【参考方案6】:

我发现使用各种可用的工具非常不可靠(包括this other answer 提到的最好的pkg_resources),因为它们中的大多数并不涵盖所有情况。例如

内置模块 模块未安装,只是添加到 python 路径(例如通过您的 IDE) 同一模块的两个版本可用(python 路径中的一个取代已安装的一个)

由于我们需要一种可靠的方法来获取任何包、模块或子模块的版本,所以我最终写了getversion。使用起来非常简单:

from getversion import get_module_version
import foo
version, details = get_module_version(foo)

详情请参阅documentation。

【讨论】:

【参考方案7】:

对于不提供__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))

【讨论】:

以上是关于在运行时检查 Python 模块版本的主要内容,如果未能解决你的问题,请参考以下文章

在sublime文本CLI中运行python时,没有名为“statsmodels”的模块

使用 poll() 方法(在 opensuse 中)运行 python 模块时,终端显示返回值为 None?

请求运行时权限时检查 Android 版本

如何在运行时检查 Win32 中的 windows 版本?

在 Azure 中检查 Databricks 运行时的版本

python在命令行环境下运行时,显示拒绝访问,请大神指点。