Dodock permet d'exécuter des scripts Python et des templates Jinja directement depuis l'interface (Scripts serveur, formats d'impression, e-mails, etc.). Pour protéger l'installation contre des accès non autorisés aux données ou aux opérations critiques, le moteur distingue deux contextes d'exécution aux permissions distinctes.
render_safe_globalsUtilisé par le moteur de templates Jinja (formats d'impression, modèles d'e-mail, aperçus). Ce contexte est strictement en lecture : aucune opération d'écriture en base de données, aucune mise en file d'attente de tâches en arrière-plan ne sont accessibles.
Fonctions disponibles (liste principale) :
| Fonction | Rôle |
|---|---|
frappe.get_doc | Récupère un document (objet déshydraté, sans méthodes d'écriture) |
frappe.get_list / frappe.get_all | Interroge des listes de documents |
frappe.get_meta | Retourne les métadonnées d'un DocType (objet déshydraté) |
frappe.get_cached_doc | Récupère un document depuis le cache |
frappe.get_last_doc | Retourne le dernier document d'un type |
frappe.copy_doc | Crée une copie locale d'un document |
frappe.get_mapped_doc | Mappe un document vers un autre type |
frappe.sendmail | Envoie un e-mail (retourne le nom du message, sans accès aux files) |
| Filtres et macros Jinja standards | Formatage, dates, devises… |
Remarque : Les objets retournés par ces fonctions sont déshydratés — ils exposent les données du document (champs, tables enfants) mais pas les méthodes Python internes (
save,submit,delete, etc.). Cela empêche tout effet de bord depuis un template.
exec_safe_globalsUtilisé par les Scripts serveur, les automatisations et les crochets Python configurés via l'interface. Ce contexte étend le contexte de rendu avec des capacités d'écriture contrôlées.
Fonctions supplémentaires disponibles :
| Fonction | Rôle |
|---|---|
frappe.new_doc | Crée un nouveau document (objet déshydraté prêt à l'enregistrement) |
frappe.enqueue | Met une tâche en file d'attente en arrière-plan |
QueryBuilder (lecture seule via frappe.qb) | Construit des requêtes SQL en lecture — les opérations d'écriture (INSERT, UPDATE, DELETE) restent bloquées |
Sécurité QueryBuilder : même dans le contexte d'exécution, le QueryBuilder est restreint aux opérations de lecture. Les tentatives d'écriture via
frappe.qbdéclenchent une exception.
L'un des mécanismes clés de cette architecture est la déshydratation des objets retournés par les fonctions d'accès aux documents.
Un objet Document Frappe standard expose de nombreuses méthodes Python (save(), submit(), delete(), reload(), etc.) qui modifient la base de données. Dans un contexte sécurisé, ces méthodes ne doivent pas être accessibles à du code non vérifié.
La déshydratation consiste à convertir l'objet Document en un dictionnaire enrichi (_dict) qui :
# Ce que le script reçoit (objet déshydraté)
doc = frappe.get_doc("Sales Order", "SAL-ORD-2024-00001")
print(doc.customer) # ✅ Lecture des champs
print(doc.items[0].qty) # ✅ Accès aux tables enfants
doc.save() # ❌ AttributeError — méthode non disponible
En environnement de développement (developer_mode = 1), les restrictions du contexte de rendu peuvent être assouplies pour faciliter le débogage des templates. Ce comportement est opt-out : l'assouplissement est actif par défaut en mode développement mais toujours désactivé en production.
render_safe_globals sont conçues pour protéger les données en environnement de production ; leur désactivation expose l'installation à des risques de sécurité.Ces templates s'exécutent toujours dans le contexte render_safe_globals. Si un template génère une erreur du type AttributeError sur une méthode comme save, c'est le comportement attendu : le template tente d'appeler une opération d'écriture interdite.
Bonne pratique : limiter les templates Jinja à l'affichage de données. Toute logique de transformation complexe doit être déplacée vers un Script serveur ou un crochet Python.
Les Scripts serveur disposent du contexte exec_safe_globals. Ils peuvent créer des documents, envoyer des e-mails et déclencher des tâches en arrière-plan, mais restent isolés du reste de l'environnement Python (pas d'import de modules arbitraires, pas d'accès au système de fichiers).
# Exemple — Script serveur : créer un document et envoyer un e-mail
commande = frappe.new_doc("Sales Order")
commande.customer = "Maison Verte SARL"
commande.delivery_date = frappe.utils.add_days(frappe.utils.today(), 7)
# Ajout de lignes...
commande.insert()
frappe.sendmail(
recipients=["contact@maisonverte.fr"],
subject="Votre commande a été créée",
message=f"Commande {commande.name} enregistrée."
)
Si vous développez une fonction utilitaire appelée depuis plusieurs contextes, vous pouvez vérifier les globals disponibles plutôt que de supposer le contexte :
# Vérifier si l'exécution se trouve dans un contexte sécurisé
import frappe
if frappe.flags.in_safe_exec:
# Comportement adapté au contexte sécurisé
pass
| Fichier | Rôle |
|---|---|
frappe/utils/safe_exec.py | Définition de render_safe_globals, exec_safe_globals, safer_exec et des utilitaires de déshydratation |
frappe/utils/jinja.py | Intégration de render_safe_globals dans le moteur de templates Jinja (get_jenv) |
frappe/model/meta.py | Sérialisation des métadonnées en _dict pour la déshydratation |
frappe/query_builder/utils.py | Restriction du QueryBuilder aux opérations de lecture dans les contextes sécurisés |