Aller au contenu

Empaquetage et installation

Une extension Python est un dossier avec un plugin.json et un module Python. Deux façons de l'installer : l'empaqueter en archive .mteplugin et passer par l'installeur de l'éditeur (recommandé), ou déposer le dossier à la main dans un répertoire d'extensions.

Partez du modèle

Un point de départ prêt à copier vit dans le dépôt à Python/templates/plugin-template-python/ — trois fichiers (plugin.json, main.py, README.md) plus un CLAUDE.md destiné à Claude. Renommez le dossier avec le nom court de votre extension, modifiez quatre champs de plugin.json et commencez à écrire register(ctx). Le SDK installé livre le même modèle sous share/MTEPluginSDK/plugin-template-python/.

Structure du dossier d'extension

hello/
├── plugin.json      # required
└── main.py          # required; module name from plugin.json.module

Tout ce dont l'extension a besoin doit être dans ce dossier. Les sous-imports fonctionnent mais doivent rester plats — les noms module à points dans plugin.json sont une extension future.

Vous pouvez ajouter d'autres fichiers (README, LICENSE) — l'hôte ignore ce qu'il ne reconnaît pas.

Paquets .mteplugin (recommandé)

Zippez les fichiers de l'extension et donnez à l'archive l'extension .mteplugin (un simple .zip marche aussi). Les deux formes sont acceptées :

hello.mteplugin              hello.mteplugin
├── plugin.json              └── hello-1.0.0/        # any folder name
└── main.py                      ├── plugin.json
                                 └── main.py

Le dossier enveloppant unique — résultat naturel du zippage d'un dossier — est normalisé : l'extension s'installe toujours dans <Plugins>/<id>/, indexée par l'id du manifeste, jamais par le nom de dossier de l'archive. C'est aussi pourquoi installer la version 2 d'une extension remplace la version 1 au lieu de s'installer à côté.

Installez via Préférences → Extensions → Installer… puis redémarrez l'éditeur.

N'installez que des paquets de confiance

L'installeur vérifie qu'un paquet est structurellement sain (voir plus bas) — il ne rend pas sûre une extension non fiable. Une fois chargée, une extension s'exécute avec le même accès à vos fichiers, paramètres et réseau que l'éditeur, et n'est pas sandboxée. La sonde statique register(...) n'exécute aucun code à l'installation, mais le code de l'extension s'exécute bel et bien au prochain lancement. Traitez un .mteplugin (et tout fichier de configuration ou JSON livré) comme un programme inconnu : n'installez que depuis une source de confiance. Voir Extensions pour l'avertissement complet.

Ce que l'installeur valide

Le paquet est entièrement validé sur une copie jetable avant de toucher quoi que ce soit sur disque — un mauvais paquet ne peut jamais perturber une installation existante :

  1. plugin.json s'analyse, a un id, apiVersion correspond à l'éditeur, entry vaut "python" et module est présent.
  2. La liste de l'archive est sûre : pas de chemins absolus ni d'entrées .., au plus 10 000 entrées, au plus 256 Mio décompressé, et au moins un fichier .py.
  3. Après extraction vers un répertoire de travail, le <module>.py déclaré existe et déclare un def register(...) au niveau supérieur — la même sonde statique que la découverte. Aucun code Python n'est exécuté à l'installation.

Tout échec produit un message d'erreur lisible et laisse les extensions de l'éditeur intactes.

Mettre à jour et désinstaller

  • Installer un paquet dont l'id est déjà installé le remplace. Si cette extension est chargée, la mise à jour est mise en attente et appliquée au prochain lancement.
  • Désinstallez depuis la même page de Préférences ; la suppression a lieu elle aussi au prochain lancement, quand rien n'est chargé.
  • Les extensions livrées (intégrées) ne peuvent pas être remplacées par un paquet installé de même id.

Installation à la main (dépôt de dossier)

L'éditeur découvre les extensions dans deux répertoires à chaque démarrage :

  1. Livré — à côté de l'exécutable, dans <exe-dir>/Plugins/. Les extensions intégrées (p. ex. HelloPython) vivent ici.
  2. Utilisateur — par utilisateur, accessible en écriture. Sous Windows : %LOCALAPPDATA%/MTE/Plugins/, sous macOS : ~/Library/Application Support/MTE/Plugins/, sous Linux : ~/.local/share/MTE/Plugins/.

Les deux répertoires sont scannés. Si le même id apparaît dans les deux, la première occurrence gagne (le livré a priorité). Redémarrez l'éditeur pour prendre en compte de nouveaux dossiers — le rechargement à chaud n'est pas pris en charge.

Deux structures acceptées

Le scan cherche plugin.json soit directement dans le répertoire d'extensions (en vrac), soit dans un niveau de sous-dossier immédiat (dossier par extension) :

Plugins/
├── plugin.json         # loose -- one plugin at the top level
├── main.py
└── hello/              # per-plugin folder -- one plugin
    ├── plugin.json
    └── main.py

Le dossier par extension est la structure recommandée ; c'est la forme que produit l'installeur.

Dépendances (pyRequires)

plugin.json peut déclarer des exigences pip en tableau inline :

"pyRequires": ["requests>=2.31"]

Au premier lancement de l'extension, l'éditeur provisionne un environnement virtuel dans <AppLocalData>/PluginVenv/<id>/ (python -m venv + pip install, qui a besoin du réseau cette fois-là) et exécute le worker de l'extension sous l'interpréteur de ce venv. Les lancements suivants le réutilisent ; changer pyRequires reprovisionne automatiquement (le venv porte une empreinte des exigences pour lesquelles il a été construit).

  • Les échecs de provisionnement (pas de réseau, une exigence mal écrite) laissent l'extension listée mais pas chargée, avec l'erreur pip dans le journal ; le lancement suivant réessaie.
  • Désinstaller une extension supprime son venv avec le dossier de l'extension (un venv est une donnée dérivée — il se reconstruit depuis pyRequires en cas de réinstallation).

Machines hors ligne / verrouillées

Livrez un venv pré-construit dans le paquet, comme dossier venv/ à la racine de l'extension. Quand il est présent, il l'emporte sur tout — pip ne s'exécute jamais. Construisez-le sur une machine de même OS/architecture, car les venvs ne sont pas portables entre plateformes.

Vendoring (petites dépendances pur Python)

Pour un unique module pur Python, le vendoring dans le dossier de l'extension fonctionne toujours et évite entièrement la machinerie venv :

# main.py
import os, sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "vendor"))

import your_dep

Permissions déclarées

plugin.json peut porter un tableau permissions (p. ex. ["network"]). La page de Préférences des Extensions l'affiche dans une colonne Permissions en lecture seule, pour que les utilisateurs voient ce qu'une extension déclare d'elle-même. C'est une déclaration, pas une contrainte — le sandboxing est un travail futur.

Où vont les données inscriptibles

Le répertoire d'extensions contient du code. Les données d'exécution (caches, configuration par utilisateur, index) vont dans un répertoire de données par extension géré par l'hôte — ctx.data_dir() renvoie son chemin absolu. N'écrivez PAS dans le répertoire d'extensions depuis votre .py à l'exécution ; la désinstallation supprime tout le dossier <Plugins>/<id>/, et les écritures faites ailleurs dans l'arbre des extensions ne sont jamais nettoyées.

Déployer sur d'autres machines

Expédiez le fichier .mteplugin — il est autonome et validé à la réception. Un zip/tarball/git-clone du dossier dans le répertoire d'extensions par utilisateur fonctionne aussi.

Activer / désactiver

La page de Préférences des Extensions liste chaque extension découverte (natives + Python ensemble) avec les mêmes colonnes d'origine/état. Désactiver une extension la garde listée mais empêche l'appel de sa fabrique au démarrage — aucun worker n'est lancé. Réactivez et redémarrez pour la retrouver.