Created
August 16, 2024 12:05
-
-
Save mgaitan/7d75ff2dc7063e67639a6568151d65f3 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/env python | |
# /// script | |
# requires-python = ">=3.11" | |
# dependencies = [ | |
# "pip-requirements-parser", | |
# "rich", | |
# ] | |
# /// | |
""" | |
This script compares two Python requirements files, providing a set of operations to analyze the differences and commonalities between them. | |
Usage: | |
$ pip install pip-requirements-parser | |
$ python compare_reqs.py <path_to_first_requirements_file> <path_to_second_requirements_file> [--operation <operation>] | |
Arguments: | |
<path_to_first_requirements_file> : The file path to the first requirements file to be compared. | |
<path_to_second_requirements_file> : The file path to the second requirements file to be compared. | |
Options: | |
-o, --operation <operation> : Specify the set operation to perform. Choices are: | |
- "intersection": Shows packages present in both files. | |
- "diff1": Shows packages present in the first file (r1) but not in the second file (r2). | |
- "diff2": Shows packages present in the second file (r2) but not in the first file (r1). | |
Default is "intersection". | |
Output: | |
The script outputs a table with the results of the specified operation. The table includes the package name and version (if available) from both requirements files. The comparison is color-coded: | |
- Green: The versions match in both files. | |
- Red: The versions differ between the files or the package is only present in one of them. | |
Dependencies: | |
- pip-requirements-parser: A package used to parse the requirements files. | |
- rich: A package for formatting and displaying rich text, tables, and other elements in the console. | |
If you run this via `uv run` these are automatically installed. | |
Example: | |
To compare two requirements files and find the intersection: | |
$ python compare_reqs.py requirements1.txt requirements2.txt --operation intersection | |
To find packages in the first file that are not in the second: | |
$ python compare_reqs.py requirements1.txt requirements2.txt --operation diff1 | |
To find packages in the second file that are not in the first: | |
$ python compare_reqs.py requirements1.txt requirements2.txt --operation diff2 | |
""" | |
import argparse | |
from pip_requirements_parser import RequirementsFile | |
from rich.console import Console | |
from rich.table import Table | |
# Create the argument parser | |
parser = argparse.ArgumentParser(description="Compare two requirement files.") | |
# Add arguments for file paths | |
parser.add_argument("r1_path", type=str, help="Path to the first requirements file") | |
parser.add_argument("r2_path", type=str, help="Path to the second requirements file") | |
parser.add_argument( | |
"-o", | |
"--operation", | |
default="intersection", | |
choices=["intersection", "diff1", "diff2"], | |
help="Set operation to perform: intersection, diff1 (r1 not in r2), diff2 (r2 not in r1)", | |
) | |
# Parse the arguments | |
args = parser.parse_args() | |
# Use the provided file paths | |
r1 = RequirementsFile.from_file(args.r1_path) | |
r2 = RequirementsFile.from_file(args.r2_path) | |
# Convert the requirements to dictionaries | |
r1_dict = { | |
r["name"]: r["specifier"][0].replace("==", "") if r["specifier"] else "" for r in r1.to_dict()["requirements"] | |
} | |
r2_dict = { | |
r["name"]: r["specifier"][0].replace("==", "") if r["specifier"] else "" for r in r2.to_dict()["requirements"] | |
} | |
if args.operation == "intersection": | |
title = "Packages in both files" | |
result_keys = set(r2_dict) & set(r1_dict) | |
elif args.operation == "diff1": | |
title = "Packages in r1 and not r2" | |
result_keys = set(r1_dict) - set(r2_dict) | |
elif args.operation == "diff2": | |
title = "Packages in r2 and not r1" | |
result_keys = set(r2_dict) - set(r1_dict) | |
comparison_result = {pkg: (r1_dict.get(pkg, ''), r2_dict.get(pkg, "")) for pkg in result_keys} | |
table = Table(title=title) | |
table.add_column("Package") | |
table.add_column(args.r1_path) | |
table.add_column(args.r2_path) | |
# Print the sorted comparison results | |
for p, (v1, v2) in sorted(comparison_result.items()): | |
color = "green" if v1 == v2 else "red" | |
table.add_row(f"[{color}]{p}[/{color}]", v1, v2) | |
console = Console() | |
console.print(table) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment