Как проверить, является ли пакет python последней версией программно? - PullRequest
24 голосов
/ 31 октября 2019

Как вы проверяете, является ли пакет в его последней версии программно в скрипте, и возвращаете истину или ложь?

Я могу проверить с помощью скрипта, подобного этому:

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)

Но как мне проверить программно и вернуть true или false?

Ответы [ 6 ]

11 голосов
/ 31 октября 2019

Быстрая версия (только проверка пакета)

Этот способ выполняет вызов пакета с недоступной версией, такой как 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

Этот вызывает 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
7 голосов
/ 31 октября 2019

Мой проект 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'
3 голосов
/ 31 октября 2019

Редактировать: Удалить поиск в пипсах

Спасибо за несколько предложений. Вот новая версия, которая не использует pip search, но вместо этого извлекает последнюю версию прямо из pypi, как предложено Daniel Hill . Это также решает проблему с ложными совпадениями подстроки.

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. Улучшение будет заключаться в том, чтобы программно получить последнюю версию и сделать прямое сравнение.

2 голосов
/ 01 ноября 2019

Последняя версия:

Мой проект luddite имеет эту функцию:

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

Установленная версия:

Канонический способ проверкиустановленная версия предназначена только для доступа к атрибуту __version__ пространства имен верхнего уровня:

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

К сожалению, не все проекты устанавливают этот атрибут. Когда они этого не делают, вы можете использовать pkg_resources, чтобы извлечь его из метаданных:

>>> import pkg_resources
>>> pkg_resources.get_distribution("gekko").version
'0.2.0'
2 голосов
/ 31 октября 2019

Это должно помочь, по крайней мере, в демонстрационных целях. Просто позвоните 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
1 голос
/ 31 октября 2019

Нетрудно написать простой скрипт самостоятельно, запросив API PyPI . В последнем Python 3.8 возможно использование только стандартной библиотеки (при использовании Python 3.7 или более поздней версии вам необходимо установить 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)
...