153 lines
5.3 KiB
Python
153 lines
5.3 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Generate requirements.txt from pyproject.toml
|
||
|
|
Ensures consistency in dependency management
|
||
|
|
"""
|
||
|
|
|
||
|
|
import re
|
||
|
|
import toml
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
def generate_requirements():
|
||
|
|
"""Generate requirements.txt from pyproject.toml"""
|
||
|
|
|
||
|
|
# Read pyproject.toml
|
||
|
|
try:
|
||
|
|
with open('pyproject.toml', 'r', encoding='utf-8') as f:
|
||
|
|
pyproject = toml.load(f)
|
||
|
|
except FileNotFoundError:
|
||
|
|
print("❌ pyproject.toml not found")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
# Get main dependencies
|
||
|
|
dependencies = pyproject.get('project', {}).get('dependencies', [])
|
||
|
|
|
||
|
|
# Get development dependencies
|
||
|
|
dev_dependencies = pyproject.get('project', {}).get('optional-dependencies', {}).get('dev', [])
|
||
|
|
|
||
|
|
# Generate requirements.txt
|
||
|
|
requirements_content = []
|
||
|
|
|
||
|
|
# Add header comment
|
||
|
|
requirements_content.append("# Main dependencies - auto-generated from pyproject.toml")
|
||
|
|
requirements_content.append("# Do not edit this file manually, use 'python generate_requirements.py' to regenerate")
|
||
|
|
requirements_content.append("")
|
||
|
|
|
||
|
|
# Add main dependencies
|
||
|
|
requirements_content.append("# === Core Dependencies ===")
|
||
|
|
for dep in dependencies:
|
||
|
|
requirements_content.append(dep)
|
||
|
|
|
||
|
|
requirements_content.append("")
|
||
|
|
requirements_content.append("# === Development Dependencies ===")
|
||
|
|
for dep in dev_dependencies:
|
||
|
|
requirements_content.append(dep)
|
||
|
|
|
||
|
|
# Write requirements.txt
|
||
|
|
with open('requirements.txt', 'w', encoding='utf-8') as f:
|
||
|
|
f.write('\n'.join(requirements_content))
|
||
|
|
|
||
|
|
print(f"✅ Generated requirements.txt")
|
||
|
|
print(f" Main dependencies: {len(dependencies)} items")
|
||
|
|
print(f" Dev dependencies: {len(dev_dependencies)} items")
|
||
|
|
|
||
|
|
def generate_requirements_dev():
|
||
|
|
"""Generate requirements-dev.txt (only development dependencies)"""
|
||
|
|
|
||
|
|
pyproject_path = Path("pyproject.toml")
|
||
|
|
if not pyproject_path.exists():
|
||
|
|
print("Error: pyproject.toml not found")
|
||
|
|
return
|
||
|
|
|
||
|
|
with open(pyproject_path, 'r', encoding='utf-8') as f:
|
||
|
|
data = toml.load(f)
|
||
|
|
|
||
|
|
# Get development dependencies
|
||
|
|
dev_dependencies = data.get('project', {}).get('optional-dependencies', {}).get('dev', [])
|
||
|
|
|
||
|
|
# Generate requirements-dev.txt
|
||
|
|
content = []
|
||
|
|
content.append("# Development dependencies - auto-generated from pyproject.toml")
|
||
|
|
content.append("# Installation command: pip install -r requirements-dev.txt")
|
||
|
|
content.append("")
|
||
|
|
|
||
|
|
for dep in dev_dependencies:
|
||
|
|
content.append(dep)
|
||
|
|
|
||
|
|
# Write file
|
||
|
|
dev_requirements_path = Path("requirements-dev.txt")
|
||
|
|
with open(dev_requirements_path, 'w', encoding='utf-8') as f:
|
||
|
|
f.write('\n'.join(content))
|
||
|
|
|
||
|
|
print(f"✅ Generated requirements-dev.txt ({len(dev_dependencies)} development dependencies)")
|
||
|
|
|
||
|
|
def verify_consistency():
|
||
|
|
"""Verify dependency consistency"""
|
||
|
|
|
||
|
|
def extract_packages_from_requirements():
|
||
|
|
"""Extract package names from requirements.txt"""
|
||
|
|
packages = set()
|
||
|
|
try:
|
||
|
|
with open('requirements.txt', 'r') as f:
|
||
|
|
for line in f:
|
||
|
|
line = line.strip()
|
||
|
|
if line and not line.startswith('#'):
|
||
|
|
# Extract package name (remove version)
|
||
|
|
pkg = re.split(r'[>=<\[]', line)[0].strip()
|
||
|
|
if pkg:
|
||
|
|
packages.add(pkg.lower())
|
||
|
|
except FileNotFoundError:
|
||
|
|
print("requirements.txt not found")
|
||
|
|
return packages
|
||
|
|
|
||
|
|
def extract_packages_from_pyproject():
|
||
|
|
"""Extract package names from pyproject.toml"""
|
||
|
|
packages = set()
|
||
|
|
try:
|
||
|
|
with open('pyproject.toml', 'r') as f:
|
||
|
|
data = toml.load(f)
|
||
|
|
|
||
|
|
# Get main dependencies
|
||
|
|
dependencies = data.get('project', {}).get('dependencies', [])
|
||
|
|
for dep in dependencies:
|
||
|
|
pkg = re.split(r'[>=<\[]', dep)[0].strip()
|
||
|
|
if pkg:
|
||
|
|
packages.add(pkg.lower())
|
||
|
|
|
||
|
|
# Get development dependencies
|
||
|
|
dev_deps = data.get('project', {}).get('optional-dependencies', {}).get('dev', [])
|
||
|
|
for dep in dev_deps:
|
||
|
|
pkg = re.split(r'[>=<\[]', dep)[0].strip()
|
||
|
|
if pkg:
|
||
|
|
packages.add(pkg.lower())
|
||
|
|
|
||
|
|
except FileNotFoundError:
|
||
|
|
print("pyproject.toml not found")
|
||
|
|
return packages
|
||
|
|
|
||
|
|
req_packages = extract_packages_from_requirements()
|
||
|
|
toml_packages = extract_packages_from_pyproject()
|
||
|
|
|
||
|
|
only_in_req = req_packages - toml_packages
|
||
|
|
only_in_toml = toml_packages - req_packages
|
||
|
|
|
||
|
|
if len(only_in_req) == 0 and len(only_in_toml) == 0:
|
||
|
|
print("✅ Dependency consistency verification passed!")
|
||
|
|
return True
|
||
|
|
else:
|
||
|
|
print("⚠️ Found dependency inconsistencies:")
|
||
|
|
if only_in_req:
|
||
|
|
print(f" Only in requirements.txt: {sorted(only_in_req)}")
|
||
|
|
if only_in_toml:
|
||
|
|
print(f" Only in pyproject.toml: {sorted(only_in_toml)}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
print("🔄 Generating requirements.txt from pyproject.toml...")
|
||
|
|
generate_requirements()
|
||
|
|
generate_requirements_dev()
|
||
|
|
print()
|
||
|
|
print("🔍 Verifying dependency consistency...")
|
||
|
|
verify_consistency()
|
||
|
|
print("✨ Completed!")
|