Analyse Python
Pendant que l'élève tape, CapyCode souligne les erreurs de son code Python et les explique en termes simples ; il peut aussi le formater. Tout se passe dans le navigateur, avec Ruff compilé en WebAssembly.
Ruff
Ruff analyse et formate du Python, en un seul module (@astral-sh/ruff-wasm-web), assez vite pour tourner à chaque frappe. Il a été préféré aux autres solutions :
- pyflakes et black dans Pyodide : il faudrait un Pyodide entier dans un worker dédié (le noyau d'exécution est isolé, et souvent occupé par un
input()ou une boucle), pour un résultat plus lent ; - Pyright : plus lourd et plus lent, et l'analyse des types n'est pas une priorité pour des débutants ;
- un analyseur maison : peu de règles, toutes à maintenir.
Son coût est le téléchargement du module WASM (~11 Mo, ~4 Mo compressé). Il n'est donc chargé qu'à la première analyse d'un fichier Python (import dynamique dans ruffService.init), puis gardé par le service worker (cache ruff-wasm, une seule version), et jamais précaché pour qui n'écrit pas de Python. En attendant, les erreurs de syntaxe viennent de l'arbre Lezer de CodeMirror, déjà présent.
Règles
DEFAULT_RUFF_SETTINGS (src/services/ruff.ts) active un jeu de règles réduit, celui qui aide un débutant sans le noyer dans le style :
| Règles | Ce qu'elles signalent |
|---|---|
E4, E7, E9 | erreurs de syntaxe et d'exécution évidentes, comparaisons invalides, except: nu |
F (Pyflakes) | imports inutilisés, noms non définis, variables locales inutilisées… |
Le formatage suit les conventions de Ruff (proches de black) : lignes de 88 caractères, indentation de 4 espaces, guillemets doubles.
Les explications pédagogiques
src/services/pythonErrorTranslator.ts reconnaît les messages fréquents (deux-points oublié, indentation, parenthèse non fermée, = au lieu de ==, print sans parenthèses…) et les remplace par un titre, une explication et un conseil, dans la langue de l'interface (clés pythonErrors.*). src/services/linter.ts compose le message de l'infobulle avec les clés linter.message et linter.tip, ponctuation comprise (« : » précédé d'une espace en français). Les corrections automatiques proposées par Ruff deviennent des actions dans l'infobulle, nommées par Ruff ou, à défaut, par linter.autoFix.
Les diagnostics
Le linter ne connaît pas les stores : createLinterExtension(lint, getPath, report) reçoit une fonction report, que CodeEditor branche sur diagnosticsStore.setDiagnostics. Le store diagnostics garde les problèmes par fichier et calcule les compteurs du fichier actif, affichés dans la barre d'état.
Le registre des langages
Rien de cela n'est propre à l'éditeur : c'est le langage Python (src/languages/python.ts) qui déclare lint: lintPython, format (Ruff) et outline. Un autre langage pourrait apporter sa propre analyse de la même façon (voir Langages).
Limites
- L'analyse ne voit qu'un fichier à la fois : un nom importé d'un autre fichier du projet n'est pas vérifié.
- Les erreurs à l'exécution (tracebacks dans la console) ne passent pas encore par le traducteur pédagogique (voir Pistes).