如何以编程方式检查 python 包是否为最新版本?

How to check if python package is latest version programmatically?

如何在脚本中以编程方式检查软件包是否为最新版本并且 return 是真还是假?

我可以用这样的脚本检查:

package='gekko'
import pip
if hasattr(pip, 'main'):
    from pip import main as pipmain
else:
    from pip._internal import main as pipmain
pipmain(['search','gekko'])

或使用命令行:

(base) C:\User>pip search gekko
gekko (0.2.3)  - Machine learning and optimization for dynamic systems
  INSTALLED: 0.2.3 (latest)

但是我如何以编程方式检查 return 是真还是假?

至少出于演示目的,这应该可以解决问题。只需使用您要检查的包的名称调用 isLatestVersion。如果您在重要的地方使用它,您可能需要 try/catch url 请求,因为可能无法访问互联网。另请注意,如果未安装软件包 isLatestVersion 将 return False。

已针对 Python 3.7.4 和 Pip 19.0.3 进行测试。

import pip
import subprocess
import json
import urllib.request
from pip._internal.operations.freeze import freeze

def isLatestVersion(pkgName):
    # Get the currently installed version
    current_version = ''
    for requirement in freeze(local_only=False):
        pkg = requirement.split('==')
        if pkg[0] == pkgName:
            current_version = pkg[1]

    # Check pypi for the latest version number
    contents = urllib.request.urlopen('https://pypi.org/pypi/'+pkgName+'/json').read()
    data = json.loads(contents)
    latest_version = data['info']['version']

    return latest_version == current_version

快速版(只检查包)

下面的代码调用了一个不可用版本的包,如 pip install package_name==random。调用 returns 所有可用版本。程序读取最新版本。

程序然后运行 ​​pip show package_name 并获取包的当前版本。

如果找到匹配项,则 returns 为真,否则为假。

这是一个可靠的选择,因为它位于 pip

import subprocess
import sys
def check(name):
    latest_version = str(subprocess.run([sys.executable, '-m', 'pip', 'install', '{}==random'.format(name)], capture_output=True, text=True))
    latest_version = latest_version[latest_version.find('(from versions:')+15:]
    latest_version = latest_version[:latest_version.find(')')]
    latest_version = latest_version.replace(' ','').split(',')[-1]

    current_version = str(subprocess.run([sys.executable, '-m', 'pip', 'show', '{}'.format(name)], capture_output=True, text=True))
    current_version = current_version[current_version.find('Version:')+8:]
    current_version = current_version[:current_version.find('\n')].replace(' ','') 

    if latest_version == current_version:
        return True
    else:
        return False

编辑 2021:以下代码不再适用于新版本的 pip

以下代码调用 pip list --outdated:

import subprocess
import sys

def check(name):
    reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'list','--outdated'])
    outdated_packages = [r.decode().split('==')[0] for r in reqs.split()]
    return name in outdated_packages

我的项目johnnydep有这个功能。

在shell中:

pip install --upgrade pip johnnydep
pip install gekko==0.2.0

在Python中:

>>> from johnnydep.lib import JohnnyDist
>>> dist = JohnnyDist("gekko")
>>> dist.version_installed  
'0.2.0'
>>> dist.version_latest 
'0.2.3'

编辑:删除 pip 搜索

感谢您的几条建议。这是一个不使用 pip search 的新版本,而是按照 Daniel Hill 的建议直接从 pypi 中提取最新版本。这也解决了子字符串错误匹配的问题。

def check(name):
    import subprocess
    import sys
    import json
    import urllib.request

    # create dictionary of package versions
    pkgs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
    keys = [p.decode().split('==')[0] for p in pkgs.split()]
    values = [p.decode().split('==')[1] for p in pkgs.split()]
    d = dict(zip(keys, values)) # dictionary of all package versions

    # retrieve info on latest version
    contents = urllib.request.urlopen('https://pypi.org/pypi/'+name+'/json').read()
    data = json.loads(contents)
    latest_version = data['info']['version']

    if d[name]==latest_version:
        print('Latest version (' + d[name] + ') of '+str(name)+' is installed')
        return True
    else:
        print('Version ' + d[name] + ' of '+str(name)+' not the latest '+latest_version)
        return False

print(check('gekko'))

原始回复

这是一个快速解决方案,可以仅检索感兴趣的 gekko 包的最新版本信息。

def check(name):
    import subprocess
    import sys
    # create dictionary of package versions
    pkgs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
    keys = [p.decode().split('==')[0] for p in pkgs.split()]
    values = [p.decode().split('==')[1] for p in pkgs.split()]
    d = dict(zip(keys, values)) # dictionary of all package versions

    # retrieve info on latest version
    s = subprocess.check_output([sys.executable, '-m', 'pip', 'search', name])

    if d[name] in s.decode():  # weakness
        print('Latest version (' + d[name] + ') of '+str(name)+' is installed')
        return True
    else:
        print(s.decode())
        return False

print(check('gekko'))

这会生成消息 Latest version (0.2.3) of gekko is installed 和 returns True 以指示最新版本(如果不是最新版本则为 False)。这可能不是最好的解决方案,因为它只检查带有 if d[name] in s.decode(): 的版本子字符串,但它比检查所有包的 pip list --outdated 更快。这不是最可靠的方法,因为如果当前安装的版本是 0.2.3 但最新版本是 0.2.300.2.3a,它会 return 一个不正确的 True。一种改进是以编程方式获取最新版本并进行直接比较。

通过 querying the PyPI API. With the latest Python 3.8, it's possible using only the standard library (when using Python 3.7 or older, you'll have to install the importlib_metadata backport 自己编写一个简单的脚本并不难):

# check_version.py

import json
import urllib.request
import sys

try:
    from importlib.metadata import version
except ImportError:
    from importlib_metadata import version

from distutils.version import LooseVersion


if __name__ == '__main__':
    name = sys.argv[1]
    installed_version = LooseVersion(version(name))

    # fetch package metadata from PyPI
    pypi_url = f'https://pypi.org/pypi/{name}/json'
    response = urllib.request.urlopen(pypi_url).read().decode()
    latest_version = max(LooseVersion(s) for s in json.loads(response)['releases'].keys())

    print('package:', name, 'installed:', installed_version, 'latest:', latest_version)

用法示例:

$ python check_version.py setuptools
package: setuptools installed: 41.2.0 latest: 41.6.0

如果你碰巧安装了packaging,它是distutils.version更好的版本解析替代品:

from distutils.version import LooseVersion

...

LooseVersion(s)

变成

from packaging.version import parse

...

parse(s)

正在检查安装的版本:

检查安装版本的一种方法是访问顶级命名空间的 __version__ 属性:

>>> import gekko
>>> gekko.__version__
'0.2.0'

遗憾的是,并非所有项目都设置此属性,这只是 Python 中的通用约定。当它们没有版本属性时,您可以使用 importlib.metadata 来查询包版本。这种方式实际上不需要导入包本身,因为它是从安装包时写出的包元数据中检索到的。

>>> import importlib.metadata
>>> importlib.metadata.version("gekko")
'0.2.0'

此功能自 Python 3.8 起可用。在旧的 Python 版本中,您可以类似地使用 pkg_resources,它是 setuptools:

的一部分
>>> import pkg_resources
>>> pkg_resources.get_distribution("gekko").version
'0.2.0'

正在检查最新版本:

目前在 stdlib 中没有办法做到这一点。但是我的项目 luddite 具有此功能:

>>> import luddite
>>> luddite.get_version_pypi("gekko")
'0.2.3'

只检查 PyPi 上的最新版本(Python 3.6 及更高版本):

$ pip install requests

import requests

package = 'django'  # replace with the package you want to check
response = requests.get(f'https://pypi.org/pypi/{package}/json')
latest_version = response.json()['info']['version']

根据已接受的答案,您可以执行以下操作:

pip list --outdated | grep name_of_package