No 3rd-party dependencies.
It's Asynchronous and Fast.
import asyncio, argparse, json, re, io
from collections import namedtuple
from typing import Iterable
import urllib.request
Package = namedtuple("Package", ["name", "version", "raw"])
placeholder = "{name:<30} {old_ver:10} {new_ver:<10}"
async def get_pypi_latest_version(package: Package) -> tuple[Package, Package]:
base_package, *_ = package.name.split("[")
with urllib.request.urlopen(f"https://pypi.org/pypi/{base_package}/json") as f:
data = json.loads(f.read())
version = data["info"]["version"]
latest_package = Package(package.name, version, f"{package.name}=={version}")
return package, latest_package
async def fetch_all_latest_packages(
packages: Iterable[Package],
) -> list[tuple[Package, Package]]:
coro = (get_pypi_latest_version(package) for package in packages)
new_packages = await asyncio.gather(*coro)
return [(old, new) for old, new in new_packages if old.version != new.version]
def read_packages(requirements_io: io.TextIOWrapper):
for line in requirements_io:
raw, *_ = line.split("#")
if not (raw := raw.strip()):
continue
package_name, *rest = re.split(r"<|=|>|\[\]", raw)
if not rest:
continue
*_, version = rest
yield Package(package_name, version, raw)
requirements_io.close()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Check for updated dependencies in requirements file."
)
parser.add_argument(
"filename",
type=argparse.FileType("r"),
help="requirements file",
)
args = parser.parse_args()
current_packages = list(read_packages(args.filename))
latest_packages = asyncio.run(fetch_all_latest_packages(current_packages))
if not latest_packages:
print("Everything upto date.")
exit(0)
print(placeholder.format(name="NAME", old_ver="OLD_VER", new_ver="NEW_VER"))
for old, new in latest_packages:
print(
placeholder.format(name=new.name, old_ver=old.version, new_ver=new.version)
)
$ python check_updates.py requirements.txt
NAME OLD_VER NEW_VER
Django 4.2.1 4.2.2
django-filter 23.1 23.2
psycopg 3.1.1 3.1.9
$ python check_updates.py -h
usage: check_updates.py [-h] filename
Check for updated dependencies in requirements file.
positional arguments:
filename requirements file
options:
-h, --help show this help message and exit
pip-compile -U requirements.txt
.pip install pip-review
. pypi.org/project/pip-review