【问题标题】:Python and pip, list all versions of a package that's available?Python 和 pip,列出可用包的所有版本?
【发布时间】:2011-02-03 15:24:30
【问题描述】:

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

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

【问题讨论】:

  • 接受的答案与脚本中的另一个答案不同,因为它们不会生成相同的输出。
  • 请更新所选答案。蛋黄坏了,不需要了。 pip install pylibmc== 的答案是完美的。
  • 请按照@Jonathan 的建议更新已接受的答案。我不会称它为完美,因为它不适用于早期版本的 pip(v7 或 v8),但除此之外非常好。
  • @Rory 请更新已接受的答案,蛋黄已死。 Chris Montanaro 的回答是目前 IMO 最好的方法。
  • @Rory 请更改已接受的答案,以便将来访问此热门问题的访问者受益。 Yolk 项目不再维护,它根本不像那个答案声称的那样工作。

标签: python pip


【解决方案1】:

对于 pip >= 21.2 使用:

pip index versions pylibmc

请注意,此命令是实验性的,将来可能会更改!

对于 pip >= 21.1 使用:

pip install pylibmc==

对于 pip >= 20.3 使用:

pip install --use-deprecated=legacy-resolver pylibmc==

对于 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==

将打印可用版本,而无需实际下载或安装任何软件包。

对于 pip 使用:

pip install pylibmc==blork

其中blork 可以是not a valid version number 的任何字符串。

【讨论】:

  • 我觉得奇怪的是 pip 的错误会吐出所有版本,但他们没有理由明确获取所述数据
  • 这应该被标记为正确答案,因为它不需要安装任何其他包。
  • 这似乎是在 pip 中执行此操作的唯一方法,这有点荒谬。我希望他们的错误跟踪器上至少有一个未解决的问题?
  • 我已经提交了 20.3 的问题:github.com/pypa/pip/issues/9252
  • 恢复旧行为的更好方法:pip install django== --use-deprecated=legacy-resolver
【解决方案2】:

(更新:截至 2020 年 3 月,许多人报告称,通过 pip install yolk3k 安装的 yolk 仅返回最新版本。Chris's answer 似乎获得了最多的支持,并且为我工作)

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

更好的全方位解决方案是使用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

yolk3k 是原始 yolk 的一个分支,它在 2012 中停止了开发。尽管 yolk 不再维护(如下面的 cmets 所示),yolk3k 似乎支持 Python 3。

注意:我不参与 yolk3k 的开发。 如果某些内容似乎无法正常工作,请在此处发表评论不会有太大影响。请改用yolk3k issue tracker,并考虑提交修复(如果可能)。

【讨论】:

  • 下面的答案(使用 pastebin 中的脚本)更麻烦,​​但至少在我的情况下有效(搜索 scipy 的版本)。 yolk 仅显示可用的最后一个版本,其他脚本显示可追溯到 0.8.0 的所有版本。
  • 大多数时候它只会返回最新版本
  • Fir python3 只需使用 pip install yolk3k。 yolk 命令将可用。
  • 和 yolk 一样,大多数时候 yolk3k 只返回最新版本。
  • 蛋黄坏了/不再维护。删除这个答案。
【解决方案3】:

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

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

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

import json
import urllib2
from distutils.version import StrictVersion

def versions(package_name):
    url = "https://pypi.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"))

该代码打印(截至 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

【讨论】:

  • JSON 有很多嵌套。我使用versions = [x for x in data["releases"] if any([y["python_version"] in ['cp26', '2.6'] for y in data["releases"][x]])] 来查找与 Python 2.6 兼容的版本。 (我在任何地方都没有看到cp26,但有些包有cp27,所以我推测这可能存在于其他包中。)
  • 这是一种使用 curl、jq 和 sort 的方法(“单线”!):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
  • 对于一些遵循不那么严格的版本控制方案的包,这会引发ValueError 异常。要为这些软件包修复它,see this gist.
  • outdated 会为你做这件事。
  • 令人讨厌的是 StrictVersion 不适用于名称中带有 dev 的软件包。
【解决方案4】:

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

使用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

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

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

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

用 pip 1.0 测试

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

【讨论】:

  • pip 1.5.4 提供DEPRECATION: --no-install, --no-download, --build, and --no-clean are deprecated. See https://github.com/pypa/pip/issues/906. 并且不显示已安装软件包的可用版本。
  • 显示所有版本,只需要-v。我的其余答案是为了避免附加效果(安装/下载)。对于已安装的 pkg,只需添加 --upgrade。 Anw,您可以创建一个单独的 virtualenv 以使一切变得更简单。
  • pip 9.0.1 吠声:no such option: --no-install
  • "newest of versions:" from -v 排除了一些版本。
【解决方案5】:

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

#!/bin/bash
set -e

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

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

更新:

  • 添加按版本号排序。
  • 添加 -L 以关注重定向。

【讨论】:

  • 我无法让curl 工作,可能是因为证书错误。 wget --no-check-certificate 有效,但即使curl -k --insecure 也无济于事。我收到wget 的警告说ERROR: certificate common name `www.python.org´ doesn´t match requested host name `pypi.python.org´.
  • sort -V 在 OSX 上无法使用自制版本的jq
  • @deepelement 当sort -V 不可用时,请参阅my answer 以了解解决方法。
  • 要让这个工作添加 -L 到 curl。 (跟随重定向)
【解决方案6】:

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

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

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

【讨论】:

  • 这个对我来说效果最好——它会生成一个有效版本号的排序列表。
【解决方案7】:

看了一会pip的代码,貌似可以在pip.indexPackageFinder类中找到负责定位包的代码。它的方法find_requirement 查找InstallRequirement 的版本,但不幸的是只返回最新版本。

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

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

http://pastebin.com/axzdUQhZ

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

样本输出

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

代码:

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]

【讨论】:

  • 这比上面的答案好很多。 skinny $ yolk -V scipy scipy 0.12.0 skinny $ python test.py scipy 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
  • the docs 明确不鼓励这种用法:“您不得以这种方式使用 pip 的内部 API
【解决方案8】:

你可以用 yolk3k 包代替 yolk。 yolk3k 是原始 yolk 的一个分支,它同时支持 python2 和 3。

https://github.com/myint/yolk

pip install yolk3k

【讨论】:

  • 这很容易知道,因为蛋黄在 python 3.x 下不起作用
  • yolk3k 只为我返回安装的版本:yolk -V attestAttest 0.5.3
  • yolk3k 好像只返回最新版本?
【解决方案9】:

您可以尝试安装确实存在的软件包版本。然后 pip 会列出可用的版本

pip install hell==99999
ERROR: Could not find a version that satisfies the requirement hell==99999
(from versions: 0.1.0, 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.4, 0.3.0,
0.3.1, 0.3.2, 0.3.3, 0.3.4, 0.4.0, 0.4.1)
ERROR: No matching distribution found for hell==99999

【讨论】:

  • 这是一个早先answer的骗子。
【解决方案10】:

这适用于我在 OSX 上:

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

它每行返回一个列表:

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

或获取可用的最新版本:

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

请记住 gsort 必须安装(在 OSX 上)才能解析版本。你可以用brew install coreutils安装它

【讨论】:

  • 天哪,你为什么还要发布这个答案。 @Chris Montaro 的回答很有效而且很优雅。这只是不必要地引入了复杂性
  • @BrianLeach smh...过滤后用于脚本的方法相同...
  • 为我在 cygwin / bash 中工作,第二个解决方案使用 sort,而不是 cygwin 中的 gsort。
  • 这里 python 产生的代码可以说是比 bash 更具可读性...见上面@eric chiang 的回复(希望是:)...
【解决方案11】:

我的项目luddite有这个功能。

示例用法:

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

它通过查询https://pypi.org/的json API列出了所有可用的包版本

【讨论】:

  • 如果你能告诉我们你的包在做什么会更有启发性,否则你只是在推广你的软件:)
  • @user228395 我认为这很明显,但它列出了可用包的所有版本,这正是问题标题所要求的。编辑 - 更好?
  • 当然是它的工作原理。所以它本质上是在包装@Timofey Stolbov 提出的解决方案?
  • @user228395 我不会称它为“包装”,因为该答案使用 bash、curl 和 jq - 而 luddite 只使用 Python 标准库 (urllib)。但是 Stolbov 的解决方案确实在 pypi.org 上使用了相同的端点。请问您投反对票的原因是什么?
  • 如果您点击链接到项目详细信息页面,您会看到该项目的主要功能是检查requirements.txt 文件中是否有过期包。它不仅仅是几行代码。为了检查requirements.txt 文件,您需要列出所有包版本的功能。这部分是有意解耦的,是 luddite 的公共 API 的一部分。而且它是 Apache License 2.0 的源代码,我认为将其称为“黑盒”软件包并不公平。
【解决方案12】:

我通常运行pip install packagename==somerandomstring。这将返回错误消息Could not find a version that satisfies the requirement packagename==somerandomstring,并且随着该错误,pip 还将列出服务器上的可用版本。

例如

$ pip install flask==aksjflashd
Collecting flask==aksjflashd
  Could not find a version that satisfies the requirement flask==aksjflashd 
(from versions: 0.1, 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, 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.12.5, 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.1.0, 1.1.1, 1.1.2)
No matching distribution found for flask==aksjflashd
$

如果像 'aksjflashd' 这样的随机字符串变成了实际的包版本,那你就非常倒霉了!

当然,pip download 也可以使用这个技巧。

【讨论】:

    【解决方案13】:

    更新

    也许不再需要该解决方案,请检查 cmets 到此答案。

    原答案

    对于 20.03 以上的 pip 版本,您可以使用旧求解器来取回所有可用版本:

    $ pip install  --use-deprecated=legacy-resolver pylibmc==
    ERROR: Could not find a version that satisfies the requirement pylibmc== (from    
    versions: 0.2, 0.3, 0.4, 0.5, 0.5.1, 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.6, 0.6.1,
    0.7, 0.7.1, 0.7.2, 0.7.3, 0.7.4, 0.8, 0.8.1, 0.8.2, 0.9, 0.9.1, 0.9.2, 1.0a0, 
    1.0b0, 1.0, 1.1, 1.1.1, 1.2.0, 1.2.1, 1.2.2, 1.2.3, 1.3.0, 1.4.0, 1.4.1, 
    1.4.2, 1.4.3, 1.5.0, 1.5.1, 1.5.2, 1.5.100.dev0, 1.6.0, 1.6.1)
    
    ERROR: No matching distribution found for pylibmc==
    

    【讨论】:

    • pip >= 21.1 中不再需要(见issue),不妨现在删除这个答案。
    【解决方案14】:

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

    【讨论】:

      【解决方案15】:

      pypi-version 包做得很好:

      $ pip3 install pip-versions
      
      $ pip-versions latest rsyncy
      0.0.4
      
      $ pip-versions list rsyncy
      0.0.1
      0.0.2
      0.0.3
      0.0.4
      

      这甚至可以在 Nexus (sonatype) 代理后面工作!

      【讨论】:

      【解决方案16】:

      替代解决方案是使用仓库 API:

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

      例如 Flask:

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

      将打印:

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

      【讨论】:

        【解决方案17】:

        我对@9​​87654322@、yolk3kpip 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
        ...
        

        【讨论】:

        • StrictVersion 不适用于许多软件包(djangouwsgipsycopg2 等等)。您可以使用 setuptools 中的 parse_version()(例如,请参阅我的 answer)。
        【解决方案18】:

        仅依赖于python 本身的简单bash 脚本(我假设在问题的上下文中应该安装它)和curlwget 之一。它假设您安装了setuptools 包来对版本进行排序(几乎总是安装)。它不依赖外部依赖,例如:

        • jq 可能不存在;
        • grepawk 在 Linux 和 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)))"
        

        带有 cmets 的稍长的版本。

        将包名放入变量中:

        PACKAGE=requests
        

        获取版本(使用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)))")
        

        获取版本(使用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)))")
        

        打印排序版本:

        echo $VERSIONS
        

        【讨论】:

          【解决方案19】:

          这是我对jq 中的列表进行排序的答案(适用于那些使用sort -V 不可用的系统的人):

          $ pythonPackage=certifi
          $ curl -Ls https://pypi.org/pypi/$pythonPackage/json | jq -r '.releases | keys_unsorted | sort_by( split(".") | map(tonumber) )'
            ............. 
            "2019.3.9",
            "2019.6.16",
            "2019.9.11",
            "2019.11.28",
            "2020.4.5",
            "2020.4.5.1",
            "2020.4.5.2",
            "2020.6.20",
            "2020.11.8"
          ]
          

          并获取包的最后一个版本号:

          $ curl -Ls https://pypi.org/pypi/$pythonPackage/json | jq -r '.releases | keys_unsorted | sort_by( split(".") | map(tonumber) )[-1]'
          2020.11.8
          

          或者快一点:

          $ curl -Ls https://pypi.org/pypi/$pythonPackage/json | jq -r '.releases | keys_unsorted | max_by( split(".") | map(tonumber) )'
          2020.11.8
          

          或者更简单:):

          $ curl -Ls https://pypi.org/pypi/$pythonPackage/json | jq -r .info.version
          2020.11.8
          

          【讨论】:

            【解决方案20】:

            适用于最新的 pip 版本,无需额外工具:

            pip install pylibmc== -v 2>/dev/null | awk '/Found link/ {print $NF}' | uniq
            

            【讨论】:

            • 这个比这里的许多替代方案要好,因为它使用可能与旧版本不同的新解析器。
            【解决方案21】:

            这是 Limmy+EricChiang 的 Py3.9+ 版本的解决方案。

            import json
            import urllib.request
            from distutils.version import StrictVersion
            
            
            # print PyPI versions of package
            def versions(package_name):
                url = "https://pypi.org/pypi/%s/json" % (package_name,)
                data = json.load(urllib.request.urlopen(url))
                versions = list(data["releases"])
                sortfunc = lambda x: StrictVersion(x.replace('rc', 'b').translate(str.maketrans('cdefghijklmn', 'bbbbbbbbbbbb')))
                versions.sort(key=sortfunc)
                return versions
            

            【讨论】:

              【解决方案22】:
              pypi-has() { set -o pipefail; curl -sfL https://pypi.org/pypi/$1/json | jq -e --arg v $2 'any( .releases | keys[]; . == $v )'; }
              

              用法:

              $ pypi-has django 4.0x ; echo $?
              false
              1
              
              $ pypi-has djangos 4.0x ; echo $?
              22
              
              $ pypi-has djangos 4.0 ; echo $?
              22
              
              $ pypi-has django 4.0 ; echo $?
              true
              0
              

              【讨论】:

                【解决方案23】:

                我的看法是结合了几个已发布的答案,并进行了一些修改以使其更易于在运行的 python 环境中使用。

                我们的想法是提供一个全新的命令(以 install 命令为模型),为您提供要使用的包查找器的实例。好处是它可以与 pip 支持并读取本地 pip 配置文件的任何索引一起使用和使用,因此您可以像使用普通 pip 安装一样获得正确的结果。

                我已尝试使其与 pip v 9.x 和 10.x 兼容。但仅在 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())
                

                示例输出

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

                【讨论】:

                • the docs 明确不鼓励这种用法:“您不得以这种方式使用 pip 的内部 API
                猜你喜欢
                • 2017-11-15
                • 2020-01-11
                • 1970-01-01
                • 2014-02-09
                • 2021-03-31
                • 2021-07-05
                • 2023-03-19
                • 2021-03-25
                • 1970-01-01
                相关资源
                最近更新 更多