Created
December 22, 2021 01:42
-
-
Save chipx86/5688b9a36453057c29b3e6c32743f52f to your computer and use it in GitHub Desktop.
Find the earliest available Python packages matching given dependency ranges
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Find the earliest available version of a list of Python dependencies. | |
This takes dependencies on the command line (package names with or without | |
version specifiers), looks up each in PyPI, and outputs a new list of | |
dependencies that specify the earliest version in each range. | |
See https://twitter.com/simonw/status/1473441058667130881 for the reason for | |
this script. | |
Example: | |
$ pypi-find-earliest.py dep1 'dep2~=X.Y' 'dep3>=1.2,<5.0' ... | |
$ pypi-find-earliest.py -f requirements.txt | |
""" | |
import sys | |
from pkg_resources import Requirement | |
from setuptools.package_index import PackageIndex | |
# Ideally we'd use argparse, but let's keep this simple. | |
if sys.argv[1] == '-r': | |
filename = sys.argv[2] | |
reqs = [] | |
try: | |
# This is absolutely not a perfect parser. It's very naive and will | |
# probably get tripped up easily. | |
# | |
# pip has a parser available in | |
# pip._internal.req.req_file.RequirementsFileParser, but that requires | |
# some pip session setup that I'm not bothering hacking around here. | |
# | |
# In the real world, you'll want to improve this block of code here. | |
with open(filename, 'r') as fp: | |
for line in fp.readlines(): | |
if line: | |
try: | |
req = Requirement.parse(line) | |
except ValueError: | |
# This line didn't parse, so we'll just ignore it. | |
# This isn't great. We might lose something. | |
continue | |
reqs.append(req) | |
except IOError as e: | |
sys.stderr.write('Unable to read %s: %s\n' % (filename, e)) | |
sys.exit(1) | |
else: | |
reqs = [ | |
Requirement.parse(_dep) | |
for _dep in sys.argv[1:] | |
] | |
index = PackageIndex() | |
for req in reqs: | |
index.find_packages(req) | |
# Normally, results will be in order of newest to oldest. We'll reverse | |
# that, and let the first that matches our requirement win. | |
for dist in reversed(index[req.key]): | |
if dist in req: | |
# First one wins. | |
print('%s==%s' % (dist.project_name, dist.version)) | |
break |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment