Python 和 pip,列出可用包的所有版本?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4888027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 17:59:05  来源:igfitidea点击:

Python and pip, list all versions of a package that's available?

pythonpip

提问by Rory

Given the name of a Python package that can be installed with pip, is there any way to find out a list of all the possible versions of it that pip could install? Right now it's trial and error.

鉴于可以使用pip安装的 Python 包的名称,有没有办法找出 pip 可以安装的所有可能版本的列表?现在是反复试验。

I'm trying to install a version for a third party library, but the newest version is too new, there were backwards incompatible changes made. So I'd like to somehow have a list of all the versions that pip knows about, so that I can test them.

我正在尝试为第三方库安装一个版本,但最新版本太新,进行了向后不兼容的更改。所以我想以某种方式列出 pip 知道的所有版本,以便我可以测试它们。

采纳答案by m000

(update: As of March 2020, many people have reported that yolk, installed via pip install yolk3k, only returns latest version. Chris's answerseems to have the most upvotes and worked for me)

(更新:截至 2020 年 3 月,许多人报告说,通过 安装的 yolkpip install yolk3k仅返回最新版本 。Chris 的回答似乎获得了最多的赞成票并且对我有用)

The script at pastebin does work. However it's not very convenient if you're working with multiple environments/hosts because you will have to copy/create it every time.

pastebin 的脚本确实有效。但是,如果您使用多个环境/主机,这不是很方便,因为您每次都必须复制/创建它。

A better all-around solution would be to use yolk3k, which is available to install with pip. E.g. to see what versions of Django are available:

更好的全方位解决方案是使用yolk3k,它可以通过 pip 安装。例如,查看可用的 Django 版本:

$ 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

yolk3kis a fork of the original yolkwhich ceased development in 2012. Though yolkis no longer maintained (as indicated in comments below), yolk3kappears to be and supports Python 3.

yolk3k2012 年yolk停止开发的原始版本的分支。虽然不再维护(如下面的评论所示),但似乎支持 Python 3。yolkyolk3k

Note:I am not involved in the development of yolk3k. If something doesn't seem to work as it should, leaving a comment here should not make much difference.Use the yolk3k issue trackerinstead and consider submitting a fix, if possible.

注意:我没有参与 yolk3k 的开发。如果某些事情似乎没有按预期工作,那么在这里发表评论应该没有太大区别。使用yolk3k问题跟踪,而不是和考虑提出一个解决方法,如果可能的话。

回答by Reiner Gerecke

After looking at pip's code for a while, it looks like the code responsible for locating packages can be found in the PackageFinderclass in pip.index. Its method find_requirementlooks up the versions of a InstallRequirement, but unfortunately only returns the most recent version.

看了一会pip的代码,貌似PackageFinderpip.index. 它的方法find_requirement查找 a 的版本InstallRequirement,但不幸的是只返回最新版本。

The code below is almost a 1:1 copy of the original function, with the return in line 114 changed to return all versions.

下面的代码几乎是原始函数的 1:1 副本,将第 114 行中的返回更改为返回所有版本。

The script expects one package name as first and only argument and returns all versions.

该脚本需要一个包名作为第一个也是唯一的参数并返回所有版本。

http://pastebin.com/axzdUQhZ

http://pastebin.com/axzdUQhZ

I can't guarantee for the correctness, as I'm not familiar with pip's code.But hopefully this helps.

我不能保证正确性,因为我不熟悉 pip 的代码。但希望这会有所帮助。

Sample output

样本输出

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

The code:

编码:

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]

回答by m0she

https://pypi.python.org/pypi/Django/- works for packages whose maintainers choose to show all packages https://pypi.python.org/simple/pip/- should do the trick anyhow (lists all links)

https://pypi.python.org/pypi/Django/- 适用于维护者选择显示所有包的包 https://pypi.python.org/simple/pip/- 无论如何都应该做到这一点(列出所有链接)

回答by HVNSweeting

Update:
As of Sep 2017 this method no longer works: --no-installwas removed in pip 7

更新:
截至 2017 年 9 月,此方法不再有效:--no-install已在 pip 7 中删除

Use pip install -v, you can see all versions that available

使用pip install -v,可以看到所有可用的版本

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

To not install any package, use one of following solution:

要不安装任何软件包,请使用以下解决方案之一:

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

or

或者

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

Tested with pip 1.0

使用 pip 1.0 测试

root@node7:~# pip --version
pip 1.0 from /usr/lib/python2.7/dist-packages (python 2.7)

回答by ykyuen

You could the yolk3k package instead of yolk. yolk3k is a fork from the original yolk and it supports both python2 and 3.

您可以使用 yolk3k 包而不是 yolk。yolk3k 是原始 yolk 的一个分支,它同时支持 python2 和 3。

https://github.com/myint/yolk

https://github.com/myint/yolk

pip install yolk3k

回答by Chris Montanaro

For pip >= 9.0use

对于pip >= 9.0使用

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

– all the available versions will be printed without actually downloading or installing any additional packages.

– 无需实际下载或安装任何其他软件包即可打印所有可用版本。

For pip < 9.0use

对于pip < 9.0使用

pip install pylibmc==blork

where blorkcan be any string that is not a valid version number.

whereblork可以是任何不是有效版本号的字符串。

回答by eric chiang

You don't need a third party package to get this information. pypi provides simple JSON feeds for all packages under

您不需要第三方包来获取此信息。pypi 为下面的所有包提供简单的 JSON 提要

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

Here's some Python code using only the standard library which gets all versions.

这是一些仅使用获取所有版本的标准库的 Python 代码。

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

That code prints (as of Feb 23rd, 2015):

该代码打印(截至 2015 年 2 月 23 日):

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

回答by Andrew Magee

I didn't have any luck with yolk, yolk3kor pip install -vbut so I ended up using this (adapted to Python 3 from eric chiang's answer):

我没有任何运气yolkyolk3k或者pip install -v所以我最终使用了它(根据 eric chiang 的回答改编为 Python 3):

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

回答by Timofey Stolbov

I came up with dead-simple bash script. Thanks to jq's author.

我想出了非常简单的 bash 脚本。感谢jq的作者。

#!/bin/bash
set -e

PACKAGE_JSON_URL="https://pypi.org/pypi//json"

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

Update:Add sorting by version number.

更新:添加按版本号排序。

回答by Eugene Yarmash

You can use this small Python 3 script (using only standard library modules) to grab the list of available versions for a package from PyPI using JSON APIand print them in reverse chronological order. Unlike some other Python solutions posted here, this doesn't break on loose versions like django's 2.2rc1or uwsgi's 2.0.17.1:

您可以使用这个小的 Python 3 脚本(仅使用标准库模块)从使用JSON API 的PyPI 获取包的可用版本列表,并按时间倒序打印它们。与此处发布的其他一些 Python 解决方案不同,这不会在诸如django's2.2rc1uwsgi'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')

Save the script and run it with the package name as an argument, e.g.:

保存脚本并使用包名作为参数运行它,例如:

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