42

如何在脚本中以编程方式检查包是否为最新版本并返回真或假?

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

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)

但是我如何以编程方式检查并返回真或假?

4

8 回答 8

23

快速版本(仅检查包)

下面的代码调用具有不可用版本的包,例如pip install package_name==random. 该调用返回所有可用的版本。该程序读取最新版本。

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

如果找到匹配项,则返回 True,否则返回 False。

这是一个可靠的选择,因为它站在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
于 2019-10-31T18:21:34.880 回答
14

我的项目johnnydep有这个功能。

在外壳中:

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'
于 2019-10-31T18:39:36.780 回答
8

检查已安装的版本:

检查已安装版本的一种方法是访问__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'
于 2019-11-01T14:55:14.437 回答
5

仅检查 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']
于 2020-06-25T08:42:39.570 回答
2

至少出于演示目的,这应该可以解决问题。只需拨打isLatestVersion您要检查的包裹名称即可。如果您在某个重要的地方使用它,您可能想尝试/捕获 url 请求,因为互联网访问可能不可用。另请注意,如果未安装包isLatestVersion将返回 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
于 2019-10-31T18:13:07.390 回答
2

编辑:删除点搜索

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

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并返回True以指示最新版本(或者False如果不是最新版本)。这可能不是最好的解决方案,因为它只检查版本子字符串,if d[name] in s.decode():但它比pip list --outdated检查所有包要快。这不是最可靠的方法,因为True如果当前安装的版本是0.2.3但最新版本是0.2.30或,它将返回不正确的方法0.2.3a。一种改进是以编程方式获取最新版本并进行直接比较。

于 2019-10-31T19:12:03.057 回答
2

通过查询 PyPI API自己编写一个简单的脚本并不难。使用最新的 Python 3.8,可以只使用标准库(使用 Python 3.7 或更早版本时,您必须安装importlib_metadatabackport):

# 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)
于 2019-10-31T20:34:25.937 回答
-1

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

pip list --outdated | grep name_of_package
于 2021-03-31T10:53:32.250 回答