#!/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()