プログラムでpythonパッケージが最新バージョンかどうかを確認するにはどうすればよいですか?


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

pipには呼び出し可能なAPIがありませんか?
Aluan Haddad

3
あなたがそれを利用できるなら、Python 3.8は、少なくともローカル側にインストールされているものに関して、このようなもののサポートを改善しました。 docs.python.org/3/library/importlib.metadata.html
JL Peyret

1
pipAPIはありません。pip-apiプロジェクトを見たいと思うかもしれませんが、まだそれほど多くはありません。
2019年

回答:


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

更新しました。これで、ユーザーが関心のあるパッケージのみがチェックされます。両方の選択肢を用意しました。
ユスフバクティル

1
通常、if (boolean): return True else: return Falseちょうど良いreturn boolean
wim

偽のバージョン番号として「0」を使用するのはよくありません。これは、先に進んでパッケージをインストールするだけだからです。(pip install p==0例えばお試しください)。
WIM

私はrandomランダムなバージョンがないと確信しています
ユスフ・バクティル

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これは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検索コマンドの削除#5216を参照してください。
2019年

現在のパッケージバージョンを取得する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リクエストを試行/キャッチすることをお勧めします。また、パッケージがインストールされていない場合はisLatestVersionFalseを返すことにも注意してください。

これは、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の方法の方が簡単なので、代わりに使用することをお勧めします。
ダニエル・ヒル

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

あなたがたまたま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を使用)、pipに異なる結果をもたらす可能性があります
wim
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.