Aller au contenu

QCMs & QCSs#

alt



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 check : 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 restart

Légendes#

Bouton/icône Description
check
É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 :
restart
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.

qcm corrigé

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...)

  1. 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

  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.

  3. Cocher toutes les bonnes réponses
    meubles = ['Table', 'Commode', 'Armoire', 'Placard', 'Buffet']
    

    • meubles[1] vaut Table

    • meubles[1] vaut Commode

    • meubles[4] vaut Buffet

    • meubles[5] vaut Buffet

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 :
  • '!!!' : classique,
  • '???' : dépliable,
  • '???+' : repliable,
  • None : pas d'admonition autour du qcm.
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
  • None : automatique (défaut).
  • "ol" : questions numérotées.
  • "ul" : questions avec puces.
Définit le type de liste html utilisée pour construire les questions.
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 :

  1. Via le fichier mkdocs.yml du thème, bien sûr (dans la section plugins.pyodide_macros).
  2. 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".
  3. 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:
  • 'multi': bool, qui permet de désambiguer les questions à choix multiples ou simples.
  • 'shuffle': bool, qui indique si les items de cette question doivent être mélangés automatiquement ou pas (équivalent de l'argument shuffle_items, mais pour les items de cette question uniquement).

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 :

  1. 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
        ],
        ...
    ) }}
    


  2. 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
    ) }}
    


  3. Réglages globaux : fichiers .meta.pmt.yml.

    args:
        multi_qcm:
            multi: true
    

    Voir la page concernant la configuration et les métadonnées.


  4. 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 macro multi_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

  1. 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

  2. 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