Files
Projektarbeit-MYP/backend/cleanup_imports.py
Till Tomczak 7a99af7ace 🎉 Feat: Import & Function Analysis Tool Enhancements 🎉
This commit introduces a suite of tools for analyzing and optimizing imports and functions within the backend codebase. The following files have been updated:

- backend/FRONTEND_ASSETS_ANALYSE.md
- backend/REDUNDANZ_ANALYSE_FINAL.md
- backend/SOFORT_L\303\226SCHBARE_FUN
2025-06-19 18:13:18 +02:00

325 lines
13 KiB
Python

#!/usr/bin/env python3
"""
Automatische Bereinigung von ungenutzten Imports im MYP Backend
Dieser Script bereinigt sichere, ungenutzte Imports automatisch und
erstellt ein Backup vor den Änderungen.
"""
import os
import re
import shutil
import ast
from pathlib import Path
from datetime import datetime
from typing import List, Dict, Set, Tuple
class ImportCleaner:
def __init__(self, backend_path: str):
self.backend_path = Path(backend_path)
self.backup_dir = self.backend_path / f"backup_imports_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
self.changes = []
# Sichere Imports die entfernt werden können (niedrige Fehlerwahrscheinlichkeit)
self.safe_unused_imports = {
# Typing imports (fast immer sicher zu entfernen)
'typing.Set', 'typing.Tuple', 'typing.List', 'typing.Dict', 'typing.Any',
'typing.Optional', 'typing.Union', 'typing.Callable',
# Standard library (meist sicher wenn ungenutzt)
'pathlib.Path', 'enum.Enum', 'dataclasses.dataclass', 'dataclasses.asdict',
'collections.defaultdict', 'collections.Counter',
# Entwicklungs-spezifische imports
'rich.console.Console', 'rich.table.Table', 'rich.panel.Panel',
'rich.progress.Progress', 'rich.text.Text',
'faker.Faker', 'bs4.BeautifulSoup',
# Selenium (oft in Test-Dateien ungenutzt)
'selenium.common.exceptions.TimeoutException',
'selenium.common.exceptions.WebDriverException',
'selenium.common.exceptions.NoSuchElementException',
'selenium.webdriver.firefox.service.Service',
'selenium.webdriver.chrome.service.Service',
'selenium.webdriver.support.expected_conditions',
'selenium.webdriver.common.by.By',
'selenium.webdriver.support.ui.WebDriverWait',
'selenium.webdriver.chrome.options.Options',
'selenium.webdriver.firefox.options.Options',
# WTForms (sicher wenn nicht in Templates verwendet)
'wtforms.validators.NumberRange', 'wtforms.validators.Optional',
'wtforms.validators.DataRequired', 'wtforms.validators.Email',
'wtforms.TextAreaField', 'wtforms.IntegerField', 'wtforms.StringField',
'wtforms.SelectField',
}
# Dateien die NUR automatisch bereinigt werden (niedrige Kritikalität)
self.safe_files = {
'template_analysis_tool.py',
'template_validation_final.py',
'template_problem_analysis.py',
'import_analyzer.py',
'form_test_automator.py',
'simple_form_tester.py',
'test_flask_minimal.py',
'scripts/screenshot_tool.py',
'scripts/quick_unicode_fix.py',
'scripts/test_protocol_generator.py',
'ssl/ssl_fix.py',
'ssl/fix_ssl_browser.py',
'static/icons/generate_icons.py',
}
def create_backup(self):
"""Erstellt Backup aller Python-Dateien"""
print(f"Erstelle Backup in: {self.backup_dir}")
self.backup_dir.mkdir(exist_ok=True)
for py_file in self.backend_path.rglob("*.py"):
if self.should_process_file(py_file):
rel_path = py_file.relative_to(self.backend_path)
backup_file = self.backup_dir / rel_path
backup_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(py_file, backup_file)
print(f"✅ Backup erstellt: {len(list(self.backup_dir.rglob('*.py')))} Dateien")
def should_process_file(self, file_path: Path) -> bool:
"""Bestimmt ob eine Datei verarbeitet werden soll"""
# Überspringe bestimmte Verzeichnisse
exclude_dirs = {'__pycache__', '.git', 'node_modules', 'instance'}
if any(part in str(file_path) for part in exclude_dirs):
return False
# Überspringe Backup-Verzeichnisse
if 'backup_' in str(file_path):
return False
return True
def analyze_file_imports(self, file_path: Path) -> Tuple[List[str], Set[str]]:
"""Analysiert Imports und Verwendungen in einer Datei"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
tree = ast.parse(content)
# Sammle alle Imports
imports = []
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
imports.append(alias.name)
elif isinstance(node, ast.ImportFrom):
module = node.module or ''
for alias in node.names:
if module:
imports.append(f"{module}.{alias.name}")
else:
imports.append(alias.name)
# Sammle verwendete Namen (vereinfacht)
used_names = set()
for node in ast.walk(tree):
if isinstance(node, ast.Name):
used_names.add(node.id)
elif isinstance(node, ast.Attribute):
if isinstance(node.value, ast.Name):
used_names.add(f"{node.value.id}.{node.attr}")
# Prüfe auch String-Literale
for imp in imports:
if imp in content:
used_names.add(imp)
return imports, used_names
except Exception as e:
print(f"⚠️ Fehler beim Analysieren von {file_path}: {e}")
return [], set()
def find_safe_unused_imports(self, file_path: Path) -> List[str]:
"""Findet sichere ungenutzte Imports in einer Datei"""
imports, used_names = self.analyze_file_imports(file_path)
unused_safe = []
for imp in imports:
# Nur sichere Imports berücksichtigen
if imp in self.safe_unused_imports:
# Prüfe verschiedene Nutzungsformen
base_name = imp.split('.')[0]
is_used = (
base_name in used_names or
imp in used_names or
any(imp in name for name in used_names)
)
if not is_used:
unused_safe.append(imp)
return unused_safe
def remove_unused_imports(self, file_path: Path, unused_imports: List[str]) -> bool:
"""Entfernt ungenutzte Imports aus einer Datei"""
if not unused_imports:
return False
try:
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
modified = False
new_lines = []
for line in lines:
should_remove = False
# Prüfe ob die Zeile einen zu entfernenden Import enthält
for unused_imp in unused_imports:
# Verschiedene Import-Patterns prüfen
patterns = [
f"from {unused_imp.split('.')[0]} import {unused_imp.split('.')[-1]}",
f"import {unused_imp}",
f"from {'.'.join(unused_imp.split('.')[:-1])} import {unused_imp.split('.')[-1]}",
]
for pattern in patterns:
if pattern in line and line.strip().startswith(('from ', 'import ')):
# Prüfe ob es eine reine Import-Zeile ist (keine Kommentare etc.)
clean_line = line.split('#')[0].strip()
if clean_line.endswith(unused_imp.split('.')[-1]) or clean_line.endswith(unused_imp):
should_remove = True
break
if should_remove:
break
if not should_remove:
new_lines.append(line)
else:
modified = True
print(f" Entferne: {line.strip()}")
if modified:
with open(file_path, 'w', encoding='utf-8') as f:
f.writelines(new_lines)
return True
except Exception as e:
print(f"❌ Fehler beim Bereinigen von {file_path}: {e}")
return False
return False
def clean_file(self, file_path: Path) -> bool:
"""Bereinigt eine einzelne Datei"""
rel_path = file_path.relative_to(self.backend_path)
# Nur sichere Dateien automatisch bereinigen
if str(rel_path) not in self.safe_files:
print(f"⚠️ Überspringe {rel_path} (nicht in sicherer Liste)")
return False
print(f"\n🔍 Analysiere: {rel_path}")
unused_imports = self.find_safe_unused_imports(file_path)
if unused_imports:
print(f" Gefunden: {len(unused_imports)} sichere ungenutzte Imports")
modified = self.remove_unused_imports(file_path, unused_imports)
if modified:
self.changes.append({
'file': str(rel_path),
'removed_imports': unused_imports,
'count': len(unused_imports)
})
print(f"{len(unused_imports)} Imports entfernt")
return True
else:
print(f" ⚠️ Imports gefunden aber nicht entfernt")
else:
print(f" ✅ Keine sicheren ungenutzten Imports gefunden")
return False
def run_cleanup(self):
"""Führt die komplette Bereinigung durch"""
print("🧹 Starte automatische Import-Bereinigung...")
print(f"📁 Backend-Pfad: {self.backend_path}")
# Backup erstellen
self.create_backup()
# Alle Python-Dateien durchgehen
modified_files = 0
total_removed = 0
for py_file in self.backend_path.rglob("*.py"):
if self.should_process_file(py_file):
if self.clean_file(py_file):
modified_files += 1
# Statistiken
total_removed = sum(change['count'] for change in self.changes)
print(f"\n" + "="*60)
print(f"📊 BEREINIGUNG ABGESCHLOSSEN")
print(f"="*60)
print(f"Bearbeitete Dateien: {modified_files}")
print(f"Entfernte Imports gesamt: {total_removed}")
print(f"Backup erstellt in: {self.backup_dir}")
if self.changes:
print(f"\n📝 GEÄNDERTE DATEIEN:")
for change in self.changes:
print(f" 📄 {change['file']}: {change['count']} Imports entfernt")
print(f"\n💡 NÄCHSTE SCHRITTE:")
print(f"1. Tests ausführen: python -m pytest")
print(f"2. App starten und prüfen: python app.py --debug")
print(f"3. Bei Problemen Backup wiederherstellen")
print(f"4. Manuelle Bereinigung von app.py und models.py")
return modified_files, total_removed
def restore_backup(self):
"""Stellt das Backup wieder her"""
if not self.backup_dir.exists():
print("❌ Kein Backup gefunden!")
return False
print(f"🔄 Stelle Backup wieder her aus: {self.backup_dir}")
restored = 0
for backup_file in self.backup_dir.rglob("*.py"):
rel_path = backup_file.relative_to(self.backup_dir)
original_file = self.backend_path / rel_path
if original_file.exists():
shutil.copy2(backup_file, original_file)
restored += 1
print(f"{restored} Dateien wiederhergestellt")
return True
def main():
backend_path = Path(__file__).parent
cleaner = ImportCleaner(str(backend_path))
import sys
if len(sys.argv) > 1 and sys.argv[1] == '--restore':
# Backup wiederherstellen
cleaner.restore_backup()
else:
# Bereinigung durchführen
modified, removed = cleaner.run_cleanup()
if modified > 0:
print(f"\n⚠️ WICHTIG: Führe Tests aus um sicherzustellen dass alles funktioniert!")
print(f"Bei Problemen: python cleanup_imports.py --restore")
if __name__ == "__main__":
main()