Skip to content

Instantly share code, notes, and snippets.

@andreagrandi
Created October 8, 2024 15:38
Show Gist options
  • Save andreagrandi/e38c1854a2bc14ba389d106a57bc7b2d to your computer and use it in GitHub Desktop.
Save andreagrandi/e38c1854a2bc14ba389d106a57bc7b2d to your computer and use it in GitHub Desktop.
Check Python requirements compatibility
import os
import re
import requests
import argparse
def extract_package_names(file_content):
"""Extract package names from the requirements file content."""
package_names = []
# Regular expression to match package names (excluding the version part)
package_regex = re.compile(r'^([a-zA-Z0-9-_]+)==[0-9]+(?:\.[0-9]+)*(?:[-a-zA-Z0-9._]*)?$')
for line in file_content.splitlines():
line = line.strip()
# Ignore lines that start with -r (referencing another file)
if line.startswith('-r'):
continue
match = package_regex.match(line)
if match:
package_names.append(match.group(1))
return package_names
def get_package_info_from_pypi(package_name):
"""Fetch the package info from the PyPI API."""
url = f"https://pypi.org/pypi/{package_name}/json"
try:
response = requests.get(url)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f"Failed to fetch info for {package_name}: {e}")
return None
def check_python_support(package_info, version):
"""Check if the package supports the specified Python version."""
classifiers = package_info.get("info", {}).get("classifiers", [])
version_string = f"Programming Language :: Python :: {version}"
return version_string in classifiers
def parse_txt_files(paths):
"""Search all .txt files in the provided paths and extract package names."""
all_packages = []
for path in paths:
if not os.path.exists(path):
print(f"Path does not exist: {path}")
continue
# Walk through the directory to find all .txt files
for root, _, files in os.walk(path):
for file in files:
if file.endswith('.txt'):
file_path = os.path.join(root, file)
with open(file_path, 'r') as f:
content = f.read()
packages = extract_package_names(content)
all_packages.extend(packages)
return all_packages
def main():
# Set up argument parser
parser = argparse.ArgumentParser(description="Check package Python version support.")
parser.add_argument('-p', '--paths', nargs='+', required=True, help="Paths to search for .txt files")
parser.add_argument('-v', '--version', required=True, help="Python version to check support for (e.g., 3.12)")
args = parser.parse_args()
search_paths = args.paths
python_version = args.version
packages = parse_txt_files(search_paths)
if not packages:
print("No package names found.")
return
print(f"Total packages found: {len(packages)}")
no_python_support = []
for pkg in packages:
package_info = get_package_info_from_pypi(pkg)
if package_info:
if not check_python_support(package_info, python_version):
no_python_support.append(pkg)
# Calculate the percentage
total_packages = len(packages)
no_python_support_count = len(no_python_support)
percentage_no_python_support = (no_python_support_count / total_packages) * 100
print(f"\nPackages without Python {python_version} support:")
for pkg in no_python_support:
print(pkg)
print(f"\nTotal packages without Python {python_version} support: {no_python_support_count}")
print(f"Percentage of packages without Python {python_version} support: {percentage_no_python_support:.2f}%")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment