कैसे जांच करें कि पायथन पैकेज प्रोग्रामेटिक रूप से नवीनतम संस्करण है या नहीं?


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

क्या आपके पास कॉल करने के लिए पाइप नहीं है?
एलुआन हद्दाद

3
यदि आप इसका उपयोग कर सकते हैं, तो पायथन 3.8 ने इस थोड़े सामान के लिए समर्थन में सुधार किया है, कम से कम इसके स्थानीय स्तर पर स्थापित की गई वस्तु परdocs.python.org/3/library/importlib.metadata.html
JL Peyret

1
pipएपीआई नहीं है। आप pip-apiप्रोजेक्ट देखना चाहते हैं , लेकिन अभी बहुत कुछ नहीं है।
विम

जवाबों:


16

फास्ट संस्करण (केवल पैकेज की जाँच)

नीचे दिए गए कोड पैकेज को अनुपलब्ध संस्करण की तरह कहते हैं pip install package_name==random। कॉल सभी उपलब्ध संस्करणों को लौटाता है। कार्यक्रम नवीनतम संस्करण को पढ़ता है।

कार्यक्रम तब चलाता है pip show package_nameऔर पैकेज का वर्तमान संस्करण प्राप्त करता है।

यदि यह एक मैच पाता है, तो यह सही है, अन्यथा गलत है।

यह एक विश्वसनीय विकल्प है जो इसे दिया जाता है 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

मैंने इसे अपडेट किया है। अब यह केवल उस पैकेज की जांच करता है जिसमें उपयोगकर्ता की रुचि है। मैंने दोनों विकल्प रखे हैं।
यूसुफ बक्तीर

1
आम तौर पर if (boolean): return True else: return Falseबेहतर बस करने के लिए हैreturn boolean
विम

फर्जी संस्करण संख्या के रूप में "0" का उपयोग करना अच्छा नहीं है, क्योंकि कभी-कभी यह बस आगे बढ़ेगा और एक पैकेज स्थापित करेगा! ( pip install p==0उदाहरण के लिए प्रयास करें )।
विम

मैंने उपयोग किया है randomमुझे यकीन है कि कोई यादृच्छिक संस्करण नहीं है
यूसुफ बक्तीर

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'

जब मैं इसे विंडोज कमांड प्रॉम्प्ट में चलाता हूं, तो मुझे एएनएसआई एस्केप कोड मिलते हैं जो परिणाम को अपठनीय बनाते हैं। मुझे लगता है कि आप इसे ठीक करना चाह सकते हैं?
user541686

मेरे पास colorama == 0.4.1 और संरचित == 19.2.0 है, और हां, मुझे उस आदेश के साथ भागने के कोड भी दिखाई देते हैं। यदि यह मदद करता है कि मैं इसे विंडोज 10.0.17763.195, पायथन 3.7.4 पर चला रहा हूं। दुर्भाग्य से एक मुद्दा पोस्ट करने के लिए मेरे पास अभी कोई मौका नहीं है।
15:54 बजे user541686

@ user541686 यह था issue232 , आज जारी किया गया structlog v20.1.0 में संकल्प लिया। रिपोर्ट के लिए धन्यवाद।
विम

बहुत अच्छे धन्यवाद!
user541686

4

संपादित करें: पाइप खोज निकालें

कई सुझावों के लिए धन्यवाद। यहां एक नया संस्करण है जो उपयोग नहीं करता है, pip searchलेकिन इसके बजाय नवीनतम संस्करण को सीधे डैनियल हिल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 का उपयोग करता है, और कभी-कभी खोज परिणाम गलत / गलत होते हैं वास्तव में मुझे लगता है कि इसे जल्द ही हटाया जा सकता है, पाइप खोज कमांड # 5216 को देखें
विम

मैंने वर्तमान पैकेज संस्करण को खींचने के लिए डैनियल की विधि का उपयोग करने के लिए कोड को संशोधित किया। एक और तरीका है वर्तमान गेको संस्करण प्राप्त करने के लिए है import gekkoऔर फिर current_version=gekko.__version__सब पैकेज संस्करणों में से एक शब्दकोश बनाने की बजाय। हालांकि, सभी पैकेजों में पैकेज में एक संस्करण संख्या सुलभ नहीं है।
जॉन हेडेनग्रेन

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तो फाल्स वापस आ जाएगा।

यह पायथन 3.7.4 और पिप 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सार्वजनिक एपीआई नहीं है। यह पाइप के डॉक्स में भी स्पष्ट रूप से हतोत्साहित करता है : " आपको इस तरह से पाइप के आंतरिक एपीआई का उपयोग नहीं करना चाहिए "।
विम

@ जानने के लिए अच्छा है। मुझे इस बारे में नहीं पता था। मुझे बताने के लिए धन्यवाद। मैं निश्चित रूप से लोगों को यूसुफ बक्तीर की विधि का उपयोग करने की सलाह दूंगा, क्योंकि यह सरल है।
डेनियल हिल

2

PyPI API को क्वेरी करके एक साधारण स्क्रिप्ट को लिखना मुश्किल नहीं है । नवीनतम पायथन 3.8 के साथ, यह केवल मानक पुस्तकालय (जब पायथन 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

यदि आप 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.