Python i pip, wymień wszystkie dostępne wersje pakietu?

445

Biorąc pod uwagę nazwę pakietu Python, który można zainstalować za pomocą pip , czy jest jakiś sposób, aby znaleźć listę wszystkich możliwych wersji, które pip mógłby zainstalować? W tej chwili jest to próba i błąd.

Próbuję zainstalować wersję dla biblioteki innej firmy, ale najnowsza wersja jest zbyt nowa, wprowadzono zmiany niezgodne wstecz. Chciałbym więc w jakiś sposób wyświetlić listę wszystkich wersji, o których wie pip, aby móc je przetestować.

Rory
źródło
1
Przyjęta odpowiedź nie jest równoważna drugiej ze skryptem, ponieważ nie generują one tego samego wyniku.
oligofren,
17
Zaktualizuj wybraną odpowiedź. Żółtko jest zepsute i niepotrzebne. Odpowiedź z pip install pylibmc==jest idealna.
Jonathan
Zaktualizuj zaakceptowaną odpowiedź zgodnie z sugestią @Jonathan. Nie nazwałbym tego doskonałym, ponieważ nie będzie działał na wcześniejszych wersjach pipa (v7 lub v8), ale poza tym jest świetny.
Antony Hatchkins,
1
@Rory proszę zaktualizować zaakceptowaną odpowiedź, żółtko nie żyje. Odpowiedź Chrisa Montanaro jest najlepszą obecnie metodą IMO.
Ryan Fisher,
1
@Rory Zmień akceptowaną odpowiedź z korzyścią dla przyszłych użytkowników tego popularnego pytania. Projekt Yolk nie jest już utrzymywany i po prostu nie działa, jak twierdzi ta odpowiedź.
wim

Odpowiedzi:

167

(aktualizacja: od marca 2020 r. wiele osób zgłosiło, że żółtko zainstalowane za pomocą pip install yolk3kzwraca tylko najnowszą wersję. Odpowiedź Chrisa wydaje się mieć najwięcej pozytywnych opinii i działała dla mnie)

Skrypt w pastebin działa. Jednak nie jest to zbyt wygodne, jeśli pracujesz z wieloma środowiskami / hostami, ponieważ będziesz musiał go kopiować / tworzyć za każdym razem.

Lepszym uniwersalnym rozwiązaniem byłoby użycie yolk3k , który można zainstalować za pomocą pip. Np. Aby zobaczyć, jakie wersje Django są dostępne:

$ pip install yolk3k
$ yolk -V django
Django 1.3
Django 1.2.5
Django 1.2.4
Django 1.2.3
Django 1.2.2
Django 1.2.1
Django 1.2
Django 1.1.4
Django 1.1.3
Django 1.1.2
Django 1.0.4

yolk3kjest rozwidleniem oryginału, yolkktóry zaprzestał opracowywania w 2012 roku . Chociaż yolknie jest już utrzymywany (jak wskazano w komentarzach poniżej), yolk3kwydaje się, że jest i obsługuje Python 3.

Uwaga: Nie jestem zaangażowany w rozwój yolk3k. Jeśli coś nie działa tak, jak powinno, zostawienie komentarza nie powinno mieć większego znaczenia. Zamiast tego użyj narzędzia do śledzenia problemów yolk3k i rozważ przesłanie poprawki, jeśli to możliwe.

m000
źródło
4
Odpowiedź poniżej (użycie skryptu z pastebin) jest bardziej kłopotliwa, ale przynajmniej działa w moim przypadku (wyszukiwanie wersji scipy). żółtko pokazuje tylko ostatnią dostępną wersję, drugi skrypt pokazuje wszystkie wersje sprzed 0.8.0.
oligofren,
30
W większości przypadków zwraca tylko najnowszą wersję
PawelRoman,
17
Fir python3 wystarczy użyć instalatora pip yolk3k. Polecenie żółtka będzie dostępne.
Pierre Criulanscy,
8
Podobnie jak żółtek, przez większość czasu żółtko zwraca tylko najnowszą wersję.
diabloneo
4
żółtko jest zepsute / nie jest już utrzymywane. usuń tę odpowiedź.
wim
836

Dla pip> = 9.0 użyj

$ pip install pylibmc==
Collecting pylibmc==
  Could not find a version that satisfies the requirement pylibmc== (from 
  versions: 0.2, 0.3, 0.4, 0.5.1, 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5, 0.6.1, 0.6, 
  0.7.1, 0.7.2, 0.7.3, 0.7.4, 0.7, 0.8.1, 0.8.2, 0.8, 0.9.1, 0.9.2, 0.9, 
  1.0-alpha, 1.0-beta, 1.0, 1.1.1, 1.1, 1.2.0, 1.2.1, 1.2.2, 1.2.3, 1.3.0)
No matching distribution found for pylibmc==

- wszystkie dostępne wersje zostaną wydrukowane bez pobierania lub instalowania jakichkolwiek dodatkowych pakietów.

Dla pip <9.0 użycia

pip install pylibmc==blork

gdzie blorkmoże być dowolny ciąg znaków, który nie jest prawidłowym numerem wersji .

Chris Montanaro
źródło
25
Dziwne wydaje mi się, że błąd Pip wyrzuca wszystkie wersje, ale nie mają one żadnego argumentu, aby jawnie odczytać wspomniane dane
Chris Montanaro
2
Kolejną zaletą tego rozwiązania jest to, że działa ze wszystkimi normalnymi flagami, aby ograniczyć źródła instalacji. Na przykład pip install --only-binary :all: pylibmcwyświetli listę wszystkich wersji pylibmc dostępnych jako pakiety binarne.
pavon
3
pip install pylibmc==9999999 | tr ', ' "\n" | sort -n
Vikas,
18
Należy to zaznaczyć jako poprawną odpowiedź, ponieważ nie wymaga instalowania żadnych innych pakietów.
Yves Dorfsman
5
To trochę niedorzeczne, że wydaje się, że jest to jedyny sposób na zrobienie tego w pip. Mam nadzieję, że w ich narzędziu do śledzenia błędów jest co najmniej otwarty problem?
pmos
69

Aktualizacja:
od września 2017 r. Ta metoda już nie działa: --no-installzostała usunięta w pip 7

Użyj pip install -v, możesz zobaczyć wszystkie dostępne wersje

root@node7:~# pip install web.py -v
Downloading/unpacking web.py
  Using version 0.37 (newest of versions: 0.37, 0.36, 0.35, 0.34, 0.33, 0.33, 0.32, 0.31, 0.22, 0.2)
  Downloading web.py-0.37.tar.gz (90Kb): 90Kb downloaded
  Running setup.py egg_info for package web.py
    running egg_info
    creating pip-egg-info/web.py.egg-info

Aby nie instalować żadnego pakietu, użyj jednego z następujących rozwiązań:

root@node7:~# pip install --no-deps --no-install flask -v                                                                                                      
Downloading/unpacking flask
  Using version 0.10.1 (newest of versions: 0.10.1, 0.10, 0.9, 0.8.1, 0.8, 0.7.2, 0.7.1, 0.7, 0.6.1, 0.6, 0.5.2, 0.5.1, 0.5, 0.4, 0.3.1, 0.3, 0.2, 0.1)
  Downloading Flask-0.10.1.tar.gz (544Kb): 544Kb downloaded

lub

root@node7:~# cd $(mktemp -d)
root@node7:/tmp/tmp.c6H99cWD0g# pip install flask -d . -v
Downloading/unpacking flask
  Using version 0.10.1 (newest of versions: 0.10.1, 0.10, 0.9, 0.8.1, 0.8, 0.7.2, 0.7.1, 0.7, 0.6.1, 0.6, 0.5.2, 0.5.1, 0.5, 0.4, 0.3.1, 0.3, 0.2, 0.1)
  Downloading Flask-0.10.1.tar.gz (544Kb): 4.1Kb downloaded

Testowane z pip 1.0

root@node7:~# pip --version
pip 1.0 from /usr/lib/python2.7/dist-packages (python 2.7)
HVNSweeting
źródło
9
pip 1.5.4daje DEPRECATION: --no-install, --no-download, --build, and --no-clean are deprecated. See https://github.com/pypa/pip/issues/906.i nie pokazuje dostępnych wersji pakietów, które są już zainstalowane.
int_ua
2
aby pokazać wszystkie wersje, wystarczy -v. Reszta mojej odpowiedzi dotyczy unikania efektu dodania (instalacja / pobieranie). Aby zainstalować pkg, po prostu dodaj --upgrade. W każdym razie możesz utworzyć osobną wirtualną platformę, aby wszystko było prostsze.
HVNSweeting
2
pip 9.0.1 szczeka:no such option: --no-install
zmęczony_nitpickers
„najnowsza wersja:” z -v wyklucza niektóre wersje.
mmacvicar
55

Aby uzyskać te informacje, nie potrzebujesz pakietu innej firmy. pypi zapewnia proste kanały JSON dla wszystkich pakietów poniżej

https://pypi.python.org/pypi/{PKG_NAME}/json

Oto trochę kodu Pythona używającego tylko standardowej biblioteki, która pobiera wszystkie wersje.

import json
import urllib2
from distutils.version import StrictVersion

def versions(package_name):
    url = "https://pypi.python.org/pypi/%s/json" % (package_name,)
    data = json.load(urllib2.urlopen(urllib2.Request(url)))
    versions = data["releases"].keys()
    versions.sort(key=StrictVersion)
    return versions

print "\n".join(versions("scikit-image"))

Ten kod jest drukowany (na dzień 23 lutego 2015 r.):

0.7.2
0.8.0
0.8.1
0.8.2
0.9.0
0.9.1
0.9.2
0.9.3
0.10.0
0.10.1
eric chiang
źródło
2
JSON ma spore zagnieżdżenie. Kiedyś versions = [x for x in data["releases"] if any([y["python_version"] in ['cp26', '2.6'] for y in data["releases"][x]])]znajdowałem wersje kompatybilne z Python 2.6. ( cp26Nigdzie nie widziałem , ale niektóre pakiety miały, cp27więc spekuluję, że może istnieć w innych pakietach.)
tripleee
2
Oto sposób na zrobienie tego za pomocą curl, jq i sortowania („one-liner”!): curl -s https://pypi.python.org/pypi/{PKG_NAME}/json | jq -r '.releases | keys[]' | sort -t. -k 1,1n -k 2,2n -k 3,3n
Alan Ivey
1
Zgłasza to ValueErrorwyjątek dla niektórych pakietów, które przestrzegają niezbyt ścisłych schematów kontroli wersji. Aby to naprawić w przypadku tych pakietów, zobacz tę treść .
TrinitronX
przestarzałe zrobią to za Ciebie.
shadi
18

Wymyśliłem prosty skrypt bash. Dzięki autorowi jq .

#!/bin/bash
set -e

PACKAGE_JSON_URL="https://pypi.org/pypi/${1}/json"

curl -s "$PACKAGE_JSON_URL" | jq  -r '.releases | keys | .[]' | sort -V

Aktualizacja: dodaj sortowanie według numeru wersji.

Timofey Stolbov
źródło
Nie mogłem dostać się curldo pracy, prawdopodobnie z powodu błędów certyfikatu. wget --no-check-certificatedziała, ale nawet curl -k --insecurenic nie produkuje. Ostrzeżenie, które otrzymuję, wgetmówiERROR: certificate common name `www.python.org´ doesn´t match requested host name `pypi.python.org´.
tripleee
sort -VNie działa na OSX z wersji homebrew dniajq
deepelement
16

Możesz użyć pakietu yolk3k zamiast żółtka. yolk3k jest rozwidleniem oryginalnego żółtka i obsługuje zarówno python2, jak i 3.

https://github.com/myint/yolk

pip install yolk3k
ykyuen
źródło
Było to przydatne, ponieważ żółtko nie działa w Pythonie 3.x
Broken Man
1
yolk3k zwraca mi tylko zainstalowaną wersję:yolk -V attest Attest 0.5.3
Antony Hatchkins
2
yolk3k wydaje się zwracać tylko najnowszą wersję?
mvherweg
16

Po dłuższym spojrzeniu na kod pip wygląda na to, że kod odpowiedzialny za lokalizowanie pakietów można znaleźć w PackageFinderklasie w pip.index. Ta metoda find_requirementwyszukuje wersje InstallRequirement, ale niestety zwraca tylko najnowszą wersję.

Poniższy kod jest prawie kopią 1: 1 oryginalnej funkcji, a zwrot w wierszu 114 został zmieniony, aby zwrócić wszystkie wersje.

Skrypt oczekuje nazwy pierwszego pakietu jako jedynego argumentu i zwraca wszystkie wersje.

http://pastebin.com/axzdUQhZ

Nie mogę zagwarantować poprawności, ponieważ nie znam kodu pip. Ale mam nadzieję, że to pomaga.

Próbka wyjściowa

python test.py pip
Versions of pip
0.8.2
0.8.1
0.8
0.7.2
0.7.1
0.7
0.6.3
0.6.2
0.6.1
0.6
0.5.1
0.5
0.4
0.3.1
0.3
0.2.1
0.2 dev

Kod:

import posixpath
import pkg_resources
import sys
from pip.download import url_to_path
from pip.exceptions import DistributionNotFound
from pip.index import PackageFinder, Link
from pip.log import logger
from pip.req import InstallRequirement
from pip.util import Inf


class MyPackageFinder(PackageFinder):

    def find_requirement(self, req, upgrade):
        url_name = req.url_name
        # Only check main index if index URL is given:
        main_index_url = None
        if self.index_urls:
            # Check that we have the url_name correctly spelled:
            main_index_url = Link(posixpath.join(self.index_urls[0], url_name))
            # This will also cache the page, so it's okay that we get it again later:
            page = self._get_page(main_index_url, req)
            if page is None:
                url_name = self._find_url_name(Link(self.index_urls[0]), url_name, req) or req.url_name

        # Combine index URLs with mirror URLs here to allow
        # adding more index URLs from requirements files
        all_index_urls = self.index_urls + self.mirror_urls

        def mkurl_pypi_url(url):
            loc = posixpath.join(url, url_name)
            # For maximum compatibility with easy_install, ensure the path
            # ends in a trailing slash.  Although this isn't in the spec
            # (and PyPI can handle it without the slash) some other index
            # implementations might break if they relied on easy_install's behavior.
            if not loc.endswith('/'):
                loc = loc + '/'
            return loc
        if url_name is not None:
            locations = [
                mkurl_pypi_url(url)
                for url in all_index_urls] + self.find_links
        else:
            locations = list(self.find_links)
        locations.extend(self.dependency_links)
        for version in req.absolute_versions:
            if url_name is not None and main_index_url is not None:
                locations = [
                    posixpath.join(main_index_url.url, version)] + locations

        file_locations, url_locations = self._sort_locations(locations)

        locations = [Link(url) for url in url_locations]
        logger.debug('URLs to search for versions for %s:' % req)
        for location in locations:
            logger.debug('* %s' % location)
        found_versions = []
        found_versions.extend(
            self._package_versions(
                [Link(url, '-f') for url in self.find_links], req.name.lower()))
        page_versions = []
        for page in self._get_pages(locations, req):
            logger.debug('Analyzing links from page %s' % page.url)
            logger.indent += 2
            try:
                page_versions.extend(self._package_versions(page.links, req.name.lower()))
            finally:
                logger.indent -= 2
        dependency_versions = list(self._package_versions(
            [Link(url) for url in self.dependency_links], req.name.lower()))
        if dependency_versions:
            logger.info('dependency_links found: %s' % ', '.join([link.url for parsed, link, version in dependency_versions]))
        file_versions = list(self._package_versions(
                [Link(url) for url in file_locations], req.name.lower()))
        if not found_versions and not page_versions and not dependency_versions and not file_versions:
            logger.fatal('Could not find any downloads that satisfy the requirement %s' % req)
            raise DistributionNotFound('No distributions at all found for %s' % req)
        if req.satisfied_by is not None:
            found_versions.append((req.satisfied_by.parsed_version, Inf, req.satisfied_by.version))
        if file_versions:
            file_versions.sort(reverse=True)
            logger.info('Local files found: %s' % ', '.join([url_to_path(link.url) for parsed, link, version in file_versions]))
            found_versions = file_versions + found_versions
        all_versions = found_versions + page_versions + dependency_versions
        applicable_versions = []
        for (parsed_version, link, version) in all_versions:
            if version not in req.req:
                logger.info("Ignoring link %s, version %s doesn't match %s"
                            % (link, version, ','.join([''.join(s) for s in req.req.specs])))
                continue
            applicable_versions.append((link, version))
        applicable_versions = sorted(applicable_versions, key=lambda v: pkg_resources.parse_version(v[1]), reverse=True)
        existing_applicable = bool([link for link, version in applicable_versions if link is Inf])
        if not upgrade and existing_applicable:
            if applicable_versions[0][1] is Inf:
                logger.info('Existing installed version (%s) is most up-to-date and satisfies requirement'
                            % req.satisfied_by.version)
            else:
                logger.info('Existing installed version (%s) satisfies requirement (most up-to-date version is %s)'
                            % (req.satisfied_by.version, applicable_versions[0][1]))
            return None
        if not applicable_versions:
            logger.fatal('Could not find a version that satisfies the requirement %s (from versions: %s)'
                         % (req, ', '.join([version for parsed_version, link, version in found_versions])))
            raise DistributionNotFound('No distributions matching the version for %s' % req)
        if applicable_versions[0][0] is Inf:
            # We have an existing version, and its the best version
            logger.info('Installed version (%s) is most up-to-date (past versions: %s)'
                        % (req.satisfied_by.version, ', '.join([version for link, version in applicable_versions[1:]]) or 'none'))
            return None
        if len(applicable_versions) > 1:
            logger.info('Using version %s (newest of versions: %s)' %
                        (applicable_versions[0][1], ', '.join([version for link, version in applicable_versions])))
        return applicable_versions


if __name__ == '__main__':
    req = InstallRequirement.from_line(sys.argv[1], None)
    finder = MyPackageFinder([], ['http://pypi.python.org/simple/'])
    versions = finder.find_requirement(req, False)
    print 'Versions of %s' % sys.argv[1]
    for v in versions:
        print v[1]
Reiner Gerecke
źródło
To działało o wiele lepiej niż powyższa odpowiedź. skinny $ żółtko -V scipy scipy 0.12.0 skinny $ python test.py scipy Wersje scipy 0.12.0 0.12.0 0.11.0 0.11.0 0.10.1 0.10.1 0.10.0 0.10.0 0.9.0 0.9.0 0.8.0
oligofren
1
Takie użycie jest wyraźnie odradzane w dokumentach : „ nie wolno używać wewnętrznych interfejsów API pip w ten sposób
wim
9

Możesz użyć tego małego skryptu Python 3 (używając tylko standardowych modułów bibliotecznych), aby pobrać listę dostępnych wersji pakietu z PyPI przy użyciu JSON API i wydrukować je w odwrotnej kolejności chronologicznej. W odróżnieniu od innych rozwiązań Python zamieszczone tutaj, to nie łamie się na luźnych wersjach, takich jak django„s 2.2rc1lub uwsgi” s 2.0.17.1:

#!/usr/bin/env python3

import json
import sys
from urllib import request    
from pkg_resources import parse_version    

def versions(pkg_name):
    url = f'https://pypi.python.org/pypi/{pkg_name}/json'
    releases = json.loads(request.urlopen(url).read())['releases']
    return sorted(releases, key=parse_version, reverse=True)    

if __name__ == '__main__':
    print(*versions(sys.argv[1]), sep='\n')

Zapisz skrypt i uruchom go z nazwą pakietu jako argumentem, np .:

python versions.py django
3.0a1
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2
2.2rc1
...
Eugene Yarmash
źródło
7

Działa to dla mnie w OSX:

pip install docker-compose== 2>&1 \
| grep -oE '(\(.*\))' \
| awk -F:\  '{print$NF}' \
| sed -E 's/( |\))//g' \
| tr ',' '\n'

Zwraca listę jeden w wierszu:

1.1.0rc1
1.1.0rc2
1.1.0
1.2.0rc1
1.2.0rc2
1.2.0rc3
1.2.0rc4
1.2.0
1.3.0rc1
1.3.0rc2
1.3.0rc3
1.3.0
1.3.1
1.3.2
1.3.3
1.4.0rc1
1.4.0rc2
1.4.0rc3
1.4.0
1.4.1
1.4.2
1.5.0rc1
1.5.0rc2
1.5.0rc3
1.5.0
1.5.1
1.5.2
1.6.0rc1
1.6.0
1.6.1
1.6.2
1.7.0rc1
1.7.0rc2
1.7.0
1.7.1
1.8.0rc1
1.8.0rc2
1.8.0
1.8.1
1.9.0rc1
1.9.0rc2
1.9.0rc3
1.9.0rc4
1.9.0
1.10.0rc1
1.10.0rc2
1.10.0

Lub, aby uzyskać najnowszą wersję dostępną:

pip install docker-compose== 2>&1 \
| grep -oE '(\(.*\))' \
| awk -F:\  '{print$NF}' \
| sed -E 's/( |\))//g' \
| tr ',' '\n' \
| gsort -r -V \
| head -1
1.10.0rc2

Należy pamiętać, że gsortmusi być zainstalowany (w OSX), aby analizować wersje. Możesz go zainstalować za pomocąbrew install coreutils

babcia
źródło
Jezu, dlaczego nawet opublikowałeś tę odpowiedź. Odpowiedź Chrisa Montaro działa i jest elegancka. To niepotrzebnie wprowadza komplikacje
Brian Leach
@BrianLeach smh ... to samo podejście przefiltrowane do użycia w skrypcie ...
babcia
1
Dla mnie działa w cygwin / bash, dla drugiego rozwiązania użyj sort, a nie gsort w cygwin.
WebComer,
Tutaj python daje prawdopodobnie czytelniejszy kod niż bash ... patrz odpowiedź @eric chiang (mam nadzieję :) powyżej ...
mirekphd
4

Mój projekt ludditema tę funkcję.

Przykładowe użycie:

>>> import luddite
>>> luddite.get_versions_pypi("python-dateutil")
('0.1', '0.3', '0.4', '0.5', '1.0', '1.1', '1.2', '1.4', '1.4.1', '1.5', '2.0', '2.1', '2.2', '2.3', '2.4.0', '2.4.1', '2.4.2', '2.5.0', '2.5.1', '2.5.2', '2.5.3', '2.6.0', '2.6.1', '2.7.0', '2.7.1', '2.7.2', '2.7.3', '2.7.4', '2.7.5', '2.8.0')

Wyświetla listę wszystkich dostępnych wersji pakietu, wysyłając zapytanie do json API https://pypi.org/

wim
źródło
Byłoby bardziej pouczające, gdybyś powiedział nam, co robi twój pakiet, w przeciwnym razie po prostu
promujesz
@ user228395 Myślałem, że to dość oczywiste, ale zawiera listę wszystkich dostępnych wersji pakietu, dokładnie o to pyta tytuł pytania. Edytowane - lepiej?
wim
To oczywiście działa. Czy to w istocie zawiera rozwiązanie przedstawione przez @Timofey Stolbov?
user228395,
1
@ user228395 Nie nazwałbym tego „zawijaniem”, ponieważ ta odpowiedź używa bash, curl i jq - podczas gdy luddite po prostu używa standardowej biblioteki Pythona (urllib). Ale rozwiązanie firmy Stolbov korzysta z tego samego punktu końcowego na pypi.org . Czy mogę zapytać, jaki jest powód twojego odrzucenia?
wim
1
Jeśli podążasz za linkiem do strony ze szczegółowymi informacjami o projekcie, możesz zauważyć, że główną funkcją projektu jest sprawdzanie requirements.txtplików pod kątem nieaktualnych pakietów. To więcej niż kilka wierszy kodu. Aby sprawdzić requirements.txtplik, potrzebujesz funkcji, aby wyświetlić listę wszystkich wersji pakietów. Ta część jest celowo oddzielona i stanowi część publicznego interfejsu API luddite. I jest to źródłowa licencja Apache 2.0, myślę, że nie jest tak uczciwie nazywać to pakietem oprogramowania „czarnej skrzynki”.
wim
2

I nie ma żadnego szczęścia yolk, yolk3kczy pip install -vjednak tak skończyło się za pomocą tego (dostosowany do Python 3 z odpowiedzią Eric Chianga):

import json
import requests
from distutils.version import StrictVersion

def versions(package_name):
    url = "https://pypi.python.org/pypi/{}/json".format(package_name)
    data = requests.get(url).json()
    return sorted(list(data["releases"].keys()), key=StrictVersion, reverse=True)

>>> print("\n".join(versions("gunicorn")))
19.1.1
19.1.0
19.0.0
18.0
17.5
0.17.4
0.17.3
...
Andrew Magee
źródło
1
StrictVersionnie będzie pracować dla wielu pakietów ( django, uwsgi, psycopg2aby wymienić tylko kilka). Możesz użyć parse_version()z setuptools(patrz moja odpowiedź na przykład).
Eugene Yarmash
1

Alternatywnym rozwiązaniem jest użycie interfejsów API hurtowni:

https://warehouse.readthedocs.io/api-reference/json/#release

Na przykład dla Flask:

import requests
r = requests.get("https://pypi.org/pypi/Flask/json")
print(r.json()['releases'].keys())

wydrukuje:

dict_keys(['0.1', '0.10', '0.10.1', '0.11', '0.11.1', '0.12', '0.12.1', '0.12.2', '0.12.3', '0.12.4', '0.2', '0.3', '0.3.1', '0.4', '0.5', '0.5.1', '0.5.2', '0.6', '0.6.1', '0.7', '0.7.1', '0.7.2', '0.8', '0.8.1', '0.9', '1.0', '1.0.1', '1.0.2'])
Charlie
źródło
0

Prosty bashskrypt, który polega tylko na pythonsobie (zakładam, że w kontekście pytania powinien zostać zainstalowany) i jeden curllub wget. Zakłada się, że masz setuptoolszainstalowany pakiet do sortowania wersji (prawie zawsze zainstalowany). Nie opiera się na zewnętrznych zależnościach, takich jak:

  • jq które mogą nie być obecne;
  • grepi awkto może zachowywać się inaczej w systemie Linux i macOS.
curl --silent --location https://pypi.org/pypi/requests/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))"

Trochę dłuższa wersja z komentarzami.

Umieść nazwę pakietu w zmiennej:

PACKAGE=requests

Pobierz wersje (za pomocą curl):

VERSIONS=$(curl --silent --location https://pypi.org/pypi/$PACKAGE/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))")

Pobierz wersje (za pomocą wget):

VERSIONS=$(wget -qO- https://pypi.org/pypi/$PACKAGE/json | python -c "import sys, json, pkg_resources; releases = json.load(sys.stdin)['releases']; print(' '.join(sorted(releases, key=pkg_resources.parse_version)))")

Drukuj posortowane wersje:

echo $VERSIONS
Andrey Semakin
źródło
-1

Moje podejście jest kombinacją kilku opublikowanych odpowiedzi, z pewnymi modyfikacjami, aby ułatwić ich użycie z działającego środowiska python.

Chodzi o to, aby dostarczyć zupełnie nowe polecenie (wzorowane na poleceniu install), które daje instancję wyszukiwarki pakietów do użycia. Zaletą jest to, że współpracuje i wykorzystuje wszystkie indeksy, które pip obsługuje i odczytuje lokalne pliki konfiguracyjne pip, dzięki czemu otrzymujesz prawidłowe wyniki, tak jak w przypadku normalnej instalacji pip.

Podjąłem próbę uczynienia go kompatybilnym zarówno z pipem v. 9.x jak i 10.x .., ale wypróbowałem go tylko na 9.x

https://gist.github.com/kaos/68511bd013fcdebe766c981f50b473d4

#!/usr/bin/env python
# When you want a easy way to get at all (or the latest) version of a certain python package from a PyPi index.

import sys
import logging

try:
    from pip._internal import cmdoptions, main
    from pip._internal.commands import commands_dict
    from pip._internal.basecommand import RequirementCommand
except ImportError:
    from pip import cmdoptions, main
    from pip.commands import commands_dict
    from pip.basecommand import RequirementCommand

from pip._vendor.packaging.version import parse as parse_version

logger = logging.getLogger('pip')

class ListPkgVersionsCommand(RequirementCommand):
    """
    List all available versions for a given package from:

    - PyPI (and other indexes) using requirement specifiers.
    - VCS project urls.
    - Local project directories.
    - Local or remote source archives.

    """
    name = "list-pkg-versions"
    usage = """
      %prog [options] <requirement specifier> [package-index-options] ...
      %prog [options] [-e] <vcs project url> ...
      %prog [options] [-e] <local project path> ...
      %prog [options] <archive url/path> ..."""

    summary = 'List package versions.'

    def __init__(self, *args, **kw):
        super(ListPkgVersionsCommand, self).__init__(*args, **kw)

        cmd_opts = self.cmd_opts

        cmd_opts.add_option(cmdoptions.install_options())
        cmd_opts.add_option(cmdoptions.global_options())
        cmd_opts.add_option(cmdoptions.use_wheel())
        cmd_opts.add_option(cmdoptions.no_use_wheel())
        cmd_opts.add_option(cmdoptions.no_binary())
        cmd_opts.add_option(cmdoptions.only_binary())
        cmd_opts.add_option(cmdoptions.pre())
        cmd_opts.add_option(cmdoptions.require_hashes())

        index_opts = cmdoptions.make_option_group(
            cmdoptions.index_group,
            self.parser,
        )

        self.parser.insert_option_group(0, index_opts)
        self.parser.insert_option_group(0, cmd_opts)

    def run(self, options, args):
        cmdoptions.resolve_wheel_no_use_binary(options)
        cmdoptions.check_install_build_global(options)

        with self._build_session(options) as session:
            finder = self._build_package_finder(options, session)

            # do what you please with the finder object here... ;)
            for pkg in args:
                logger.info(
                    '%s: %s', pkg,
                    ', '.join(
                        sorted(
                            set(str(c.version) for c in finder.find_all_candidates(pkg)),
                            key=parse_version,
                        )
                    )
                )


commands_dict[ListPkgVersionsCommand.name] = ListPkgVersionsCommand

if __name__ == '__main__':
    sys.exit(main())

Przykładowe dane wyjściowe

./list-pkg-versions.py list-pkg-versions pika django
pika: 0.5, 0.5.1, 0.5.2, 0.9.1a0, 0.9.2a0, 0.9.3, 0.9.4, 0.9.5, 0.9.6, 0.9.7, 0.9.8, 0.9.9, 0.9.10, 0.9.11, 0.9.12, 0.9.13, 0.9.14, 0.10.0b1, 0.10.0b2, 0.10.0, 0.11.0b1, 0.11.0, 0.11.1, 0.11.2, 0.12.0b2
django: 1.1.3, 1.1.4, 1.2, 1.2.1, 1.2.2, 1.2.3, 1.2.4, 1.2.5, 1.2.6, 1.2.7, 1.3, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7, 1.4, 1.4.1, 1.4.2, 1.4.3, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.4.8, 1.4.9, 1.4.10, 1.4.11, 1.4.12, 1.4.13, 1.4.14, 1.4.15, 1.4.16, 1.4.17, 1.4.18, 1.4.19, 1.4.20, 1.4.21, 1.4.22, 1.5, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.5.5, 1.5.6, 1.5.7, 1.5.8, 1.5.9, 1.5.10, 1.5.11, 1.5.12, 1.6, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, 1.6.9, 1.6.10, 1.6.11, 1.7, 1.7.1, 1.7.2, 1.7.3, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9, 1.7.10, 1.7.11, 1.8a1, 1.8b1, 1.8b2, 1.8rc1, 1.8, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.8.6, 1.8.7, 1.8.8, 1.8.9, 1.8.10, 1.8.11, 1.8.12, 1.8.13, 1.8.14, 1.8.15, 1.8.16, 1.8.17, 1.8.18, 1.8.19, 1.9a1, 1.9b1, 1.9rc1, 1.9rc2, 1.9, 1.9.1, 1.9.2, 1.9.3, 1.9.4, 1.9.5, 1.9.6, 1.9.7, 1.9.8, 1.9.9, 1.9.10, 1.9.11, 1.9.12, 1.9.13, 1.10a1, 1.10b1, 1.10rc1, 1.10, 1.10.1, 1.10.2, 1.10.3, 1.10.4, 1.10.5, 1.10.6, 1.10.7, 1.10.8, 1.11a1, 1.11b1, 1.11rc1, 1.11, 1.11.1, 1.11.2, 1.11.3, 1.11.4, 1.11.5, 1.11.6, 1.11.7, 1.11.8, 1.11.9, 1.11.10, 1.11.11, 1.11.12, 2.0, 2.0.1, 2.0.2, 2.0.3, 2.0.4
Kaos
źródło
takie użycie jest wyraźnie odradzane w dokumentach : „ nie wolno używać wewnętrznych interfejsów API pip w ten sposób
wim