-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheck_dependencies.py
More file actions
148 lines (124 loc) · 5.92 KB
/
Copy pathcheck_dependencies.py
File metadata and controls
148 lines (124 loc) · 5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python3
"""
Local dependency checker for the vocabulary app.
Run this script to check for outdated dependencies and security issues.
Usage: python check_dependencies.py
"""
import subprocess
import sys
import json
import re
from typing import List, Dict, Any
def run_command(cmd: List[str]) -> tuple[bool, str]:
"""Run a command and return success status and output."""
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
return True, result.stdout
except subprocess.CalledProcessError as e:
return False, e.stderr
except FileNotFoundError:
return False, f"Command not found: {cmd[0]}"
def get_python_version() -> str:
"""Get current Python version."""
return f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
def check_python_compatibility(package_name: str, version: str) -> bool:
"""Check if a package version is compatible with current Python version.
Since we only support Python 3.12+, all modern packages should be compatible.
"""
# With Python 3.12+ requirement, all modern packages are compatible
if sys.version_info < (3, 12):
print(f"⚠️ Python {get_python_version()} detected. This project requires Python 3.12+")
return False
return True
def check_outdated_packages() -> None:
"""Check for outdated packages."""
print("🔍 Checking for outdated packages...")
success, output = run_command(["pip", "list", "--outdated", "--format=json"])
if success:
try:
outdated = json.loads(output)
if outdated:
print(f"📦 Found {len(outdated)} outdated packages:")
python_incompatible = []
for pkg in outdated:
print(f" 📦 {pkg['name']}: {pkg['version']} → {pkg['latest_version']}")
print("\nTo update all packages:")
print(" pip install --upgrade " + " ".join([pkg['name'] for pkg in outdated]))
else:
print("✅ All packages are up to date!")
except json.JSONDecodeError:
print("❌ Failed to parse outdated packages output")
else:
print(f"❌ Failed to check outdated packages: {output}")
def check_security_vulnerabilities() -> None:
"""Check for security vulnerabilities using pip-audit."""
print("\n🔒 Checking for security vulnerabilities...")
# Try pip-audit first
success, output = run_command(["pip-audit", "--desc", "--format=json"])
if success:
try:
audit_data = json.loads(output)
vulnerabilities = audit_data.get('vulnerabilities', [])
if vulnerabilities:
print(f"⚠️ Found {len(vulnerabilities)} security vulnerabilities:")
for vuln in vulnerabilities:
pkg = vuln.get('package', 'Unknown')
version = vuln.get('installed_version', 'Unknown')
desc = vuln.get('description', 'No description')
print(f" - {pkg} {version}: {desc}")
else:
print("✅ No security vulnerabilities found!")
except json.JSONDecodeError:
print("❌ Failed to parse security audit output")
else:
print("⚠️ pip-audit not available. Installing...")
install_success, _ = run_command(["pip", "install", "pip-audit"])
if install_success:
print("✅ pip-audit installed. Please run the script again.")
else:
print("❌ Failed to install pip-audit. You can install it manually with: pip install pip-audit")
def check_requirements_file() -> None:
"""Check if requirements.txt exists and analyze it."""
print(f"\n📋 Analyzing requirements.txt (Python {get_python_version()})...")
try:
with open("requirements.txt", "r") as f:
lines = f.readlines()
packages = [line.strip() for line in lines if line.strip() and not line.startswith("#")]
print(f"📦 Found {len(packages)} packages in requirements.txt")
# Check for version pinning
pinned = [pkg for pkg in packages if "==" in pkg]
unpinned = [pkg for pkg in packages if "==" not in pkg]
print(f" - {len(pinned)} packages with exact versions")
print(f" - {len(unpinned)} packages without exact versions")
# Verify Python 3.12+ requirement
if sys.version_info < (3, 12):
print(f"\n❌ This project requires Python 3.12+, but you're using {get_python_version()}")
print(" Please upgrade your Python version")
else:
print(f"\n✅ Python {get_python_version()} meets the 3.12+ requirement")
if unpinned:
print("⚠️ Consider pinning these packages for reproducible builds:")
for pkg in unpinned:
print(f" - {pkg}")
except FileNotFoundError:
print("❌ requirements.txt not found!")
def main():
"""Main function to run all checks."""
print("🔍 Vocab App Dependency Checker")
print("=" * 40)
check_requirements_file()
check_outdated_packages()
check_security_vulnerabilities()
print("\n💡 Recommendations:")
print(" 1. Review any security vulnerabilities and update affected packages")
print(" 2. Test your application after updating dependencies")
print(" 3. Consider using virtual environments for isolation")
print(" 4. Keep your requirements.txt file up to date")
print(" 5. Use Dependabot for automated dependency updates")
print(f" 6. Current Python version: {get_python_version()}")
if sys.version_info < (3, 12):
print(" 7. ❌ This project requires Python 3.12+. Please upgrade your Python version")
else:
print(" 7. ✅ Python version meets project requirements (3.12+)")
if __name__ == "__main__":
main()