Référence plugin.json¶
Chaque plugin Python déclare son identité, son point d'entrée et son
placement dans la barre de menus dans un fichier plugin.json situé à côté
de son main.py. C'est le même schéma que côté C++ ; seuls les champs
entry et module sont spécifiques à Python.
Exemple¶
{
"id": "org.example.wordcount",
"name": "Word Count",
"version": "1.0.0",
"vendor": "Example, Inc.",
"description": "Counts words and characters in the active document.",
"apiVersion": 1,
"entry": "python",
"module": "main",
"pyRequires": [],
"order": 900,
"menus": [
{ "title": "Plugins", "barPriority": 570, "itemPriority": 100 }
]
}
Champs¶
Obligatoires¶
| Champ | Type | Notes |
|---|---|---|
id |
string | Identifiant unique en DNS inversé. Utilisé partout — activation / désactivation, lignes de journal, réglages par plugin. Ne doit pas changer d'une version à l'autre. |
apiVersion |
integer | Doit être égal au MTE_PLUGIN_API_VERSION de l'hôte. Actuellement 1. Une incohérence est signalée dans la page Extensions et le plugin est listé mais non chargé. |
entry |
string | Doit valoir "python" pour passer par le backend Python. "native" ou l'absence du champ passe par le chargeur Qt. |
module |
string | Nom du module Python contenant register(ctx). Si "main", le worker cherche main.py dans le dossier du plugin. Les noms de paquets avec points ("src.main") sont une extension future — la phase 1 ne prend en charge que les noms plats. |
Recommandés¶
| Champ | Type | Notes |
|---|---|---|
name |
string | Nom d'affichage lisible, montré dans la page Extensions. |
version |
string | Semver ; forme libre sinon. |
vendor |
string | Auteur / organisation. Affiché dans la page Extensions. |
description |
string | Une ou deux lignes. Affichée dans la page Extensions. |
Optionnels¶
| Champ | Type | Notes |
|---|---|---|
order |
integer | Ordre de chargement entre plugins ; plus bas = chargé plus tôt. 1000 par défaut. Les égalités sont départagées par id. |
menus |
tableau d'objets | Voir ci-dessous. |
pyRequires |
tableau de chaînes | Chaînes d'exigences pip (p. ex. ["requests>=2.31"]). Au premier lancement du plugin, l'éditeur provisionne un environnement virtuel par plugin, y installe ces dépendances via pip et exécute le worker du plugin dedans (voir Empaquetage). Les entrées vides ou non textuelles sont ignorées. |
permissions |
tableau de chaînes | Déclarations de capacités à gros grain (p. ex. ["network"]), affichées en lecture seule dans la colonne Permissions de Préférences → Extensions afin que les utilisateurs voient ce que le plugin déclare faire. Déclaratif uniquement — pas encore appliqué. |
thirdParty |
tableau d'objets | Composants tiers embarqués par le plugin, pour l'attribution dans la boîte de dialogue À propos. Chaque entrée : name (obligatoire), license, url, file. Livrez le texte de licence nommé par file avec le plugin sous Plugins/Licenses/<id>/. Voir ci-dessous. |
menus¶
Chaque entrée déclare un menu de premier niveau auquel le plugin contribue et
fixe sa position. Répétez un objet par menu de premier niveau que vous
touchez (Tools, Plugins, Help, etc.).
| Champ | Type | Notes |
|---|---|---|
title |
string, obligatoire | Le libellé du menu de premier niveau sous lequel vit l'élément (Plugins, Tools, …). Doit correspondre au segment le plus à gauche des chemins que vous passez à ctx.menus.add_item(). |
barPriority |
integer, optionnel | Rang de gauche à droite dans la barre de menus. Plus bas = plus à gauche. Les menus du cœur ont des priorités fixes espacées de 100 (Fichier 100, Édition 200, …, Fenêtre 600) ; 570 place votre sous-menu près de la position Plugins. Répété entre plugins visant le même menu de premier niveau ; le dernier gagne, ce qui est sans conséquence car idempotent. |
itemPriority |
integer, optionnel | Rang vertical de l'ensemble du bloc de votre plugin dans le menu feuille. 1000 par défaut. Plus bas = plus haut. |
Vous ne listez PAS les éléments individuels ici — ils sont ajoutés par
ctx.menus.add_item() à l'exécution. menus ne concerne que le placement
dans la barre de menus.
thirdParty¶
Déclarez tout composant tiers embarqué par votre plugin afin que la boîte de dialogue À propos puisse l'attribuer. Chaque entrée :
"thirdParty": [
{ "name": "SomeLib", "license": "MIT",
"url": "https://example.com/", "file": "SomeLib-LICENSE.txt" }
]
| Champ | Type | Notes |
|---|---|---|
name |
string, obligatoire | Le composant. Les entrées sans nom non vide sont ignorées. |
license |
string, optionnel | Étiquette de style SPDX, p. ex. MIT, LGPL-3.0. |
url |
string, optionnel | Page du projet. |
file |
string, optionnel | Nom de base du texte de licence que vous livrez, résolu en Plugins/Licenses/<your-plugin-id>/<file>. |
Vous êtes propriétaire des textes de licence : livrez-les avec votre
paquet de plugin sous Plugins/Licenses/<id>/. L'éditeur liste les
composants et oriente les utilisateurs vers ce dossier ; il ne conserve pas
les textes tiers de votre plugin dans son propre dossier Licenses/.
Sonde statique¶
Au moment de la découverte — et de nouveau lors de l'installation d'un paquet
.mteplugin — l'hôte lit module, ouvre <pluginDir>/<module>.py et
confirme qu'il contient un def register(...) de niveau module — aucun
code n'est exécuté. L'installateur rejette un paquet défaillant avec une
boîte de dialogue d'erreur ; la découverte ignore silencieusement le plugin
avec une ligne d'erreur dans le journal :
PythonPluginBackend: skipping 'org.example.wordcount': module
'.../main.py' does not declare a top-level `def register(...)`.
Gardez register à la colonne 0 d'une ligne commençant par def register(.
Ordre de chargement et placement dans la barre de menus¶
Si votre plugin contribue à Plugins avec barPriority: 570, le menu
apparaît au rang 570 dans la barre de menus. Deux plugins avec des valeurs
de barPriority différentes pour le même titre sont en concurrence : le
dernier chargé gagne, mais comme les deux déclarent généralement le même
rang pour un menu donné, cela n'a pas d'importance. Voir
PLUGIN_ARCHITECTURE.md §13 pour le modèle d'ordonnancement complet.
Ce qui n'a PAS sa place ici¶
L'hôte analyse les champs documentés ci-dessus et ignore tout le reste — n'inventez pas de champs ; une clé inconnue est un poids mort silencieux.