จะตรวจสอบว่าแพ็คเกจไพ ธ อนเป็นเวอร์ชั่นล่าสุดได้หรือไม่?


29

คุณจะตรวจสอบได้อย่างไรว่าแพคเกจนั้นเป็นเวอร์ชั่นล่าสุดโดยทางโปรแกรมในสคริปต์และส่งคืนจริงหรือเท็จ?

ฉันสามารถตรวจสอบกับสคริปต์เช่นนี้:

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
ไม่ใช่โซลูชันที่สมบูรณ์ แต่อาจให้แนวคิดบางอย่างกับคุณ stackoverflow.com/questions/4888027/…
reyPanda

pip ไม่ได้มี api ที่คุณสามารถโทรหาได้หรือไม่?
Aluan Haddad

3
ถ้าคุณสามารถใช้มันได้ Python 3.8 ได้รับการปรับปรุงให้ดีขึ้นสำหรับสิ่งที่น่าสนใจนี้อย่างน้อยก็ในสิ่งที่ติดตั้งไว้ภายในเครื่อง docs.python.org/3/library/importlib.metadata.html
JL Peyret

1
pipไม่มี API คุณอาจต้องการดูpip-apiโครงการ แต่ยังมีไม่มาก
Wim

คำตอบ:


16

Fast Version (ตรวจสอบแพ็คเกจเท่านั้น)

รหัสด้านล่างเรียกแพคเกจด้วยรุ่นที่ใช้งานไม่pip install package_name==randomได้ การโทรจะส่งคืนเวอร์ชันที่มีอยู่ทั้งหมด โปรแกรมอ่านเวอร์ชันล่าสุด

โปรแกรมจะทำงาน pip show package_nameและรับแพคเกจเวอร์ชันปัจจุบัน

หากพบคู่ที่ตรงกันจะส่งคืนค่า True หรือเท็จ

นี่เป็นตัวเลือกที่เชื่อถือได้เนื่องจากตั้งอยู่บน 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

ใน Python:

>>> 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 นี่เป็นปัญหา 232ได้รับการแก้ไขใน structlog v20.1.0 ที่วางจำหน่ายวันนี้ ขอบคุณสำหรับการรายงาน
Wim

ยอดเยี่ยมขอบคุณ!
user541686

4

แก้ไข: ลบการค้นหา pip

ขอบคุณสำหรับคำแนะนำหลายประการ นี่เป็นรุ่นใหม่ที่ไม่ได้ใช้pip searchแต่แทนที่จะดึงรุ่นล่าสุดได้โดยตรงจากpypiที่เสนอโดยแดเนียลฮิลล์ นอกจากนี้ยังช่วยแก้ไขปัญหาการจับคู่ substring false

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การปรับปรุงจะเป็นการรับรุ่นล่าสุดโดยทางโปรแกรมและทำการเปรียบเทียบโดยตรง


pip searchระมัดระวังด้วย มันใช้เลิกใช้ XML-RPC API และบางครั้งการค้นหาผลลัพธ์ที่ได้จะไม่ถูกต้อง / ผิด ในความเป็นจริงผมคิดว่ามันอาจจะถูกลบออกในเร็ว ๆ นี้ดูเอาคำสั่งค้นหา pip #
Wim

ฉันแก้ไขรหัสเพื่อใช้วิธีการของ Daniel ในการดึงเวอร์ชันแพ็คเกจปัจจุบัน อีกวิธีหนึ่งในการรับรุ่น gekko ปัจจุบันคือการทำ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จะคืนค่าเท็จ

นี่คือการทดสอบสำหรับ 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 : " คุณต้องไม่ใช้ API ภายในของ pip ด้วยวิธีนี้ "
Wim

@wim รู้ดี ฉันไม่ได้ตระหนักถึงสิ่งนี้ ขอบคุณสำหรับการให้ฉันรู้ว่า. ฉันจะแนะนำคนที่ใช้วิธีของ Yusuf Baktir แทนแทนเพราะมันง่ายกว่า
Daniel Hill

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)

นี้สามารถให้ผลลัพธ์ที่แตกต่างกันเพื่อจุดถ้าดัชนีเพิ่มเติมหรือสำรองมีการกำหนดค่าสำหรับผู้ใช้ (ผ่านทางไฟล์ pip.conf หรือ PIP_INDEX_URL หรือ PIP_EXTRA_INDEX_URL env vars)
Wim
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.