Làm thế nào để kiểm tra xem gói python có phải là phiên bản mới nhất không?


29

Làm thế nào để bạn kiểm tra xem một gói ở phiên bản mới nhất của nó được lập trình trong một tập lệnh và trả về đúng hay sai?

Tôi có thể kiểm tra với một kịch bản như thế này:

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'])

hoặc với dòng lệnh:

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

Nhưng làm thế nào để tôi kiểm tra theo chương trình và trả về đúng hay sai?


4
không phải là một giải pháp hoàn chỉnh nhưng nó có thể cung cấp cho bạn một số ý tưởng. stackoverflow.com/questions/4888027/ từ
reyPanda

Không có pip có một api bạn có thể gọi vào?
Aluan Haddad

3
Nếu bạn có thể sử dụng nó, Python 3.8 đã cải thiện hỗ trợ cho công cụ này, ít nhất là về những gì được cài đặt cục bộ của nó. docs.python.org/3/l Library / imllib.metadata.html
JL Peyret

1
pipkhông có API. Bạn có thể muốn xem pip-apidự án, nhưng vẫn chưa có nhiều.
wim

Câu trả lời:


16

Phiên bản nhanh (Chỉ kiểm tra gói)

Mã dưới đây gọi gói với một phiên bản không có sẵn như pip install package_name==random. Cuộc gọi trả về tất cả các phiên bản có sẵn. Chương trình đọc phiên bản mới nhất.

Chương trình sau đó chạy pip show package_namevà lấy phiên bản hiện tại của gói.

Nếu tìm thấy kết quả khớp, nó trả về True, ngược lại là Sai.

Đây là một lựa chọn đáng tin cậy cho rằng nó đứng trên 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

Đoạn mã sau gọi cho 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

Tôi đã cập nhật nó. Bây giờ nó chỉ kiểm tra gói mà người dùng quan tâm. Tôi đã đặt cả hai lựa chọn thay thế.
Yusuf Baktir

1
Thường if (boolean): return True else: return Falselà tốt hơn chỉ đểreturn boolean
wim

Thật không tốt khi sử dụng "0" làm số phiên bản không có thật, bởi vì đôi khi điều này sẽ chỉ đi trước và cài đặt một gói! (thử pip install p==0ví dụ).
wim

Tôi đã sử dụng randomTôi chắc chắn không có phiên bản ngẫu nhiên
Yusuf Baktir

10

Dự án của tôi johnnydepcó tính năng này.

Trong vỏ bọc:

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

Trong Python:

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

Khi tôi chạy mã này trong Dấu nhắc lệnh của Windows, tôi nhận được mã thoát ANSI khiến kết quả không thể đọc được. Tôi nghĩ rằng bạn có thể muốn khắc phục điều này?
dùng541686

Tôi có colorama == 0.4.1 và structlog == 19.2.0, và vâng, tôi cũng thấy mã thoát với lệnh đó. Nếu nó giúp tôi chạy cái này trên Windows 10.0.17763.195, Python 3.7.4. Tôi không có cơ hội ngay bây giờ để gửi một vấn đề không may.
dùng541686

@ user541686 Đây là vấn đề 232 , được giải quyết trong structlog v20.1.0 được phát hành ngày hôm nay. Cảm ơn báo cáo.
Wim

thật sự cảm ơn!
dùng541686

4

Chỉnh sửa: Xóa tìm kiếm pip

Cảm ơn cho một số gợi ý. Đây là phiên bản mới không sử dụng pip searchmà thay vào đó lấy phiên bản mới nhất trực tiếp từ pypiđề xuất của Daniel Hill . Điều này cũng giải quyết vấn đề với các chuỗi con khớp sai.

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'))

Phản hồi ban đầu

Đây là một giải pháp nhanh chóng lấy thông tin phiên bản mới nhất chỉ trên gekkogói quan tâm.

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'))

Điều này tạo ra thông báo Latest version (0.2.3) of gekko is installedvà trả về Trueđể chỉ phiên bản mới nhất (hoặc Falsenếu không phải là phiên bản mới nhất). Đây có thể không phải là giải pháp tốt nhất vì nó chỉ kiểm tra một chuỗi con phiên bản với if d[name] in s.decode():nhưng nó nhanh hơn pip list --outdatedkiểm tra tất cả các gói. Đây không phải là phương pháp đáng tin cậy nhất vì nó sẽ trả về không chính xác Truenếu phiên bản được cài đặt hiện tại là 0.2.3nhưng phiên bản mới nhất là 0.2.30hoặc 0.2.3a. Một cải tiến sẽ là lập trình lấy phiên bản mới nhất và so sánh trực tiếp.


Cẩn thận với pip search. Nó sử dụng API XML-RPC không dùng nữa và đôi khi kết quả tìm kiếm không chính xác / sai Trên thực tế tôi nghĩ rằng nó có thể bị xóa sớm, xem Xóa lệnh tìm kiếm pip # 5216 .
wim

Tôi đã sửa đổi mã để sử dụng phương pháp kéo phiên bản gói hiện tại của Daniel. Một cách khác để có được phiên bản gekko hiện tại là làm import gekkovà sau đó current_version=gekko.__version__thay vì tạo một từ điển của tất cả các phiên bản gói. Tuy nhiên, không phải tất cả các gói đều có số phiên bản có thể truy cập được trong gói.
John Hedengren

4

Phiên bản mới nhất:

Dự án của tôi ludditecó tính năng này:

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

Phiên bản đã cài đặt:

Cách chính tắc để kiểm tra phiên bản đã cài đặt chỉ là truy cập vào __version__thuộc tính của không gian tên cấp cao nhất:

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

Thật không may, không phải tất cả các dự án đều đặt thuộc tính này. Khi họ không, bạn có thể sử dụng pkg_resourcesđể khai thác nó từ siêu dữ liệu:

>>> import pkg_resources
>>> pkg_resources.get_distribution("gekko").version
'0.2.0'

2

Điều này nên làm thủ thuật ít nhất cho mục đích demo. Chỉ cần gọi isLatestVersionvới tên của gói bạn muốn kiểm tra. Nếu bạn đang sử dụng điều này ở một nơi quan trọng, bạn sẽ muốn thử / bắt yêu cầu url vì truy cập internet có thể không khả dụng. Cũng lưu ý rằng nếu gói không được cài đặt isLatestVersionsẽ trả về Sai.

Điều này đã được thử nghiệm cho Python 3.7.4 và 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._internalkhông phải là API công khai. Nó thậm chí còn được khuyến khích rõ ràng trong các tài liệu của pip : " bạn không được sử dụng API nội bộ của pip theo cách này ".
wim

@wim Tốt để biết. Tôi đã không nhận thức được điều này. Cảm ơn vì đã cho tôi biết. Tôi chắc chắn sẽ khuyên mọi người sử dụng phương pháp của Yusuf Baktir thay vì dù sao nó đơn giản hơn.
Đồi Daniel

2

Không khó để tự viết một tập lệnh đơn giản bằng cách truy vấn API PyPI . Với Python 3.8 mới nhất, chỉ có thể sử dụng thư viện chuẩn (khi sử dụng Python 3.7 trở lên, bạn sẽ phải cài đặt 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)

Ví dụ sử dụng:

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

Nếu bạn tình cờ đã packagingcài đặt, thì đó là cách thay thế tốt hơn distutils.versioncho phân tích phiên bản:

from distutils.version import LooseVersion

...

LooseVersion(s)

trở thành

from packaging.version import parse

...

parse(s)

Điều này có thể cung cấp các kết quả khác nhau cho pip nếu các chỉ mục bổ sung hoặc thay thế được định cấu hình cho người dùng (thông qua tệp pip.conf hoặc PIP_INDEX_URL hoặc PIP_EXTRA_INDEX_URL env vars)
wim
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.