Terminal et IDE dans Mkdocs⚓︎
+Introduction⚓︎
+Pyodide-Mkdocs
est une solution technique permettant de créer un cours interactif à partir d'un site généré par Mkdocs.
Il permet d'intégrer, dans le navigateur, côté client :
+-
+
- une console Python ; +
- un éditeur de code ; +
- un juge en ligne associé à des corrigés. +
Garantie :
+-
+
- sans cookie +
- sans inscription +
- créé par un enseignant pour les enseignants +
Solution
+La technologie permettant ce tour de force s'appelle Pyodide.
+Pyodide utilise WebAssembly pour faire le lien entre Python et Javascript et proposer un environnement permettant de manipuler le DOM avec Python, ou de manipuler Python avec Javascript.
+Aperçu⚓︎
+voyelles = ['a', 'e', 'i', 'o', 'u', 'y']bksl-nlbksl-nldef dentiste(texte):bksl-nl passbksl-nlbksl-nlassert dentiste("j'ai mal") == 'aia'bksl-nlassert dentiste("il fait chaud") == 'iaiau'bksl-nlassert dentiste("") == ''bksl-nlbksl-nlvoyelles = ['a', 'e', 'i', 'o', 'u', 'y']bksl-nlbksl-nldef dentiste(texte):bksl-nl resultat = ''bksl-nl for lettre in texte:bksl-nl if lettre in voyelles:bksl-nl resultat = resultat + lettrebksl-nl return resultatbksl-nlbksl-nl
+A
+Une première remarque
+Ceci est un exercice classique.
+D'autres détails
+On pourrait représenter la situation dans un tableau :
+a | +b | +c | +
---|---|---|
1 | +2 | +3 | +
Z
+Installation⚓︎
+On part d'une installation comme indiqué sur [https://ens-fr.gitlab.io/mkdocs/] avec le plugin macro, préalablement installé.
+L'installation demande de rajouter à cette configuration les éléments suivants.
+Modification :
+-
+
- fichier YML
mkdocs.yml
;
+ - fichier de macro
main.py
;
+
Ajout :
+-
+
- un dossier
my_theme_customizations/
à la racine du projet Mkdocs ;
+ - un template HTML
my_theme_customizations/main.html
;
+ - un fichier CSS
docs/xtra/stylesheets/pyoditeur.css
;
+ - deux fichiers Javascript
docs/xtra/javascripts/interpreter.js
etmy_theme_customizations/js/ide.js
;
+ - deux fichiers Markdown
docs/xtra/start.md
etdocs/xtra/end.md
.
+
Fichier YML mkdocs.yml
⚓︎
+Ajoutez les lignes surlignées dans votre fichier mkdocs.yml .
+ site_name: "Terminal et REPL dans Mkdocs"
+
+ ...
+
+ theme:
+ name: material
+ custom_dir: my_theme_customizations/
+
+ ...
+
+ extra_javascript:
+ - xtra/javascripts/mathjax-config.js # MathJax
+ - javascripts/config.js
+ - https://polyfill.io/v3/polyfill.min.js?features=es6
+ - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
+ - xtra/javascripts/interpreter.js
+
+ extra_css:
+ - xtra/stylesheets/pyoditeur.css
+ - xtra/stylesheets/ajustements.css # ajustements
+
Fichier macro Python main.py
⚓︎
+À votre fichier main.py
, ajoutez les lignes du fichier main.py
.
Création du dossier custom_dir
⚓︎
+N'oubliez pas de créer le dossier my_theme_customizations/
à la racine du projet Mkdocs.
Dans ce dossier, ajoutez le template Jinja main.html
:
{% extends "base.html" %}
+
+ {% block content %}
+ {{super()}}
+ <script src="{{ base_url }}/js/ide.js"></script>
+ {% endblock %}
+
+ {% block libs %}
+ {{ super() }}
+ <!-- favicons -->
+ <link rel="shortcut icon" href="../assets/images/favicon.ico" type="image/x-icon">
+ <link rel="icon" href="../assets/images/favicon_32x32.png" sizes="32x32">
+ <link rel="icon" href="../assets/images/favicon_96x96.png" sizes="96x96">
+ <link rel="icon" href="../assets/images/favicon_144x144.png" sizes="144x144">
+ <!-- Load CDNs : Pyodide (Python in WASM), Ace (Editor) and JQuery (Terminal) -->
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" type="text/javascript" charset="utf-8"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pyodide.js"></script>
+ <script src="https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pyodide.asm.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/js-md5"></script>
+ <script src="https://cdn.jsdelivr.net/npm/jquery"></script>
+ <script src="https://cdn.jsdelivr.net/npm/jquery.terminal@2.23.0/js/jquery.terminal.min.js"></script>
+ <link href="https://cdn.jsdelivr.net/npm/jquery.terminal@2.23.0/css/jquery.terminal.min.css" rel="stylesheet">
+ {% endblock %}
+
Fichier CSS pyoditeur.css
⚓︎
+Afin de coller au thème du site, recopiez et ajoutez le fichier pyoditeur.css
au dossier docs/xtra/stylesheets/
.
Si vous avez opté pour d'autres couleurs, c'est là que vous pourrez faire les modifications de l'éditeur.
+Fichiers javascripts interpreter.js
et ide.js
⚓︎
+Deux fichiers Javascript interpreter.js
et ide.js
sont nécessaires :
-
+
interpreter.js
doit être placé dans le dossier :docs/xtra/javascripts/
;
+ide.js
doit être placé dans le dossier :my_theme_customizations/js/ide.js
.
+
Fichiers start_REM.md
et end_REM.md
⚓︎
+Pour la bonne gestion des fichiers de remarque, il faut également ajouter deux fichiers standardisés au format markdown : start_REM.md
et end_REM.md
Images des boutons⚓︎
+Les boutons doivent être placés à cette adresse : /docs/images/buttons/
. Il existe six boutons que vous pouvez récupérer en téléchargeant l'archive.
Syntaxe et exemples⚓︎
+Syntaxe Markdown⚓︎
+La syntaxe
+{{ terminal() }}
+
{{ IDE() }}
+
{{ IDEv() }}
+
{{ IDE('foo/bar/nom_de_fichier', MAX = 8, SANS = 'max,min') }}
+
nom_de_fichier.py
dans un IDE. Le fichier doit être dans docs/scripts/foo/bar/
. Ne pas oublier les guillemets.
+MAX = 8
indique le nombre maximal de tentatives de validation que l'élève peut effectuer. MAX = 1000
permet de mettre ce nombre à l'infini. Valeur par défaut : MAX = 5
.
SANS = 'max,min'
permet d'interdire l'utilisation des fonctions built-ins max
et min
.
Les IDE sont enregistrés à intervalle de temps régulier. Ils permettent également l'autocomplétion avec la combinaison de touches Alt+Space.
+Remarque
+Ceci est un exemple complexe de remarque.
+La première ligne du fichier de remarque doit être vide
+La syntaxe markdown
est complètement préservée. Par exemple, un tableau :
a | +b | +c | +
---|---|---|
1 | +2 | +3 | +
Une admonition ?
+Vous pouvez inclure des admonitions et des superfences dans vos remarques.
+{{ IDEv('foo/bar/nom_de_fichier', MAX = 1000) }}
+
nom_de_fichier
dans un IDE avec division verticale. Le fichier doit être dans docs/scripts/foo/bar/
.
+Remarque
+Ceci est un exemple complexe de remarque.
+La première ligne du fichier de remarque doit être vide
+La syntaxe markdown
est complètement préservée. Par exemple, un tableau :
a | +b | +c | +
---|---|---|
1 | +2 | +3 | +
Une admonition ?
+Vous pouvez inclure des admonitions et des superfences dans vos remarques.
+Détails techniques
+Tous les IDE et les terminaux partagent le même namespace. On peut donc accéder à n'importe quelle fonction créée dans n'importe quel IDE ou terminal.
+C'est un comportement qui a l'avantage de pouvoir proposer des exercices où l'on construit petit à petit un code complexe.
+Exemples⚓︎
+L'exemple ci-dessous, obtenu avec {{ IDEv('exo2') }}
. N'hésitez pas à modifier le code pour calculer la moyenne, l'écart-type, afficher cela dans le terminal etc.
def sommation(T: list) -> int:bksl-nl a = 0bksl-nl for nombre in T:bksl-nl a = a + nombrebksl-nl return abksl-nlbksl-nldef somme(L: list) -> None or int:bksl-nl return None if len(L) == 0 else sum(L)bksl-nldef somme(L: list[int]) -> int:bksl-nl return None if len(L) == 0 else sum(L)bksl-nl
+A
+Remarque sur la solution
+C'est simple mais il faut être vigilant.
+Une autre remarque est possible
+Toujours simple mais toujours vigilant.
+Z
+L'exemple ci-dessous a été obtenu avec {{ IDE('algo_glouton') }}
.
# dictionnaire :bksl-nl# - clé : nom de l'objetbksl-nl# - valeur : tableau [poids, prix]bksl-nlinventaire = {"A": [13,700], "B": [12,650], "C": [6,250], "D": [6,400],"E": [5, 100]}bksl-nlbksl-nl# Calcule la valeur massique en divisant la 2ème valeur du tableau par la premièrebksl-nl# on ajoute cela à la valeur du dictionnairebksl-nlfor objet, (poids, prix) in inventaire.items():bksl-nl inventaire[objet].append(prix/poids)bksl-nlbksl-nl# Trie le tableau en ordre décroissant suivant la valeur massique.bksl-nldef f(dico: dict, col = 2):bksl-nl tableaupy-undtrié = sorted(dico.items(), key = lambda a: a[1][col], reverse=True)bksl-nl return {clé:valeur for clé, valeur in tableaupy-undtrié}bksl-nlbksl-nlbksl-nlinventaire = f(inventaire, 2)bksl-nlbksl-nlpoidspy-undmax = 30bksl-nlbksl-nl# Algorithme gloutonbksl-nldef gloutonnerie(inventaire : dict, poidspy-undmax:int=30):bksl-nl sacpy-undapy-unddos = []bksl-nl poidspy-undsac = 0bksl-nl for objet, (poids, prix, vpy-undmassique) in inventaire.items():bksl-nl if poidspy-undsac + poids <= poidspy-undmax:bksl-nl sacpy-undapy-unddos.append(objet)bksl-nl poidspy-undsac += poidsbksl-nl return sacpy-undapy-unddos, poidspy-undsacbksl-nlbksl-nlprint(gloutonnerie(inventaire, poidspy-undmax))bksl-nlbksl-nlbksl-nl
+A
+Z
+ + + + +