Python paketinin programlı olarak en son sürüm olup olmadığını nasıl kontrol edebilirim?


29

Bir paketin bir komut dosyasında programlı olarak en son sürümde olup olmadığını nasıl kontrol edersiniz ve doğru mu yanlış mı döndürürsünüz?

Böyle bir komut dosyası ile kontrol edebilirsiniz:

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

veya komut satırı ile:

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

Ancak programlı olarak nasıl kontrol edip doğru veya yanlış döndürürüm?


4
tam bir çözüm değil ama size bazı fikirler verebilir. stackoverflow.com/questions/4888027/…
reyPanda

Pip'in arayabileceğiniz bir API'si yok mu?
Aluan Haddad

3
Bundan yararlanabiliyorsanız, Python 3.8, en azından yerel olarak yüklü olan bu tür şeyler için geliştirilmiş bir desteğe sahiptir . docs.python.org/3/library/importlib.metadata.html
JL Peyret

1
pipAPI'sı yok. pip-apiProjeyi izlemek isteyebilirsiniz , ama henüz çok şey yok.
wim

Yanıtlar:


16

Hızlı Sürüm (Yalnızca paketi kontrol etme)

Aşağıdaki kod, paketi şu şekilde kullanılamayan bir sürümle çağırır pip install package_name==random. Çağrı mevcut tüm sürümleri döndürür. Program en son sürümü okur.

Program daha sonra çalışır pip show package_nameve paketin geçerli sürümünü alır.

Bir eşleşme bulursa True, aksi halde False döndürür.

Bu güvenilir bir seçenektir. 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

Aşağıdaki kod pip list --outdatedşunları gerektirir :

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

Güncelledim. Şimdi sadece kullanıcının ilgilendiği paketi kontrol ediyor. Her iki alternatifi de koydum.
Yusuf Baktir

1
Genellikle if (boolean): return True else: return Falsesadece daha iyidirreturn boolean
wim

Sahte sürüm numarası olarak "0" kullanmak iyi değildir, çünkü bu bazen devam eder ve bir paket kurar! ( pip install p==0örneğin deneyin ).
wim

randomRastgele bir sürüm olmadığından eminim kullandım
Yusuf Baktir

10

Projemde johnnydepbu özellik var.

Kabukta:

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

Python'da:

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

Bunu Windows Komut İstemi'nde çalıştırdığımda sonucu okunamaz hale getiren ANSI kaçış kodları alıyorum. Bence bunu düzeltmek isteyebilirsin?
user541686

Colorama == 0.4.1 ve structlog == 19.2.0 var ve evet, ben de bu komutla kaçış kodları görüyorum. Yardımcı oluyorsa, bunu Windows 10.0.17763.195, Python 3.7.4 üzerinde çalıştırıyorum. Şu anda maalesef bir sorun yayınlama şansım yok.
user541686

@ user541686 Bu oldu issue232 bugün yayımlanan structlog v20.1.0 çözüldü. Rapor için teşekkürler.
wim

harika, teşekkürler!
user541686

4

Düzenle: Pip aramasını kaldır

Birkaç öneri için teşekkürler. İşte kullanmayan pip searchancak bunun yerine en son sürümü doğrudan Daniel Hill'inpypi önerdiği gibi çeken yeni bir sürüm . Bu aynı zamanda alt dize yanlış eşleşmeleriyle ilgili sorunu da giderir.

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

Orijinal Yanıt

İşte sadece ilgili gekkopakette en son sürüm bilgilerini alan hızlı bir çözü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'))

Bu mesajı üretir Latest version (0.2.3) of gekko is installedve Trueen son sürümü (veya Falseen son sürümü değilse) belirtmek için geri döner . Bu en iyi çözüm olmayabilir, çünkü yalnızca bir sürüm alt dizesini kontrol eder, if d[name] in s.decode():ancak pip list --outdatedtüm paketleri kontrol ettiğinden daha hızlıdır . Bu yanlış bir dönecektir çünkü en güvenilir yöntem değildir Trueakım yüklü versiyonu ise 0.2.3ancak son sürümüdür 0.2.30veya 0.2.3a. Bir iyileştirme, programlı olarak en son sürümü almak ve doğrudan bir karşılaştırma yapmak olacaktır.


Dikkatli ol pip search. Kullanımdan kaldırılmış bir XML-RPC API kullanıyor ve bazen arama sonuçları yanlış / yanlış Aslında aslında yakında kaldırılabileceğini düşünüyorum, bkz . # 5216 pip arama komutunu kaldırma .
wim

Kodu, Daniel'in mevcut paket sürümünü çekme yöntemini kullanacak şekilde değiştirdim. Geçerli gekko sürümünü almanın başka bir yolu yapmak import gekkove daha sonra current_version=gekko.__version__tüm paket sürümlerinin bir sözlük oluşturmaktır. Ancak, tüm paketlerin pakette erişilebilir bir sürüm numarası yoktur.
John Hedengren

4

En son sürüm:

Projem ludditeşu özelliğe sahip:

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

Yüklü sürüm:

Yüklü sürümü kontrol etmenin standart yolu, yalnızca __version__üst düzey ad alanının niteliğine erişmektir :

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

Ne yazık ki, tüm projeler bu özelliği belirlemez. Yapmadıkları zaman, bunu pkg_resourcesmeta verilerden kazmak için kullanabilirsiniz :

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

2

Bu, en azından demo amaçlı olarak hile yapmalıdır. isLatestVersionKontrol etmek istediğiniz paketin adını girmeniz yeterlidir . Bunu önemli bir yerde kullanıyorsanız, internet erişimi bulunmayabileceğinden URL isteğini denemek / yakalamak istersiniz. Ayrıca paket yüklü değilse isLatestVersionFalse döndüreceğini unutmayın .

Bu Python 3.7.4 ve Pip 19.0.3 için test edilmiştir.

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._internalherkese açık API değil. Pip'in dokümanlarında açıkça cesaretiniz kırılmıştır : " pip'in dahili API'lerini bu şekilde kullanmamalısınız ".
wim

@wim Bilmek güzel. Bunun farkında değildim. Bilmeme izin verdiğin için teşekkürler. Kesinlikle daha basit olduğu için yine de Yusuf Baktir'in yöntemini kullananlara tavsiye ederim.
Daniel Hill

2

Kendinize basit bir senaryo yazmak zor değil PyPI API'sini sorgulayarak . En son Python 3.8 ile, yalnızca standart kitaplığı kullanmak mümkündür (Python 3.7 veya daha eski bir importlib_metadatasürümü kullanırken , backport'u yüklemeniz gerekir ):

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

Kullanım örneği:

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

Eğer sahipseniz packaging yüklü, bu daha iyi bir alternatif olduğunu distutils.versionversiyon ayrıştırma için:

from distutils.version import LooseVersion

...

LooseVersion(s)

olur

from packaging.version import parse

...

parse(s)

Bu, kullanıcı için ek veya alternatif dizinler yapılandırılırsa pip'e farklı sonuçlar verebilir (pip.conf dosyası veya PIP_INDEX_URL veya PIP_EXTRA_INDEX_URL env vars üzerinden)
wim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.