如何获取特定日期之前发布的 python 软件包的版本号列表?

问题描述 投票:0回答:4

考虑使用一个包含(未版本控制的)依赖项(python 包)列表的 python

requirements.txt
文件。安装它们后(例如
pip install -r requirements.txt
),您可以调用
pip freeze
并获取所有已安装Python包的(版本)列表。

这将是当时可用的 python 包版本(及其依赖项)的快照。我需要生成的是相同的列表,但是是过去的日期(比如说

2018-06-12
)。

我想从技术上来说,我只需要找到

requirements.txt
文件中包含的所有软件包的发布版本。

理想情况下,会有一个命令

pip install -r requirements.txt --before 2018-06-21
,然后调用
pip freeze
,但我在
pip install --help
中没有看到类似的东西。我确实找到了一种指定另一个
--index-url
的方法,我可以想象如果有一个从该日期开始的 archived 索引,我可以将
pip
指向它,它应该可以工作吗?

还有一个

--constraint
选项,其中:

使用给定的约束文件约束版本

但我猜在这种情况下我已经必须拥有日期约束版本了?

python pip dependencies python-packaging
4个回答
7
投票

从你的问题来看,如果我猜对了,你想使用以下命令安装依赖项:

pip install -r requirements.txt --before 2018-06-21

需要修补

pip
本身,以便添加
--before
选项来提供目标日期。

下面的代码是第二好的。目前它是一个粗略的草图,但它几乎可以满足您的需要,而不是生成

requirements.txt
,而是将最新版本的软件包输出到控制台,直到提供的日期为止,格式为:

$ pipenv run python <script_name>.py django click --before 2018-06-21
pip install django==2.0.6 click==6.7

这并不完全是你的想法,但非常接近。请随意根据您的需要更改它,通过添加(或不添加)

-r
选项并输出新行上的每个依赖项,然后使用重定向输出,它看起来像这样:

$ pipenv run python <script_name>.py django click --before 2018-06-21 >> requirements.txt

代码(或仅使用gist的链接):

import sys
import requests
from bs4 import BeautifulSoup
from datetime import datetime
import click

PYPI_URL = "https://pypi.org/project/{project_name}/#history"

def get_releases(request):

    soup = BeautifulSoup(request, 'html.parser')
    releases = list()

    for release in soup.find_all('div', class_='release'):
        release_version = release.find('p', class_='release__version').text.strip()
        if not is_numeric(release_version):
            continue
        release_date = try_parsing_date(release.find('time').text.strip())
        releases.append({'version': release_version, 'date': release_date})

    sorted_packages = sorted(releases, key=lambda s: list(map(int, s['version'].split('.'))))

    return sorted_packages


def is_numeric(s):
    for char in s:
        if not char.isdigit() and char not in [" ", ".", ","]:
            return False

    return True


def try_parsing_date(text):
    for fmt in ('%d.%m.%Y', '%d/%m/%Y', '%b %d, %Y', '%Y-%m-%d'):
        try:
            return datetime.strptime(text, fmt)
        except ValueError:
            pass
    click.echo('Not valid date format. Try to use one of this: <31.12.2018>, <31/12/2019> or <2018-12-31>')
    sys.exit(0)


@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('-b', '--before', help='Get latest package before specified date')
@click.argument('packages', nargs=-1, type=click.UNPROCESSED)
def cli(before, packages):
    target_date = try_parsing_date(before) if before else datetime.today()

    required_packages = list()
    not_found = list()

    for package in packages:
        project_url = PYPI_URL.format(project_name=package)
        r = requests.get(project_url)
        if r.status_code is not 200:
            not_found.append(package)
            continue

        releases = get_releases(r.text)
        last_release = None
        for idx, release in enumerate(releases):
            release_date = release['date']
            if release_date > target_date:
                if last_release and last_release['date'] <= release_date:
                    continue
            last_release = release

        required_packages.append({'package': package,
                                  'release_date': last_release['date'],
                                  'release_version': last_release['version']})


    print('pip install ' + ' '.join('{}=={}'.format(p['package'], str(p['release_version'])) for p in required_packages))
    if len(not_found) > 0:
        print('\nCould not find the following packages: {}'.format(' '.join(p for p in not_found)))

if __name__ == '__main__':
    cli()

所需的依赖项(Python3):

beautifulsoup4==4.7.1
Click==7.0
requests==2.21.0

1
投票

我找到了一个似乎可以满足您需求的工具(仍处于测试阶段): https://pypi.org/project/pypi-timemachine/

正如我从其自述文件中读到的那样,它创建了一个使用日期过滤器的 pypi.org 代理。


0
投票

好吧,一个可能的答案(尽管不是一个很好的答案)是手动浏览

requirements.txt
中的每个依赖项,在 https://pypi.org 上查找该包,然后访问发布历史记录(例如 https://pypi.org/project/requests/#history)。从那里很容易看出哪个版本在什么日期发布(例如,https://pypi.org/project/requests/2.19.0/ 表示
requests
当包含
2018-06-12
时),然后使用它作为版本(
requests==2.19.0
)。

一个稍微好一点的答案可能是以编程方式从 pypi 中提取该信息(可能通过

curl
),提取所有版本信息(包括日期),对其进行排序并选择正确的。


0
投票

这是一个使用

uv
的巧妙解决方案。 您可以使用
pip install uv
安装它。

假设您想要安装软件包

rvc3python
,其依赖项不晚于 2023 年 11 月 13 日。 就像运行这个一样简单:

uv pip install --exclude-newer 2023-11-13T10:00:00Z rvc3python

如果您有需求文件,请查看

uv pip install -r ...

© www.soinside.com 2019 - 2024. All rights reserved.