Last active
October 28, 2021 08:35
-
-
Save guillermo-carrasco/009155650dd413b8807f159fded56cb7 to your computer and use it in GitHub Desktop.
Update all versions of a requirements.txt file to the latest ones (or just list the resulting file with -d)
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
import argparse | |
import logging | |
import re | |
import subprocess | |
import sys | |
from pathlib import Path | |
from typing import List | |
def fetch_latest_version(library): | |
# Calling pip install with a version that does not exist will trigger an error message that will list all available | |
# versions of the library. We can specify something that for sure does not exist in order to get that list | |
latest_version = str( | |
subprocess.run( | |
[sys.executable, "-m", "pip", "install", f"{library}==gibberish"], capture_output=True, text=True | |
) | |
) | |
versions_array_start = latest_version.find("(from versions: ") + len("(from versions: ") | |
versions_array_end = latest_version.find(")") | |
versions_array = latest_version[versions_array_start:versions_array_end].split(", ") | |
# Filter out release candidates, beta and alpha releases | |
versions_array_releases = [v for v in versions_array if not re.findall("[a-z]", v)] | |
# Some packages do not have a stable release at all. For these particular cases, choose the latest candidate | |
if not versions_array_releases: | |
return versions_array[-1] | |
else: | |
return versions_array_releases[-1] | |
def update_requirements(requirements_file: Path, skip_list: List[str], dry_run: bool): | |
print(skip_list) | |
with open(requirements_file, "r") as f: | |
requirements = f.readlines() | |
updated_requirements = [] | |
for line in requirements: | |
if re.match("^[a-z]", line): | |
# Some libraries might not be pinned to a specific version, in such case just pin it to the latest version | |
if "==" in line: | |
library, version = line.strip().split("==") | |
else: | |
library = line.strip() | |
version = None | |
if library not in skip_list: | |
latest_version = fetch_latest_version(library) | |
logging.debug( | |
f"Library: {library}: Current pinned version is {version}, latest version is {latest_version}" | |
) | |
if version != latest_version: | |
logging.info(f"Updating {library} to {latest_version} in requirements file") | |
line = f"{library}=={latest_version}\n" | |
updated_requirements.append(line) | |
if dry_run: | |
logging.info("".join(updated_requirements)) | |
else: | |
with open(requirements_file, "w") as f: | |
f.writelines(updated_requirements) | |
if __name__ == "__main__": | |
logging.getLogger().setLevel(logging.INFO) | |
parser = argparse.ArgumentParser(description="Update your requirements file to the latest versions") | |
parser.add_argument("requirements_file", type=Path) | |
parser.add_argument("--skip", type=str, default="", help="Comma-separated list of libraries to skip update for") | |
parser.add_argument( | |
"-d", "--dry-run", action="store_true", help="Do not actually update the file, but just output the result" | |
) | |
args = parser.parse_args() | |
skip_list = args.skip.split(",") | |
update_requirements(args.requirements_file, skip_list, args.dry_run) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment