Refonte majeure du système Agent Chat et ajout de nombreux modules : - Chat unifié : suppression du dual Workflows/Agent Libre, tout passe par /api/chat avec résolution en 3 niveaux (workflow → geste → "montre-moi") - GestureCatalog : 38 raccourcis clavier universels Windows avec matching sémantique, substitution automatique dans les replays, et endpoint /api/gestures - Mode Copilot : exécution pas-à-pas des workflows avec validation humaine via WebSocket (approve/skip/abort) avant chaque action - Léa UI (agent_v0/lea_ui/) : interface PyQt5 pour Windows avec overlay transparent pour feedback visuel pendant le replay - Data Extraction (core/extraction/) : moteur d'extraction visuelle de données (OCR + VLM → SQLite), avec schémas YAML et export CSV/Excel - ReplayVerifier (agent_v0/server_v1/) : vérification post-action par comparaison de screenshots, avec logique de retry (max 3) - IntentParser durci : meilleur fallback regex, type GREETING, patterns améliorés - Dashboard : nouvelles pages gestures, streaming, extractions - Tests : 63 tests GestureCatalog, 47 tests extraction, corrections tests existants - Dépréciation : /api/agent/plan et /api/agent/execute retournent HTTP 410, suppression du code hardcodé _plan_to_replay_actions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
126 lines
4.2 KiB
Python
126 lines
4.2 KiB
Python
"""
|
|
Tests pour la validation des imports circulaires.
|
|
|
|
Auteur: Dom, Alice Kiro
|
|
Date: 20 décembre 2024
|
|
"""
|
|
|
|
import pytest
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Ajouter le répertoire racine au path pour les imports
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
try:
|
|
from validate_circular_imports import CircularImportDetector
|
|
HAS_CIRCULAR_IMPORT_DETECTOR = True
|
|
except ImportError:
|
|
HAS_CIRCULAR_IMPORT_DETECTOR = False
|
|
|
|
|
|
class TestCircularImports:
|
|
"""Tests pour la détection d'imports circulaires"""
|
|
|
|
@pytest.mark.skipif(not HAS_CIRCULAR_IMPORT_DETECTOR, reason="Script validate_circular_imports.py supprimé")
|
|
def test_no_circular_imports_in_core(self):
|
|
"""Test qu'il n'y a pas d'imports circulaires dans core/"""
|
|
root_path = Path(__file__).parent.parent.parent
|
|
core_path = root_path / 'core'
|
|
|
|
detector = CircularImportDetector(root_path)
|
|
detector.analyze_directory(core_path)
|
|
|
|
cycles = detector.find_cycles()
|
|
|
|
if cycles:
|
|
cycle_info = []
|
|
for i, cycle in enumerate(cycles, 1):
|
|
cycle_str = " → ".join(cycle)
|
|
cycle_info.append(f"Cycle {i}: {cycle_str}")
|
|
|
|
pytest.fail(
|
|
f"Imports circulaires détectés:\n" +
|
|
"\n".join(cycle_info) +
|
|
"\n\nSolutions:\n" +
|
|
"1. Utiliser TYPE_CHECKING pour les imports de type\n" +
|
|
"2. Déplacer les imports dans les fonctions (lazy loading)\n" +
|
|
"3. Créer des interfaces abstraites"
|
|
)
|
|
|
|
def test_lazy_imports_available(self):
|
|
"""Test que les fonctions de lazy loading sont disponibles"""
|
|
from core.models import (
|
|
get_workflow,
|
|
get_workflow_node,
|
|
get_action,
|
|
get_target_spec,
|
|
get_execution_result
|
|
)
|
|
|
|
# Vérifier que les fonctions retournent les bonnes classes
|
|
Workflow = get_workflow()
|
|
assert Workflow.__name__ == 'Workflow'
|
|
|
|
WorkflowNode = get_workflow_node()
|
|
assert WorkflowNode.__name__ == 'WorkflowNode'
|
|
|
|
Action = get_action()
|
|
assert Action.__name__ == 'Action'
|
|
|
|
TargetSpec = get_target_spec()
|
|
assert TargetSpec.__name__ == 'TargetSpec'
|
|
|
|
ExecutionResult = get_execution_result()
|
|
assert ExecutionResult.__name__ == 'WorkflowExecutionResult'
|
|
|
|
def test_interfaces_importable(self):
|
|
"""Test que les interfaces abstraites sont importables"""
|
|
from core.interfaces import ITargetResolver, IActionExecutor, IErrorHandler
|
|
|
|
# Vérifier que ce sont bien des classes abstraites
|
|
assert hasattr(ITargetResolver, '__abstractmethods__')
|
|
assert hasattr(IActionExecutor, '__abstractmethods__')
|
|
assert hasattr(IErrorHandler, '__abstractmethods__')
|
|
|
|
# Vérifier qu'on ne peut pas les instancier directement
|
|
with pytest.raises(TypeError):
|
|
ITargetResolver()
|
|
|
|
with pytest.raises(TypeError):
|
|
IActionExecutor()
|
|
|
|
with pytest.raises(TypeError):
|
|
IErrorHandler()
|
|
|
|
def test_type_checking_imports(self):
|
|
"""Test que les imports TYPE_CHECKING et lazy loading fonctionnent"""
|
|
# Ceci ne devrait pas lever d'exception
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from core.models import (
|
|
Workflow,
|
|
WorkflowNode,
|
|
Action,
|
|
TargetSpec
|
|
)
|
|
|
|
import core.models as models
|
|
|
|
# Les fonctions de lazy loading doivent être disponibles
|
|
assert hasattr(models, 'get_workflow')
|
|
assert hasattr(models, 'get_workflow_node')
|
|
assert hasattr(models, 'get_action')
|
|
assert hasattr(models, 'get_target_spec')
|
|
|
|
# Les classes sont accessibles via __getattr__ lazy loading
|
|
# (les attributs sont disponibles à l'exécution via le module __getattr__)
|
|
Workflow = models.get_workflow()
|
|
assert Workflow is not None
|
|
WorkflowNode = models.get_workflow_node()
|
|
assert WorkflowNode is not None
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"]) |