Handlers et points d'entrée
Chaque fonction sous functions: déclare un seul des deux
champs suivants :
handler:— chaîne, mode A uniquement. Un chemin d’import Python qui résout vers un appelable. Le runner MecaPy importe le module et l’appelle.entrypoint:— liste de chaînes, modes B/C uniquement. La commande argv que le worker lance dans votre conteneur après la préparation de/workspace/in/.
Déclarer les deux, aucun, ou un entrypoint: [] est refusé à la lecture
du manifest.
Mode A — handler:
Section intitulée « Mode A — handler: »Le handler est une chaîne unique de la forme module:function. Le
module est importé relativement à la racine de votre dépôt ; la
fonction est récupérée par attribut sur ce module. Seules les
fonctions de niveau module sont supportées — module:Classe.methode,
les classes appelables ou les applications partielles ne sont pas
acceptées par le parseur.
Fonction simple
Section intitulée « Fonction simple »functions: size: handler: bolts:sizedef size(diameter: float, load: float) -> dict: return {"stress": load / area(diameter)}Le runner appelle size(**inputs) où inputs est la fusion de
in/data.json et des fichiers d’entrée (chaque File arrive comme
pathlib.Path).
Sous-module
Section intitulée « Sous-module »handler: pkg.subpkg.module:my_functionLe préfixe pointé est le chemin d’import, le : le sépare du nom
d’attribut. Le runner ajoute /workspace/ à sys.path, donc tout ce
que vous expédiez y est importable.
Encapsuler un comportement avec état
Section intitulée « Encapsuler un comportement avec état »Si la logique vit dans une classe, exposez une fonction de niveau module qui instancie et délègue :
class Vis: def __init__(self, designation: str): ... def compute_stress(self, force: float) -> float: ...
# C'est ce que le manifest référence :def stress_for(designation: str, force: float) -> float: return Vis(designation).compute_stress(force)handler: bolts:stress_forCela garde la distinction fonction/méthode hors de la plateforme — le manifest ne voit que des fonctions de niveau module, et la classe reste un détail d’implémentation interne.
Signature et formulaire d’exécution
Section intitulée « Signature et formulaire d’exécution »En mode A, la signature annotée du handler nourrit l’introspection qui génère le formulaire d’exécution (AutoForm) :
- Paramètres simples → champs typés (un par paramètre, nom = nom du paramètre).
- Paramètres
pathlib.Path→ champs d’upload de fichier. - Retour
dictouTypedDict→ plusieurs sorties.
Si l’introspection échoue (annotations manquantes, type de retour ambigu, etc.), le formulaire retombe sur un schéma permissif et un avertissement est émis. Annotez toujours vos paramètres — ils pilotent l’AutoForm et servent de référence pour vos lecteurs.
Pour le typage côté workflow, l’introspection ne suffit pas : il
faut déclarer explicitement inputs: / outputs: avec les types du
catalogue canonique (Length, Force, Stress,
…). C’est ce qui permet à l’éditeur de workflow de valider les
connexions au tracé. Voir ports d’E/S typés.
Modes B/C — entrypoint:
Section intitulée « Modes B/C — entrypoint: »En modes B/C, le worker n’importe aucun Python utilisateur — il lance
simplement l’entrypoint dans votre conteneur, /workspace/ étant déjà
préparé.
functions: static_support: entrypoint: ["python3", "/workspace/_runner/wrapper.py"]La liste est l’argv. L’élément 0 est le programme ; les suivants sont
les arguments. La liste doit être non vide ; sinon le worker
échoue à la validation. Les ENTRYPOINT et CMD propres à l’image
sont ignorés — le worker invoque l’argv directement.
Ce que doit faire votre entrypoint
Section intitulée « Ce que doit faire votre entrypoint »L’entrypoint est responsable du contrat de runtime complet :
- Lire
/workspace/in/data.jsonet/workspace/in/files/*. - Lancer le calcul.
- Écrire
/workspace/out/data.json(un objet JSON). - Écrire les fichiers de sortie déclarés à
/workspace/out/files/<nom>.<ext>. - Éventuellement déposer des artifacts libres dans
/workspace/out/artifacts/. - Éventuellement ajouter des lignes de progression à
/workspace/out/progress.jsonl. - En cas d’échec, écrire
/workspace/out/_error.jsonet sortir avec un code de retour non nul.
Plusieurs fonctions, une seule image
Section intitulée « Plusieurs fonctions, une seule image »Plusieurs fonctions du même package partagent une seule image (construite ou tirée une seule fois). Elles se distinguent par leur argv :
runtime: kind: image image: ghcr.io/me/solver:1.4
functions: thermal: entrypoint: ["/opt/run.sh", "--mode=thermal"] mechanical: entrypoint: ["/opt/run.sh", "--mode=mechanical"] fatigue: entrypoint: ["/opt/run.sh", "--mode=fatigue"]L’image est tirée (mode C) ou construite (mode B) une fois et mise en cache ; chaque fonction la réutilise avec un argv différent.
Les ressources par fonction restent valables
Section intitulée « Les ressources par fonction restent valables »Les surcharges resources: au niveau de chaque fonction marchent en
modes B/C comme en mode A — elles changent les limites cgroup et le
timeout pour les runs de cette fonction :
functions: thermal: entrypoint: ["/opt/run.sh", "--mode=thermal"] resources: recommended: { cpu: 2, memory_mb: 2048 } timeout: 300 mechanical: entrypoint: ["/opt/run.sh", "--mode=mechanical"] resources: recommended: { cpu: 4, memory_mb: 8192 } # plus de mémoire pour mécanique timeout: 1800Choisir entre les modes
Section intitulée « Choisir entre les modes »| Question | Réponse |
|---|---|
| Python pur avec dépendances PyPI ? | Mode A. Pas de Dockerfile à écrire. |
| Solveur natif, paquet système, GPU ? | Mode B. Fournissez un Dockerfile. |
| Image déjà publiée, intouchable ? | Mode C. Référencez-la par tag ou digest. |
| Plusieurs fonctions partageant des dépendances natives ? | Un package, plusieurs fonctions, mode B ou C. |
| Fonctions sans rapport entre elles ? | Un package par fonction — le versionnement reste indépendant. |
Le typage côté workflow fonctionne identiquement dans les trois modes — seul le chemin de préparation des entrées change pour le worker.