QCMs & QCSs#
Le thème propose une macro multi_qcm
, qui permet de construire des groupes de questions :
- À choix simples ou multiples
- Avec évaluation automatique des résultats
- Avec ou sans affichage de la correction
- Avec ou sans mélange automatique des questions et/ou de leurs choix.
Les qcms sont "rejouables" à volonté et ont donc valeur d'évaluations formative.
Structure et fonctionnement#
Utilisation#
Il suffit de cocher ses réponses, et quand on a terminé, on clique sur le bouton de vérification : le compteur de réponses correctes s'affiche alors.
Note
- Un qcm devient inactif une fois l'évaluation déclenchée avec : cliquer sur les items ne modifie plus les choix.
- Une réponse est comptée bonne si tous les choix corrects, et seulement ceux-ci, ont été cochés pour une question.
- Si le qcm a un masque juste au-dessus du bouton de vérification, les points seront comptabilisés, mais les réponses correctes ou fausses ne seront pas affichées.
- Il est possible de recommencer le QCM en cliquant sur le bouton
Légendes#
Bouton/icône | Description |
---|---|
Évalue et corrige le qcm (pas de correction si le masque est affiché). Après avoir clické sur ce bouton, le qcm est inactif. Il peut alors être réactivé avec le bouton suivant : |
|
Recommencer le qcm : Efface les réponses, le compteur, et réactive l'ensemble. Mélange les questions et les items, si l'argument shuffle est True . |
|
Si le masque est affiché au-dessus du bouton de validation, les réponses sont évaluées mais pas corrigées : seul le compteur de bonnes réponses apparaît. |
Type choix |
Corrigé | Élément | Description |
---|---|---|---|
multiple | non | non choisie par l'utilisateur | |
multiple | non | choisie par l'utilisateur | |
multiple | oui | correcte, choisie par l'utilisateur | |
multiple | oui | incorrecte, choisie par l'utilisateur | |
multiple | oui | correcte mais non choisie | |
unique | non | non choisie par l'utilisateur | |
unique | non | choisie par l'utilisateur | |
unique | oui | correcte, choisie par l'utilisateur | |
unique | oui | incorrecte, choisie par l'utilisateur | |
unique | oui | correcte mais non choisie |
En résumé :
- Les carrés pour les QCMs : l'utilisateur peut en choisir autant qu'il veut.
- Les ronds pour les QCSs : chaque nouveau choix annule le précédent.
- En gris : non corrigé.
- En vert : correct.
- En rouge : incorrect.
En action...#
Un QCM avec mélange automatique des questions (bouton en bas pour recommencer)
(Une description additionnelle peut être ajoutée au début de l'admonition...)
-
On a saisi le code suivant :
n = 8 while n > 1: n = n//2
Que vaut
n
après l'exécution du code ?- 0
- 1
- 2
- 4
-
Quelle est la machine qui va exécuter un programme JavaScript inclus dans une page HTML ?
- La machine de l’utilisateur sur laquelle s’exécute le navigateur web.
- La machine de l’utilisateur ou du serveur, selon celle qui est la plus disponible.
- La machine de l’utilisateur ou du serveur, suivant la confidentialité des données manipulées.
- Le serveur web sur lequel est stockée la page HTML.
-
Cocher toutes les bonnes réponses
meubles = ['Table', 'Commode', 'Armoire', 'Placard', 'Buffet']
-
meubles[1]
vautTable
-
meubles[1]
vautCommode
-
meubles[4]
vautBuffet
-
meubles[5]
vautBuffet
-
code utilisé pour déclarer ce qcm
{{ multi_qcm(
[
"""
On a saisi le code suivant :
```python title=''
n = 8
while n > 1:
n = n//2
```
Que vaut `n` après l'exécution du code ?
""",
[
"0",
"1",
"2",
"4",
],
[2]
],
[
"Quelle est la machine qui va exécuter un programme JavaScript inclus dans une page HTML ?",
[
"La machine de l’utilisateur sur laquelle s’exécute le navigateur web.",
"La machine de l’utilisateur ou du serveur, selon celle qui est la plus disponible.",
"La machine de l’utilisateur ou du serveur, suivant la confidentialité des données manipulées.",
"Le serveur web sur lequel est stockée la page HTML."
],
[1],
],
[
"""
Cocher toutes les bonnes réponses
```python title=''
meubles = ['Table', 'Commode', 'Armoire', 'Placard', 'Buffet']
```
""",
[
"`#!py meubles[1]` vaut `#!py Table`",
"`#!py meubles[1]` vaut `#!py Commode`",
"`#!py meubles[4]` vaut `#!py Buffet`",
"`#!py meubles[5]` vaut `#!py Buffet`",
],
[2, 3],
{'multi':True}
],
multi = False,
qcm_title = "Un QCM avec mélange automatique des questions (bouton en bas pour recommencer)",
DEBUG = False,
shuffle = True,
description = "_(Une description additionnelle peut être ajoutée au début de l'admonition...)_\n{style=\"color:orange\"}"
) }}
La macro multi_qcm
#
Arguments#
La signature complète de la macro est la suivante :
{{ multi_qcm(
*questions: list = None,
*,
description: str = '',
hide: bool = False,
multi: bool = False,
shuffle: bool = False,
shuffle_questions: bool = False,
shuffle_items: bool = False,
admo_kind: str = '!!!',
admo_class: str = 'tip',
qcm_title: str = 'Question',
tag_list_of_qs: str = None,
DEBUG: bool = False,
) }}
Détails:
Argument | Type/défaut | Rôle |
---|---|---|
questions |
list |
Chaque argument individuel est une liste décrivant une question avec ses choix et réponses. Il est également possible de passer en unique argument un chemin relatif vers un fichier .json comportant une configuration complète (ou partielle) pour déclarer un multi_qcm . |
description |
'' |
Texte d'introduction (markdown) d'un QCM, ajouté au début de l'admonition, avant la première question. Cet argument est optionnel. |
hide |
False |
Si True , un masque apparaît au-dessus des boutons pour signaler à l'utilisateur que les réponses resteront cachées après validation. |
multi |
False |
Réglage pour toutes les questions du qcm ayant une seule bonne réponse, indiquant si elles doivent être considérées comme étant à choix simple ou multiples. |
shuffle |
False |
Mélange les questions et leurs choix ou pas, à chaque fois que le qcm est joué. |
shuffle_questions |
False |
Mélange les questions uniquement, à chaque fois que le qcm est joué. |
shuffle_items |
False |
Mélange seulement les items de chaque question, à chaque fois que le qcm est joué. |
admo_kind |
'!!!' |
Type d'admonition dans laquelle les questions seront rassemblées :
None permet d'ajouter du contenu markdown autour du qcm de manière plus fine, si besoin.À noter que l'admonition restera visible dans le markdown généré par la macro : elle sera supprimée dans la couche JS, au moment de l'affichage de la page html. |
admo_class |
'tip' |
Pour changer la classe d'admonition. Il est également possible d'ajouter d'autres classes si besoin, en les séparant par des espaces (exemple : 'tip inline end my-class' ). |
qcm_title |
'Question' |
Pour changer le titre de l'admonition. |
tag_list_of_qs |
str |
Si la valeur est None , '"ol" est utilisé, sauf s'il n'y a qu'une seule question pour le qcm, où c'est alors "ul" qui est utilisé. |
DEBUG |
False |
Si True , affiche dans la console le code markdown généré pour ce qcm. |
Modifier les valeurs par défaut des arguments
La configuration du plugin pyodide_macros
comporte, outre les réglages du plugin lui-même, les valeurs par défaut pour la quasi totalité des macros proposées par le thème.
Ces réglages peuvent être modifiés de différentes façons pour affecter un fichier, un dossier ou une hiérarchie de dossiers :
- Via le fichier
mkdocs.yml
du thème, bien sûr (dans la sectionplugins.pyodide_macros
). - Via des fichiers
.meta.pmt.yml
, qui peuvent être placés n'importe où dans la hiérarchie de la documentation et qui affectent tous les fichiers "descendants". - Via les métadonnées placées dans les entêtes des pages markdown elles-mêmes.
Données pour une question#
Il est possible de définir autant d'arguments *questions
que nécessaire, chaque question étant une liste python de 3 ou 4 éléments.
Un exemple avec deux questions :
multi_qcm(
["Fait-il beau ?", ['Oui', 'Non', "J'ai pas ouvert les volets"], [1], {"multi": False}],
["Fait-il vraiment beau ?", ['Oui', 'Non', "J'ai pas ouvert les volets"], [1,3]],
)
Les différents éléments de chaque liste sont, respectivement :
Type | Rôle |
---|---|
str |
Intitulé de la question. Cela peut être une simple phrase, un bloc de code, ou n'importe quoi de plus complexe, à condition d'utiliser une chaîne multilignes compatible. |
List[str] |
Ensemble des choix possibles pour cette question. Là aussi, une simple phrase, un bloc de code, ou une chaîne multilignes compatible. |
List[int] |
Indique les numéros des items corrects. Attention : ce ne sont pas des indices, donc démarrent à 1 ! |
Dict[str,Any] |
[Optionnel] Si fourni, un dictionnaire qui contient des options spécifiques à cette question.À l'heure actuelle, deux options sont utilisables:
|
Vérifications & comportements généraux#
1. Validité des données#
BuildError
est levée dans les cas suivants :
- Une question a des réponses correctes en doublons :
[1,1,4]
. - Une question a des réponses correctes invalides :
[6]
pour seulement 3 choix, ou[0,-1]
(rappel: les réponses sont données avec des numéros de choix, pas des indices). -
Une question n'a aucune réponse correcte renseignée et est par ailleurs à choix unique (
multi=False
).Questions à choix multiples sans réponses correctes
Formellement, une question à choix multiples pourrait n'avoir que des réponses fausses (même si cela implique que quelqu'un ne répondant pas à la question se verra crédité d'une réponse correcte).
Par défaut, le thème n'accepte pas ce type de situation et lève une erreur. Il est cependant possible d'autoriser cette situation en passant l'option de configuration
qcms.forbid_no_correct_answers_with_multi
àfalse
.
2. QCMs ou QCSs#
Le code considère automatiquement que toute question ayant deux réponses correctes ou plus est une question à choix multiples. Dans les autres cas, il faut préciser explicitement le type de comportement à utiliser.
Ceci peut être fait de différentes façons.
Chacun des réglages qui suivent est prioritaire sur les suivants, ce qui permet une assez bonne flexibilité lors de la rédaction des questions :
-
Réglage pour une question en particulier.
{{ multi_qcm( ..., [ "...", # Intitulé de la question [...], # Liste de choix possibles (List[str]) [1], # Réponse correcte (une seule => ambiguë) {"multi": True} # <<< ICI ; seulement cette question aura plusieurs choix possibles ], ... ) }}
-
Réglage pour toutes les questions d'un QCM, avec l'argument de la macro.
{{ multi_qcm( [...], # Question 1 [...], # Question 2 ..., multi = True, # <<< ICI ; Toutes les questions du qcm auront plusieurs choix possibles ) }}
-
Réglages globaux : fichiers
.meta.pmt.yml
.args: multi_qcm: multi: true
Voir la page concernant la configuration et les métadonnées.
-
Réglages globaux :
mkdocs.yml
:plugins: pyodide_macros: args: multi_qcm: multi: true # ou false (défaut: false)
Pièges à éviter#
Le code python est écrit dans un fichier markdown, interprété une première fois, puis passé en arguments à la macro multi_qcm
.
De ce fait, il y a un certain nombre de pièges à éviter lorsqu'on utilise des chaînes de caractères, et plus encore des chaînes multilignes.
Noter qu'il est possible de contourner ces problèmes en utilisant la déclaration des questions via un fichier .json
(impliquant alors de gérer à la place les contraintes liées au format JSON...).
1. LaTex#
Les caractères d'échappement, \
, dans les opérateurs LaTex doivent être eux-mêmes échappés, quand ils sont écrits dans les chaînes de caractères utilisées en arguments des macros.
Exemples :
Appel de macro | Rendu | Remarques |
---|---|---|
"... $a \times b$ ..." |
Erroné! | ... car \t est interprété comme une tabulation. |
"... $a \\times b$ ..." |
\(a \times b\) | |
"... $a \neq b$ ..." |
Erroné! | ... car \n est interprété comme une nouvelle ligne. |
"... $a \\neq b$ ..." |
\(a \neq b\) | |
"... $\infty$ ..." |
\(\infty\) | Correct mais génère DeprecationWarning |
"... $\\infty$ ..." |
\(\infty\) | |
"... $\mathbb{N}$ ..." |
\(\mathbb{N}\) | Correct mais génère DeprecationWarning |
"... $\\mathbb{N}$ ..." |
\(\mathbb{N}\) |
r-strings & f-strings
Dans le contexte des appels de macros, lesr-strings
de même que les f-strings
ne fonctionnent pas : r"$a \times b$"
lèverait une erreur.
2. Chaînes multilignes#
Le problème de la syntaxe#
Chaînes multilignes dans les templates Jinja
Le code tapé dans les appels de macro suit en fait la syntaxe des templates Jinja, qui n'est pas tout à fait équivalente à de la syntaxe python. En l'occurrence :
- Les syntaxes pour les chaînes multilignes n'existent pas, techniquement...
- ... mais toutes les chaînes sont en fait multilignes par défaut, quand écrites dans un template !
Vous pouvez donc utiliser les "triple quotes" de python, en tant que rappel visuel, mais il vous faudra systématiquement échapper les délimiteurs "simples" apparaissant dans la chaîne car l'interpréteur Jinja analyse en fait ces chaînes de la façon suivante :
{{ """...""" }}
est interprété comme{{ "" + "..." + "" }}
.{{ '''...''' }}
est interprété comme{{ '' + '...' + '' }}
.
Ces quatre déclarations donnent donc des résultats identiques :
{{ func("""
Hoho...
C'est une chaîne \"multilignes\" !
""")}}
{{ func("
Hoho...
C'est une chaîne \"multilignes\" !
")}}
{{ func('''
Hoho...
C\'est une chaîne "multilignes" !
''')}}
{{ func('
Hoho...
C\'est une chaîne "multilignes" !
')}}
Gestion des indentations#
Concernant les niveaux d'indentation utilisés dans une chaine
"multilignes", la macro leur applique successivement chaine.strip
, puis textwrap.dedent
, avant d'utiliser le contenu résultant.
Par conséquent, vous pouvez utiliser n'importe quel niveau de base, du moment que tout est cohérent pour une même chaîne et que vous n'allez pas sur la gauche du début de l'appel de macro multi_qcm
:
{{ multi_qcm(
[
"""
ceci...
...est valide.
On peut aussi mettre des choses
- plus \"complexes\"
mais ce n'est pas une obligation
```python
#ou des blocs de code
def somme(...):
...
```
""",
...
],
...
) }}
{{ multi_qcm(
["""
Vous pouvez aussi supprimer complètement l'indentation, si c'est plus facile
pour rédiger, mais il faut tout de même respecter l'indentation de base de
l'appel de la macro, c'est-à-dire qu'il faut être aligné avec ou sur la droite
du début de l'appel à `{{ multi_qcm(...`.
```python
# ça marchera encore...
def somme(...):
...
```
Notez que les espaces vides au début ou à la fin ne comptent pas : seules les
indentations dans la chaîne importent.
""",
...
],
...
) }}
{{ multi_qcm(
[
""" Ceci générera par contre...
...un markdown invalide car l'indentation n'est pas cohérente
avec la toute première ligne de la chaîne.
""",
...
],
...
) }}
!!! tip "L'indentation interne est à gauche de l'appel à `multi_qcm`"
{{ multi_qcm(
[ """
Trop à gauche !
```python
#ou des blocs de code
def somme(...):
...
```
""",
...
],
...
) }}
Fichiers .json
#
À partir de la version 2.4.0
du thème, il est possible d'utiliser des fichiers .json
pour déclarer des QCMs.
Ceci permet notamment de s'affranchir des pièges liés à la syntaxe Jinja, mais introduit d'autres contraintes (spécifiquement concernant les contenus multilignes, qui sont plus délicats à écrire)
Lorsque des fichiers .json
sont utilisés :
- Dans le fichier markdown, l'argument
*questions
de l'appel de macro doit être uniquement un chemin relatif vers le fichier.json
cible, contenant à minima toutes les informations sur les questions. - Le fichier
.json
doit contenir un unique objet dont les propriétés doivent être des noms d'arguments de la macromulti_qcm
. Seule la propriété"questions"
est obligatoire, toutes les autres sont optionnelles. - La valeur associée à la propriété
"questions"
doit être un tableau contenant les données pour chaque question, sous la forme de l'équivalent JSON des structures décrites plus haut (nota: les contenus multilignes doivent donc être rédigés en utilisant\n
pour les retours à la ligne). - Les autres arguments nommés de la macro peuvent toujours être utilisés pour remplacer les valeurs correspondantes ou manquantes dans le fichier
.json
. -
En termes de précédence, les données provenant des fichiers
.json
s'intercalent entre les données de configuration des macros et les arguments de l'appel de macro lui-même (sources, par priorité croissante) :\(mkdocs.yml \lt .meta.pmt.yml \lt Entêtes~markdown \lt JSON \lt arguments~macro\)
Les validations de données décrites ci-dessus s'appliquent toujours aux déclarations utilisant les fichiers .json
, ceux-ci n'étant qu'une nouvelle alternative pour définir les arguments de la macro multi_qcm
.
Exemple :
En imaginant la hiérarchie suivante de fichiers :
...
└── dossier
├── index.md
└── qcms
├── qcm1.json
...
L'appel de macro utilisé dans le fichier markdown est :
{{multi_qcm('qcms/qcm1.json', shuffle_questions=True)}}
Avec le contenu suivant pour le fichier qcm1.json
:
{
"questions": [
[
"Que peut faire Amandine(2d1) sachant qu'elle est connectée à un ordinateur du lycée",
[
"créer un fichier dans le dossier `prenom.nom`",
"créer un fichier dans le dossier `public` de 2d1",
"créer un fichier dans le dossier `public` de 2d4",
"créer un fichier dans le dossier `commun` de 2d1",
"créer un fichier dans le dossier `commun` de 2d4",
"créer un fichier sur le `bureau` de l'ordinateur"
],
[1,4,6]
],
[
"Marche aussi avec des accents: è à ê â î ï\n\n!!! tip \"Ou des admonitions?\"\n Et même des blocs de code, mais à rédiger en une seule chaîne JSON\n\n ```python\n def meh():\n print('yes')\n ```",
[
"1","2"
],
[2],
{"multi":true}
]
],
"multi": false,
"qcm_title": "QCM : Environnement de travail",
"DEBUG": false,
"shuffle_questions": false,
"shuffle_items": true
}
QCM : Environnement de travail
-
Que peut faire Amandine(2d1) sachant qu'elle est connectée à un ordinateur du lycée
-
créer un fichier dans le dossier
prenom.nom
-
créer un fichier dans le dossier
public
de 2d1 -
créer un fichier dans le dossier
public
de 2d4 -
créer un fichier dans le dossier
commun
de 2d1 -
créer un fichier dans le dossier
commun
de 2d4 -
créer un fichier sur le
bureau
de l'ordinateur
-
créer un fichier dans le dossier
-
Marche aussi avec des accents: è à ê â î ï
Ou des admonitions?
Et même des blocs de code, mais à rédiger en une seule chaîne JSON
def meh(): print('yes')
- 1
- 2