在运行时检查Python模块版本


118

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

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

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

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

有更好的解决方案吗?

Answers:


8

我会远离哈希。使用的libxslt版本可能包含某种补丁,但不会影响您的使用。

作为一种替代方法,我建议您不要在运行时检查(不知道这是否很困难)。对于我编写的具有外部依赖性(第3方库)的python东西,我编写了一个脚本,用户可以运行该脚本来检查其python安装,以查看是否安装了适当的模块版本。

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


244

使用pkg_resources。从PyPI安装的所有内容至少应具有版本号。

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

8
另请注意,程序包名称必须是PyPI条目的名称。因此,“ pkg_resources.get_distribution('MySQLdb')。version”之类的东西将不起作用,而“ pkg_resources.get_distribution('mysql-python')。version”则将起作用。
拉胡尔2012年

1
如果您使用的是绝对文件名,则pkg_resources可能会选择其他版本来遮盖实际运行的版本,因为它在您PYTHONPATH或类似的文件上具有更高的优先级。
Tripleee 2014年

4
如果有人想知道如何进行__version__属性设置:stackoverflow.com/q/17583443/562769
Martin Thoma

pkg_resources链接是错误404
gerrit

对于自动化处理,请参阅此问题
gerrit

6

一些想法:

  1. 尝试检查所需版本中存在的功能或不存在的功能。
  2. 如果没有函数差异,请检查函数参数和签名。
  3. 如果无法从函数签名中找出问题,请在导入时设置一些存根调用并检查其行为。

软件包应指定其版本。对于通常(估计为99%的情况)的简单版本检查任务,这些想法完全过头了。
Zelphir Kaltstahl,

2

您可以使用

pip freeze

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


1

您可以importlib_metadata为此使用库。

如果您使用的是python < 3.8,请首先使用以下命令进行安装:

pip install importlib_metadata

从python开始,3.8它就包含在python的标准库中。

然后,要检查软件包的版本(在本示例中为lxml),请运行:

>>> from importlib_metadata import version
>>> version('lxml')
'4.3.1'

请记住,这仅适用于从PyPI安装的软件包。同样,您必须将包名称作为version方法的参数传递,而不是此包提供的模块名称(尽管它们通常是相同的)。


0

我发现使用各种可用的工具(包括此其他答案中pkg_resources提到的最好的一种)非常不可靠,因为它们中的大多数都不能涵盖所有情况。例如

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

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

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

有关详细信息,请参见文档


0

对于不提供__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))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.