Python y pip, ¿enumera todas las versiones de un paquete que está disponible?

445

Dado el nombre de un paquete de Python que se puede instalar con pip , ¿hay alguna forma de encontrar una lista de todas las versiones posibles que pip podría instalar? En este momento es prueba y error.

Estoy tratando de instalar una versión para una biblioteca de terceros, pero la versión más nueva es demasiado nueva, se realizaron cambios incompatibles con versiones anteriores. Entonces, de alguna manera, me gustaría tener una lista de todas las versiones que Pip conoce, para poder probarlas.

Rory
fuente
1
La respuesta aceptada no es equivalente a la otra con el script, ya que no generan la misma salida.
oligofren
17
Actualiza la respuesta seleccionada. La yema está rota e innecesaria. La respuesta con pip install pylibmc==es perfecta.
Jonathan
Actualice la respuesta aceptada como @Jonathan sugiere. No lo llamaría perfecto porque no funcionará en versiones anteriores de pip (v7 o v8), pero de lo contrario es genial.
Antony Hatchkins
1
@Rory, actualiza la respuesta aceptada, la yema está muerta. La respuesta de Chris Montanaro es el mejor método actualmente IMO.
Ryan Fisher
1
@Rory Cambie la respuesta aceptada para beneficio de futuros visitantes a esta pregunta popular. El proyecto de yema ya no se mantiene y simplemente no funciona, ya que esa respuesta afirma.
wim

Respuestas:

167

(actualización: a partir de marzo de 2020, muchas personas han informado que la yema, instalada a través de pip install yolk3k, solo devuelve la última versión. La respuesta de Chris parece tener más votos positivos y funcionó para mí)

El script en pastebin funciona. Sin embargo, no es muy conveniente si está trabajando con múltiples entornos / hosts porque tendrá que copiarlo / crearlo cada vez.

Una mejor solución integral sería usar yolk3k , que está disponible para instalar con pip. Por ejemplo, para ver qué versiones de Django están disponibles:

$ 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

yolk3kes una bifurcación del original yolkque dejó de desarrollarse en 2012 . Aunque yolkya no se mantiene (como se indica en los comentarios a continuación), yolk3kparece ser y es compatible con Python 3.

Nota: no estoy involucrado en el desarrollo de yolk3k. Si algo no parece funcionar como debería, dejar un comentario aquí no debería hacer mucha diferencia. Utilice el rastreador de problemas yolk3k en su lugar y considere enviar una solución, si es posible.

m000
fuente
44
La respuesta a continuación (usando el script de pastebin) es más engorrosa, pero al menos funciona en mi caso (buscando versiones de scipy). yema solo muestra la última versión disponible, el otro script muestra todas las versiones que datan de 0.8.0.
oligofren
30
La mayoría de las veces solo devolverá la versión más nueva
PawelRoman el
17
Abeto python3 solo usa pip install yolk3k. El comando yema estará disponible.
Pierre Criulanscy
8
Al igual que la yema, la mayoría de las veces solo devuelve la versión más nueva.
diabloneo
44
la yema está rota / ya no se mantiene. borrar esta respuesta
wim
836

Para pip> = 9.0 use

$ 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==

- todas las versiones disponibles se imprimirán sin descargar o instalar ningún paquete adicional.

Para pip <9.0 use

pip install pylibmc==blork

donde blorkpuede haber cualquier cadena que no sea un número de versión válido .

Chris Montanaro
fuente
25
Me parece extraño que el error de pip escupe todas las versiones, pero no tienen argumentos para obtener explícitamente dichos datos
Chris Montanaro
2
Otra buena propiedad de esta solución es que funciona con todos los indicadores normales para limitar las fuentes de instalación. Por ejemplo pip install --only-binary :all: pylibmc, enumerará todas las versiones de pylibmc disponibles como paquetes binarios.
Pavón el
3
pip install pylibmc==9999999 | tr ', ' "\n" | sort -n
Vikas
18
Esto debe marcarse como la respuesta correcta, ya que no requiere la instalación de ningún otro paquete.
Yves Dorfsman
55
Es un poco ridículo que esta parezca ser la única forma de hacerlo en pip. Espero que haya al menos un problema abierto sobre esto en su rastreador de errores.
pmos
69

Actualización: a
partir de septiembre de 2017, este método ya no funciona: --no-installse eliminó en el pip 7

Use pip install -v, puede ver todas las versiones disponibles

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

Para no instalar ningún paquete, use una de las siguientes soluciones:

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

o

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

Probado con pip 1.0

root@node7:~# pip --version
pip 1.0 from /usr/lib/python2.7/dist-packages (python 2.7)
HVNSweeting
fuente
99
pip 1.5.4da DEPRECATION: --no-install, --no-download, --build, and --no-clean are deprecated. See https://github.com/pypa/pip/issues/906.y no muestra versiones disponibles para paquetes que ya están instalados.
int_ua
2
para mostrar todas las versiones, solo necesita -v. El resto de mi respuesta es para evitar el efecto de suma (instalación / descarga). Para el paquete instalado, simplemente agregue --upgrade. De nuevo, puede crear un virtualenv separado para simplificar todo.
HVNSweeting
2
pip 9.0.1 ladra:no such option: --no-install
tired_of_nitpickers
"la más nueva de las versiones:" de -v excluye algunas versiones.
mmacvicar
55

No necesita un paquete de terceros para obtener esta información. pypi proporciona feeds JSON simples para todos los paquetes bajo

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

Aquí hay un código de Python que usa solo la biblioteca estándar que obtiene todas las versiones.

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

Ese código se imprime (a partir del 23 de febrero de 2015):

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
fuente
2
El JSON tiene una buena cantidad de anidamiento. Solía versions = [x for x in data["releases"] if any([y["python_version"] in ['cp26', '2.6'] for y in data["releases"][x]])]encontrar versiones compatibles con Python 2.6. (No vi en cp26ningún lado, pero algunos paquetes sí, cp27así que especulo que esto podría existir en otros paquetes.)
tripleee
2
Aquí hay una manera de hacerlo con curl, jq y sort (¡un "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
Esto arroja una ValueErrorexcepción para algunos paquetes que siguen esquemas de versiones no tan estrictos. Para arreglarlo para estos paquetes, vea esta esencia .
TrinitronX
anticuado hará esto por ti.
shadi
18

Se me ocurrió un script bash muy simple. Gracias al autor de 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

Actualización: Agregue la clasificación por número de versión.

Timofey Stolbov
fuente
No pude llegar curlal trabajo, posiblemente debido a errores de certificado. wget --no-check-certificatefunciona, pero incluso curl -k --insecureno produce nada. La advertencia que recibo wgetdiceERROR: certificate common name `www.python.org´ doesn´t match requested host name `pypi.python.org´.
tripleee
El sort -Vno funciona en OSX con la versión de homebrew dejq
deepelement
16

Podría usar el paquete yolk3k en lugar de la yema. yolk3k es una bifurcación de la yema original y es compatible con python2 y 3.

https://github.com/myint/yolk

pip install yolk3k
ykyuen
fuente
Esto fue útil de saber, ya que la yema no funciona con Python 3.x
Broken Man el
1
yolk3k solo me devuelve la versión instalada:yolk -V attest Attest 0.5.3
Antony Hatchkins
2
parece que yolk3k solo devuelve la última versión?
mvherweg
16

Después de mirar el código de pip por un tiempo, parece que el código responsable de localizar paquetes se puede encontrar en la PackageFinderclase en pip.index. Su método find_requirementbusca las versiones de a InstallRequirement, pero desafortunadamente solo devuelve la versión más reciente.

El siguiente código es casi una copia 1: 1 de la función original, con el retorno en la línea 114 cambiado para devolver todas las versiones.

El script espera un nombre de paquete como primer y único argumento y devuelve todas las versiones.

http://pastebin.com/axzdUQhZ

No puedo garantizar la corrección, ya que no estoy familiarizado con el código de pip. Pero espero que esto ayude.

Salida de muestra

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

El código:

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
fuente
Esto funcionó mucho mejor que la respuesta anterior. skinny $ yolk -V scipy scipy 0.12.0 skinny $ python test.py scipy Versiones de 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
Este uso se desaconseja explícitamente en los documentos : " no debe utilizar las API internas de pip de esta manera "
wim
9

Puede usar este pequeño script Python 3 (usando solo módulos de biblioteca estándar) para obtener la lista de versiones disponibles para un paquete de PyPI usando la API JSON e imprimirlas en orden cronológico inverso. A diferencia de otras soluciones de Python publicadas aquí, esto no se rompe en versiones sueltas como django's 2.2rc1o 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')

Guarde el script y ejecútelo con el nombre del paquete como argumento, por ejemplo:

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
fuente
7

Esto funciona para mí en OSX:

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

Devuelve la lista una por línea:

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

O para obtener la última versión disponible:

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

Tenga en cuenta gsortque debe estar instalado (en OSX) para analizar las versiones. Puedes instalarlo conbrew install coreutils

abuela
fuente
Dios, ¿por qué publicaste esta respuesta? La respuesta de @Chris Montaro funciona y es elegante. Esto simplemente introduce complicaciones innecesariamente
Brian Leach
@BrianLeach smh ... es el mismo enfoque filtrado para usar en un script ...
abuela
1
Para mí funciona en cygwin / bash, para la segunda solución use sort, no gsort en cygwin.
WebComer
Aquí, Python produce posiblemente un código más legible que bash ... ver la respuesta de @eric chiang (con suerte :) arriba ...
mirekphd
4

Mi proyecto ludditetiene esta característica.

Ejemplo de uso:

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

Enumera todas las versiones de un paquete disponibles, consultando la API json de https://pypi.org/

wim
fuente
Sería más instructivo si nos dijera qué está haciendo su paquete, de lo contrario, solo está promocionando su software :)
user228395
@ user228395 Pensé que era bastante obvio, pero enumeraba todas las versiones de un paquete que estaba disponible, que era exactamente de lo que se pregunta el título de la pregunta. Editado - mejor?
wim
Su funcionamiento, por supuesto. Entonces, ¿está esencialmente envolviendo la solución presentada por @Timofey Stolbov?
user228395
1
@ user228395 No lo llamaría "envoltura", ya que esa respuesta usa bash, curl y jq, mientras que luddite solo usa la biblioteca estándar de Python (urllib). Pero la solución de Stolbov usa el mismo punto final en pypi.org . ¿Puedo preguntar cuál es el motivo de su voto negativo?
wim
1
Si siguió el enlace a la página de detalles del proyecto, podría ver que la característica principal del proyecto es verificar requirements.txtarchivos para paquetes obsoletos. Es más que un par de líneas de código. Para verificar un requirements.txtarchivo, necesita la funcionalidad para enumerar todas las versiones del paquete. Esta parte está desacoplada intencionalmente y es parte de la API pública de luddite. Y es la fuente Apache License 2.0, creo que no es justo llamarlo un paquete de software "caja negra".
wim
2

No tuve suerte con yolk, yolk3ko pip install -vasí que terminé usando esto (adaptado a Python 3 de la respuesta de Eric Chiang):

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
fuente
1
StrictVersionno va a funcionar para muchos paquetes ( django, uwsgi, psycopg2por nombrar algunos). Puede usar parse_version()desde setuptools(vea mi respuesta para ver un ejemplo).
Eugene Yarmash
1

La solución alternativa es usar las API de Warehouse:

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

Por ejemplo para Flask:

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

imprimirá:

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
fuente
0

bashScript simple que se basa solo en pythonsí mismo (supongo que en el contexto de la pregunta debe instalarse) y uno de curlo wget. Se supone que tiene un setuptoolspaquete instalado para ordenar las versiones (casi siempre instalado). No depende de dependencias externas como:

  • jq que puede no estar presente;
  • grepy awkeso puede comportarse de manera diferente en Linux y 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)))"

Una versión un poco más larga con comentarios.

Ponga el nombre del paquete en una variable:

PACKAGE=requests

Obtener versiones (usando 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)))")

Obtener versiones (usando 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)))")

Imprimir versiones ordenadas:

echo $VERSIONS
Andrey Semakin
fuente
-1

Mi opinión es una combinación de un par de respuestas publicadas, con algunas modificaciones para que sean más fáciles de usar desde un entorno de Python en ejecución.

La idea es proporcionar un comando completamente nuevo (modelado a partir del comando de instalación) que le brinde una instancia del buscador de paquetes para usar. La ventaja es que funciona y utiliza cualquier índice que pip admita y lea sus archivos de configuración de pip locales, de modo que obtenga los resultados correctos como lo haría con una instalación de pip normal.

Intenté hacer que sea compatible con pip v 9.xy 10.x, pero solo lo probé en 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())

Salida de ejemplo

./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
fuente
este uso se desaconseja explícitamente en los documentos : " no debe usar las API internas de pip de esta manera "
wim