- 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>
214 lines
7.3 KiB
Python
214 lines
7.3 KiB
Python
#!/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() |