pip3 - Python y pip, ¿enumera todas las versiones de un paquete que está disponible?
pip version (18)
Acabo de ejecutar esto:
pip show packagename
p.ej:
> pip3 show setuptools
---
Metadata-Version: 2.0
Name: setuptools
Version: 18.4
Summary: Easily download, build, install, upgrade, and uninstall Python packages
Home-page: https://bitbucket.org/pypa/setuptools
Author: Python Packaging Authority
Author-email: [email protected]
License: PSF or ZPL
Location: /usr/local/lib/python3.4/site-packages
Requires:
Dado el nombre de un paquete Python (2.X) que se puede instalar con pip y virtualenv , ¿hay alguna forma de encontrar una lista de todas las versiones posibles que podría instalar pip? Ahora mismo es prueba y error.
Estoy intentando instalar una versión para una biblioteca de terceros, pero la versión más reciente es demasiado nueva, se hicieron cambios incompatibles hacia atrás. Así que me gustaría tener de alguna manera una lista de todas las versiones que conoce pip, para poder probarlas.
Aquí está el método actual basado en pip de Python, buscando la API del paquete PyPi heredado:
from pip import index
import requests
finder = index.PackageFinder(
[],
[''https://pypi.python.org/simple''],
session=requests.Session()
)
results = finder.find_all_candidates("package_name")
versions = [p.version for p in results]
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 clase pip.index
en pip.index
. Su método find_requirement
busca las versiones de un InstallRequirement
, pero desafortunadamente solo devuelve la versión más reciente.
El código a continuación 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.
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]
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 solución más completa sería utilizar yolk , 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
Una advertencia menor: la yema depende de la distribución. Esto no es algo malo, pero puede ser un problema si necesita, por algún motivo, seguir con las herramientas de configuración de Python (desaprobadas).
Nota: No estoy involucrado en el desarrollo de la yema. Si algo no parece funcionar como debería, dejar un comentario aquí no debería hacer mucha diferencia. Utilice el rastreador de problemas de la yema en su lugar y considere enviar una solución, si es posible.
Esto me funciona en OSX:
pip install docker-compose== 2>&1 | grep -oE ''(/(.*/))'' | awk -F:/ ''{print$NF}'' | sed -E ''s/( |/))//g'' | tr '','' ''/n''
Devuelve la lista uno por línea:
1.10.0rc2
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
pip install django == x
Tenga en cuenta que gsort
tiene que estar instalado (en OSX) para analizar las versiones. Puedes instalarlo con brew install coreutils
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 después del comando de instalación) que le dé una instancia del buscador de paquetes para usar. La ventaja es que funciona con, y utiliza, cualquier índice que pip admite y lee sus archivos de configuración de pip locales, por lo que obtiene los resultados correctos como lo haría con una instalación pip normal.
Intenté hacerlo compatible con pip v 9.xy 10.x .. pero solo lo probé con 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())
Ejemplo de salida
$ ./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
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 algunos códigos Python que usan 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
No tuve suerte con yolk
, yolk3k
o pip install -v
pero terminé usando esto (adaptado a Python 3 de la respuesta de eric chiang):
$ pip install --no-deps Django==x.x.x
Collecting Django==x.x.x.
Could not find a version that satisfies the requirement Django==x.x.x. (from versions: 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.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.8a1, 1.8b1, 1.8b2, 1.8rc1, 1.8, 1.8.1, 1.8.2)
No matching distribution found for Django==x.x.x.
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 ni instalar ningún paquete adicional.
Para pip <9.0 use
pip install pylibmc==blork
donde blork
puede ser cualquier cadena que no es probable que sea un candidato de instalación.
Pip 7.1.0 ha eliminado la opción --no instalar desde la instalación. Encontré un método para obtener todas las versiones de un paquete sin ningún paquete adicional.
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
Podrías el paquete yolk3k en lugar de yolk. yolk3k es un tenedor de la yema original y es compatible con python2 y 3.
pip install yolk3k
Puede usar este breve fragmento de Python3 para obtener la lista de versiones disponibles para un paquete de PyPI . A diferencia de otras soluciones de Python publicadas aquí, esto no se rompe en versiones sueltas como 1.10rc1
django
o uwsgi
de 2.0.13.1
:
>>> import requests
>>> from pkg_resources import parse_version
>>>
>>> def versions(name):
... url = "https://pypi.python.org/pypi/{}/json".format(name)
... return sorted(requests.get(url).json()["releases"], key=parse_version)
...
>>> print(*reversed(versions("Django")), sep="/n")
1.10.3
1.10.2
1.10.1
1.10
1.10rc1
1.10b1
1.10a1
...
Sé que esto es un poco tonto pero puedes intentar algo como esto:
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
...
Esto producirá un error pero mostrará una lista de todas las versiones disponibles para este paquete.
Simplemente reemplace django
con el paquete que desea y también creo que, con suerte, no existe tal versión llamada x.
Se me ocurrió el guión de bash muerto simple. Gracias al autor de jq .
#!/bin/bash
set -e
PACKAGE_JSON_URL="https://pypi.python.org/pypi/${1}/json"
curl -s "$PACKAGE_JSON_URL" | jq -r ''.releases | keys | .[]'' | sort -V
Actualización: Añadir clasificación por número de versión.
Una solución alternativa es utilizar las API de almacén:
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''])
puedes grep el resultado de tu pip list
-> % pip list | grep ''beautifulsoup4''
beautifulsoup4 (4.4.1)
https://pypi.python.org/pypi/Django/ - funciona para paquetes cuyos mantenedores eligen mostrar todos los paquetes https://pypi.python.org/simple/pip/ - deberían hacer el truco de todos modos (enumera todos los enlaces)
Actualizar:
A partir de septiembre de 2017, este método ya no funciona: --no-install
en la pip 7
Use pip install -v
, puede ver todas las versiones que están 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)