파이썬 패키지가 프로그래밍 방식으로 최신 버전인지 확인하는 방법은 무엇입니까?


29

패키지에서 프로그래밍 방식으로 스크립트의 최신 버전인지 확인하고 true 또는 false를 반환하는 방법은 무엇입니까?

다음과 같은 스크립트로 확인할 수 있습니다.

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를 어떻게 반환합니까?


4
완전한 해결책은 아니지만 몇 가지 아이디어를 줄 수 있습니다. stackoverflow.com/questions/4888027/…
reyPanda

핍에 전화 할 수있는 API가 없습니까?
Aluan Haddad

3
그것을 사용할 수 있다면, 파이썬 3.8은 적어도 로컬설치된 것에 대해 이런 종류의 지원을 개선 했습니다. docs.python.org/3/library/importlib.metadata.html
JL Peyret

1
pipAPI가 없습니다. pip-api프로젝트 를보고 싶을 수도 있지만 아직 많지는 않습니다.
wim

답변:


16

빠른 버전 (패키지 확인 만)

아래 코드는와 같은 사용할 수없는 버전으로 패키지를 호출합니다 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

업데이트했습니다. 이제는 사용자가 관심있는 패키지 만 검사합니다. 두 가지 대안을 모두 넣었습니다.
Yusuf Baktir

1
일반적 if (boolean): return True else: return False으로 더 나은return boolean
wim

"0"을 가짜 버전 번호로 사용하는 것은 좋지 않습니다. 때로는 패키지를 설치하기도합니다. ( pip install p==0예를 들어 보십시오 ).
wim

나는 random무작위 버전이 없다고 확신했다
Yusuf Baktir

10

내 프로젝트 johnnydep에는이 기능이 있습니다.

쉘에서 :

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

파이썬에서 :

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

Windows 명령 프롬프트에서 이것을 실행하면 결과를 읽을 수 없게하는 ANSI 이스케이프 코드가 나타납니다. 이 문제를 해결하고 싶습니까?
user541686

colorama == 0.4.1 및 structlog == 19.2.0이 있으며 해당 명령에 이스케이프 코드가 표시됩니다. 그것이 도움이된다면 Windows 10.0.17763.195, Python 3.7.4에서 이것을 실행하고 있습니다. 현재 안타깝게도 문제를 게시 할 기회가 없습니다.
user541686

@ user541686이이었다 issue232 오늘 발표 structlog v20.1.0에서 해결. 보고서 주셔서 감사합니다.
wim

감사합니다!
user541686

4

편집 : 핍 검색 제거

몇 가지 제안에 감사드립니다. 사용하지 않는 새 버전은 다음과 같습니다.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돌아갑니다 . 버전 하위 문자열 만 확인 하지만 모든 패키지를 확인하는 것보다 빠르기 때문에 이것은 최상의 솔루션이 아닐 수 있습니다 . 현재 설치된 버전이 최신 버전 이거나 최신 버전 인 경우 잘못된 값을 반환하므로 가장 안정적인 방법은 아닙니다.TrueFalseif d[name] in s.decode():pip list --outdatedTrue0.2.30.2.300.2.3a . 프로그래밍 방식으로 최신 버전을 얻고 직접 비교하는 것이 개선 될 것입니다.


조심하십시오 pip search. 더 이상 사용되지 않는 XML-RPC API를 사용하며 때로는 검색 결과가 정확하지 않거나 잘못되었습니다 . 실제로 제거 될 수 있다고 생각합니다 . pip search 명령 # 5216 제거를 참조 하십시오 .
wim

현재 패키지 버전을 가져 오는 Daniel의 방법을 사용하도록 코드를 수정했습니다. 현재 게코 버전을 얻을 수있는 또 다른 방법은하는 것입니다 import gekko다음과 current_version=gekko.__version__모든 패키지 버전의 사전을 만드는 대신. 그러나 모든 패키지에 패키지에서 액세스 할 수있는 버전 번호가있는 것은 아닙니다.
John Hedengren

4

최신 버전:

내 프로젝트 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

이것은 적어도 데모 목적으로 트릭을 수행해야합니다. 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
pip._internal공개 API가 아닙니다. pip의 문서 에서는 명시 적으로 권장하지 않습니다 . " 이 방법으로 pip의 내부 API를 사용해서는 안됩니다 ".
wim

@wim 반갑습니다. 나는 이것을 몰랐다. 알려 줘서 고마워. 어쨌든 Yusuf Baktir의 방법을 사용하는 사람들이 더 간단하기 때문에 확실히 추천합니다.
Daniel Hill

2

PyPI API쿼리하여 간단한 스크립트를 직접 작성하는 것은 어렵지 않습니다 . 최신 Python 3.8에서는 표준 라이브러리 만 사용할 수 있습니다 (Python 3.7 이전 버전을 사용하는 경우 importlib_metadata백 포트 를 설치해야 함 ).

# 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

설치 한 경우 버전 구문 분석 packagingdistutils.version위한 더 나은 대안입니다 .

from distutils.version import LooseVersion

...

LooseVersion(s)

된다

from packaging.version import parse

...

parse(s)

pip.conf 파일 또는 PIP_INDEX_URL 또는 PIP_EXTRA_INDEX_URL env vars를 통해 추가 또는 대체 색인이 사용자에 대해 구성된 경우 pip에 다른 결과를 제공 할 수 있습니다.
wim
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.