v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
214
validate_imports.py
Normal file
214
validate_imports.py
Normal file
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Validation des imports pour Fiche #4 - RPA Vision V3
|
||||
|
||||
Auteur: Dom, Alice Kiro - 15 décembre 2024
|
||||
Objectif: Valider que tous les imports utilisent 'from core...' au lieu de 'from rpa_vision_v3.core...'
|
||||
|
||||
Usage:
|
||||
python validate_imports.py # Validation seule
|
||||
python validate_imports.py --fix # Correction automatique
|
||||
python validate_imports.py --stats # Statistiques détaillées
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Dict
|
||||
|
||||
class ImportValidator:
|
||||
"""Validateur d'imports pour la Fiche #4"""
|
||||
|
||||
def __init__(self):
|
||||
self.bad_pattern = re.compile(r'from rpa_vision_v3\.core')
|
||||
self.good_pattern = re.compile(r'from core\.')
|
||||
self.exclude_dirs = {
|
||||
'venv', 'venv_v3', '__pycache__', '.git',
|
||||
'node_modules', '.pytest_cache', '.hypothesis',
|
||||
'htmlcov', 'rpa_vision_v3.egg-info'
|
||||
}
|
||||
self.exclude_files = {
|
||||
'validate_imports.py', 'setup.py', 'test_fiche4_imports_stables.py'
|
||||
}
|
||||
|
||||
def should_skip(self, filepath: Path) -> bool:
|
||||
"""Vérifier si on doit ignorer ce fichier/dossier"""
|
||||
# Ignorer les dossiers exclus
|
||||
for part in filepath.parts:
|
||||
if part in self.exclude_dirs:
|
||||
return True
|
||||
|
||||
# Ignorer les fichiers exclus
|
||||
if filepath.name in self.exclude_files:
|
||||
return True
|
||||
|
||||
# Ignorer les fichiers non-Python
|
||||
if not filepath.name.endswith('.py'):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def scan_file(self, filepath: Path) -> List[Tuple[int, str]]:
|
||||
"""Scanner un fichier pour les imports non-conformes"""
|
||||
bad_imports = []
|
||||
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
for line_num, line in enumerate(f, 1):
|
||||
if self.bad_pattern.search(line):
|
||||
bad_imports.append((line_num, line.strip()))
|
||||
except (UnicodeDecodeError, PermissionError):
|
||||
# Ignorer les fichiers binaires ou non-accessibles
|
||||
pass
|
||||
|
||||
return bad_imports
|
||||
|
||||
def fix_file(self, filepath: Path) -> int:
|
||||
"""Corriger les imports dans un fichier"""
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Compter les remplacements
|
||||
original_content = content
|
||||
content = self.bad_pattern.sub('from core', content)
|
||||
|
||||
if content != original_content:
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
return content.count('from core') - original_content.count('from core')
|
||||
|
||||
except (UnicodeDecodeError, PermissionError):
|
||||
pass
|
||||
|
||||
return 0
|
||||
|
||||
def validate_all(self) -> Dict[str, List[Tuple[int, str]]]:
|
||||
"""Valider tous les fichiers Python"""
|
||||
bad_files = {}
|
||||
|
||||
for root, dirs, files in os.walk('.'):
|
||||
# Filtrer les dossiers à ignorer
|
||||
dirs[:] = [d for d in dirs if d not in self.exclude_dirs]
|
||||
|
||||
for file in files:
|
||||
filepath = Path(root) / file
|
||||
|
||||
if self.should_skip(filepath):
|
||||
continue
|
||||
|
||||
bad_imports = self.scan_file(filepath)
|
||||
if bad_imports:
|
||||
bad_files[str(filepath)] = bad_imports
|
||||
|
||||
return bad_files
|
||||
|
||||
def fix_all(self) -> Dict[str, int]:
|
||||
"""Corriger tous les fichiers Python"""
|
||||
fixed_files = {}
|
||||
|
||||
for root, dirs, files in os.walk('.'):
|
||||
# Filtrer les dossiers à ignorer
|
||||
dirs[:] = [d for d in dirs if d not in self.exclude_dirs]
|
||||
|
||||
for file in files:
|
||||
filepath = Path(root) / file
|
||||
|
||||
if self.should_skip(filepath):
|
||||
continue
|
||||
|
||||
fixes = self.fix_file(filepath)
|
||||
if fixes > 0:
|
||||
fixed_files[str(filepath)] = fixes
|
||||
|
||||
return fixed_files
|
||||
|
||||
def get_stats(self) -> Dict[str, int]:
|
||||
"""Obtenir des statistiques sur les imports"""
|
||||
stats = {
|
||||
'total_python_files': 0,
|
||||
'files_with_bad_imports': 0,
|
||||
'total_bad_imports': 0,
|
||||
'files_with_good_imports': 0,
|
||||
'total_good_imports': 0
|
||||
}
|
||||
|
||||
for root, dirs, files in os.walk('.'):
|
||||
# Filtrer les dossiers à ignorer
|
||||
dirs[:] = [d for d in dirs if d not in self.exclude_dirs]
|
||||
|
||||
for file in files:
|
||||
filepath = Path(root) / file
|
||||
|
||||
if self.should_skip(filepath):
|
||||
continue
|
||||
|
||||
stats['total_python_files'] += 1
|
||||
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
bad_count = len(self.bad_pattern.findall(content))
|
||||
good_count = len(self.good_pattern.findall(content))
|
||||
|
||||
if bad_count > 0:
|
||||
stats['files_with_bad_imports'] += 1
|
||||
stats['total_bad_imports'] += bad_count
|
||||
|
||||
if good_count > 0:
|
||||
stats['files_with_good_imports'] += 1
|
||||
stats['total_good_imports'] += good_count
|
||||
|
||||
except (UnicodeDecodeError, PermissionError):
|
||||
pass
|
||||
|
||||
return stats
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Validation imports Fiche #4')
|
||||
parser.add_argument('--fix', action='store_true', help='Corriger automatiquement')
|
||||
parser.add_argument('--stats', action='store_true', help='Afficher statistiques')
|
||||
args = parser.parse_args()
|
||||
|
||||
validator = ImportValidator()
|
||||
|
||||
if args.stats:
|
||||
print("📊 Statistiques des imports:")
|
||||
stats = validator.get_stats()
|
||||
for key, value in stats.items():
|
||||
print(f" {key}: {value}")
|
||||
return
|
||||
|
||||
if args.fix:
|
||||
print("🔧 Correction automatique des imports...")
|
||||
fixed_files = validator.fix_all()
|
||||
|
||||
if fixed_files:
|
||||
print(f"✅ {len(fixed_files)} fichiers corrigés:")
|
||||
for filepath, count in fixed_files.items():
|
||||
print(f" {filepath}: {count} imports corrigés")
|
||||
else:
|
||||
print("✅ Aucune correction nécessaire")
|
||||
return
|
||||
|
||||
# Validation par défaut
|
||||
print("🔍 Validation des imports...")
|
||||
bad_files = validator.validate_all()
|
||||
|
||||
if bad_files:
|
||||
print(f"❌ {len(bad_files)} fichiers avec imports non-conformes:")
|
||||
for filepath, bad_imports in bad_files.items():
|
||||
print(f"\n📁 {filepath}:")
|
||||
for line_num, line in bad_imports:
|
||||
print(f" ligne {line_num}: {line}")
|
||||
|
||||
print(f"\n💡 Pour corriger automatiquement: python {sys.argv[0]} --fix")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("✅ Tous les imports sont conformes")
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user