2025-06-08 18:44:40 +08:00
|
|
|
#!/usr/bin/env python3
|
2025-06-08 19:22:13 +08:00
|
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
|
|
|
# or more contributor license agreements. See the NOTICE file
|
|
|
|
|
# distributed with this work for additional information
|
|
|
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
|
|
|
# to you under the Apache License, Version 2.0 (the
|
|
|
|
|
# "License"); you may not use this file except in compliance
|
|
|
|
|
# with the License. You may obtain a copy of the License at
|
|
|
|
|
#
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
#
|
|
|
|
|
# Unless required by applicable law or agreed to in writing,
|
|
|
|
|
# software distributed under the License is distributed on an
|
|
|
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
|
# KIND, either express or implied. See the License for the
|
|
|
|
|
# specific language governing permissions and limitations
|
|
|
|
|
# under the License.
|
2025-06-08 18:44:40 +08:00
|
|
|
"""
|
|
|
|
|
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!")
|