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

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

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

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

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

有没有更好的解决方案?

【问题讨论】:

    标签: python module version


    【解决方案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__ 属性:stackoverflow.com/q/17583443/562769
    • pkg_resources 链接是错误 404
    • 不幸的是,这有很多限制。见stackoverflow.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】:

        一些想法:

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

        【讨论】:

        • 包应该指定它们的版本。对于通常(估计有 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))
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-12-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-12-30
              • 2015-06-26
              • 2018-07-02
              相关资源
              最近更新 更多