Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyPI API - How to get stable package version

Tags:

python

pip

pypi

How does pip determine which version is the stable version of a package? For example, the current stable release of Django is 1.7.5 (as of 2-27-15), and that is the version installed by the command pip install django.

But when I go to the PyPI JSON API for Django (https://pypi.python.org/pypi/Django/json), it resolves to the most recent release (including development versions):

"version": "1.8b1",

There is a key in the JSON response that looks like it would indicate stable:

"stable_version": null,

but the value is null on all the packages I tried in the API. There is this line in the JSON response:

"classifiers": [
    "Development Status :: 4 - Beta", 

But that is a complex line to parse on. It would be nice if there was a line like "stable_version": true or false. How can I determine the default pip installed version using the PyPI JSON API?

like image 523
austinheiman Avatar asked Feb 27 '15 21:02

austinheiman


2 Answers

Version scheme defined in the PEP-440. There is a module packaging, which can handle version parsing and comparison.

I came up with this function to get latest stable version of a package:

import requests
import json
try:
    from packaging.version import parse
except ImportError:
    from pip._vendor.packaging.version import parse


URL_PATTERN = 'https://pypi.python.org/pypi/{package}/json'


def get_version(package, url_pattern=URL_PATTERN):
    """Return version of package on pypi.python.org using json."""
    req = requests.get(url_pattern.format(package=package))
    version = parse('0')
    if req.status_code == requests.codes.ok:
        j = json.loads(req.text.encode(req.encoding))
        releases = j.get('releases', [])
        for release in releases:
            ver = parse(release)
            if not ver.is_prerelease:
                version = max(version, ver)
    return version


if __name__ == '__main__':
    print("Django==%s" % get_version('Django'))

When executed, this produces following results:

$ python v.py
Django==2.0
like image 190
sashk Avatar answered Oct 07 '22 10:10

sashk


Just a quick note (as I can't add a reply to a previous answer yet) that sashk's answer could return an incorrect answer, as max() doesnt really understand versioning, f.e. as of now on SQLAlchemy it thinks 1.1.9 is higher than 1.1.14 (which is actually the latest stable release).

quick solution:

import urllib.request
import packaging.version
import distutils.version
data = json.loads(urllib.request.urlopen('https://pypi.python.org/pypi/SQLAlchemy/json').readall().decode('utf-8'))
max([distutils.version.LooseVersion(release) for release in data['releases'] if not packaging.version.parse(release).is_prerelease])

which correctly returns

LooseVersion ('1.1.14')
like image 45
Sandro Tosi Avatar answered Oct 07 '22 11:10

Sandro Tosi