Autor Tema: Generador offline de preguntas para Moodle  (Leído 789 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Carlos

  • Moderador Global
  • ****
  • Mensajes: 325
Generador offline de preguntas para Moodle
« en: 12/Dic./2015, 21:59:39 p. m. »
Generador offline de preguntas para Moodle

Este pequeño programa en Python permite generar preguntas para Moodle con formato XML, a partir de  un archivo de texto con formato Yaml
Esto permite editar, generar y modificar las preguntas con mayor rapidez que con la interface de Moodle.
Es necesario conocer bien previamente, cómo rellenar los formularios de Moodle para generar preguntas.

Tipos de preguntas Moodle que se pueden generar: Cloze, Multichoice, Matching,
Las preguntas también se pueden agrupar por categorías.

Un pequeño ejemplo incluído ayuda a entender el formato del archivo de datos Yaml.

Para manejar las plantillas se utiliza el sistema de plantillas Jinja2.

Para ejecutar el programa, es necesario instalar previamente en el ordenador:
  Python 2.7
  Jinja 2
  MarkupSafe
  Yaml

Código Python:
Código: Python
  1. # -*- coding: utf-8 -*-
  2. import jinja2
  3. import codecs
  4. import yaml
  5. import os
  6.  
  7.  
  8. # Establece las opciones por defecto
  9. options = {
  10.   'template_path': 'templates',
  11.   'template': 'moodle.xml',
  12.   'feedback': '',
  13.   'shuffle': 0,
  14.   'grade': 1,
  15.   'penalty': 0.5,
  16.   'image': '',
  17. }
  18.  
  19.  
  20. def main():
  21.   for f in os.listdir('.'):
  22.     process(f)
  23.  
  24.  
  25. def process(fi_name):
  26.   global options
  27.  
  28.   # Comprueba que el fichero de entrada es de tipo yaml
  29.   if fi_name[-5:].lower() != '.yaml':
  30.     return
  31.   print 'Process', fi_name
  32.  
  33.  
  34.   # print yaml.dump([1,2,3, [4, 5, 6], 7])
  35.   # return
  36.  
  37.   # Lee los datos del fichero yaml  
  38.   text = codecs.open(fi_name, 'r', 'utf-8').read()
  39.   database = []
  40.   for data in yaml.load_all(text):
  41.     database.append(data)
  42.  
  43.  
  44.   # Lee las cuestiones
  45.   for data in database:
  46.  
  47.     # Read external options
  48.     try:
  49.       opt = data[0]['options']
  50.       for item in opt:
  51.         options[item] = opt[item]
  52.       print '  Template =', options['template']
  53.       data = data[1:]
  54.     except:
  55.       pass
  56.  
  57.     # Load and run template
  58.     templateEnv = jinja2.Environment(loader=jinja2.FileSystemLoader(options['template_path']))
  59.     template = templateEnv.get_template(options['template'])
  60.     outputText = template.render(database=data, opt=options)
  61.  
  62.     # Elimina el BOM del fichero UTF8
  63.     while (outputText[:1].encode('ascii', 'xmlcharrefreplace') == ''):
  64.       outputText = outputText[1:].strip('\n\t ')
  65.  
  66.     # Write output file
  67.     fout_name = fi_name[:-5] + '.xml'
  68.     fo = codecs.open(fout_name, 'w', 'utf-8-sig')
  69.     fo.write(outputText)
  70.     fo.close()
  71.     print '  Write', fout_name
  72.  
  73. main()
  74.  

Codigo Jinja:
Código: [Seleccionar]
{#
  moodle.xml
  ~~~~~~~~~~
  Template for moodle questions
  :license: Licencia Creative Commons Atribución Compartir Igual 3.0
#}


{###############################################################}
{%- macro category(name) %}

<!--  category  -->
<question type="category">
  <category><text>{{name}}</text></category>
</question>
{% endmacro -%}


{###############################################################}
{%- macro cloze(name, data, feedback="", shuffle=0) %}

<!--  cloze question: {{name}}  -->
<question type="cloze">
  <name><text>{{name}}</text></name>
  <questiontext><text>
  {%- block cloze_questiontext scoped -%} {{data}} {%- endblock %}
  </text></questiontext>
  <generalfeedback><text>{{feedback}}</text></generalfeedback>
  <shuffleanswers>{{shuffle}}</shuffleanswers>
</question>
{% endmacro -%}


{###############################################################}
{%- macro matching(name, data, image='', feedback="", grade=1, penalty=0.5, shuffle=0) %}

<!--  matching question: {{name}}  -->
<question type="matching">
  <name><text>{{name}}</text></name>
  <questiontext format="html"><text>{{data.0}}</text></questiontext>
  <image>{{image}}</image>
  <generalfeedback><text>{{feedback}}</text></generalfeedback>
  <defaultgrade>{{grade}}</defaultgrade>
  <penalty>{{penalty}}</penalty>
  <hidden>0</hidden>
  <shuffleanswers>{{shuffle}}</shuffleanswers>
  {%- for question in data[1:] -%}
  <subquestion>
    <text>{{question.0}}</text><answer><text>{{question.1}}</text></answer>
  </subquestion>
  {%- endfor -%}
</question>
{% endmacro -%}


{###############################################################}
{%- macro multichoice(name, data, image='', feedback="", grade=1, penalty=0.5, shuffle=0) %}

<!--  multichoice question: {{name}}  -->
<question type="multichoice">
  <name><text>{{name}}</text></name>
  <questiontext format="html"><text>{{data.0}}</text></questiontext>
  <image>{{image}}</image>
  <generalfeedback><text>{{feedback}}</text></generalfeedback>
  <defaultgrade>{{grade}}</defaultgrade>
  <penalty>{{penalty}}</penalty>
  <hidden>0</hidden>
  <shuffleanswers>{{shuffle}}</shuffleanswers>

  <single>false</single>
  <shuffleanswers>true</shuffleanswers>
  <correctfeedback><text></text></correctfeedback>
  <partiallycorrectfeedback><text></text></partiallycorrectfeedback>
  <incorrectfeedback><text></text></incorrectfeedback>
  <answernumbering>abc</answernumbering>

  {%- for ans in data[1:] %}
  <answer fraction="{{ans.0}}">
    <text>{{ans.1}}</text> {# Respuesta correcta #}
    <feedback><text>{{ans.2}}</text></feedback>
  </answer>
  {%- endfor %}
</question>
{% endmacro -%}


{###############################################################}
{%- macro all_quizs() -%}
  {%- for data in database -%}
  {%- if 'penalty' in data %} {% set penalty = data.penalty %}  {% else %} {% set penalty = opt.penalty %}   {% endif -%}
  {%- if 'image' in data %}   {% set image = data.image %}      {% else %} {% set image = opt.image %}       {% endif -%}
  {%- if 'grade' in data %}   {% set grade = data.grade %}      {% else %} {% set grade = opt.grade %}       {% endif -%}
  {%- if 'feedback' in data %}{% set feedback = data.feedback %}{% else %} {% set feedback = opt.feedback %} {% endif -%}
  {%- if 'shuffle' in data %} {% set shuffle = data.shuffle %}  {% else %} {% set shuffle = opt.shuffle %}   {% endif -%}

  {%- if 'category' in data -%}
  {{category(data.category)}}

  {%- elif 'matching' in data -%}
  {%- if 'name' in data %}    {% set name = data.name %}        {% else %} {% set name = data.matching[0] %}  {% endif -%}
  {%- if 'quiz' in data %}    {% set quiz = data.quiz %}        {% else %} {% set quiz = data.matching[1:] %} {% endif -%}
  {{matching(name, quiz, image, feedback, grade, penalty, shuffle)}}
 
  {%- elif 'multichoice' in data -%}
  {%- if 'name' in data %}    {% set name = data.name %}        {% else %} {% set name = data.multichoice[0] %}  {% endif -%}
  {%- if 'quiz' in data %}    {% set quiz = data.quiz %}        {% else %} {% set quiz = data.multichoice[1:] %} {% endif -%}
  {{multichoice(name, quiz, image, penalty, grade, feedback, shuffle)}}

  {%- elif 'cloze' in data -%}
  {%- if 'name' in data %}    {% set name = data.name %}        {% else %} {% set name = data.cloze[0] %}  {% endif -%}
  {%- if 'quiz' in data %}    {% set quiz = data.quiz %}        {% else %} {% set quiz = data.cloze[1:] %} {% endif -%}
  {{cloze(name, quiz, feedback, shuffle)}}
 
  {%- endif -%}
  {%- endfor -%}
{%- endmacro -%}


{###############################################################}
{%- block main -%}
<?xml version="1.0" encoding="UTF-8"?>
<quiz>
{{all_quizs()}}

</quiz>
{%- endblock -%}

Archivo de ejemplo en lenguaje Yaml:
Código: [Seleccionar]
#
# Examples of quizs for moodle
#


---
- options: {
  template_path: templates,
  template: examples.xml,
  grade: 1,
  penalty: 0.5,
  shuffle: 1,
  feedback: ''}

#
# Category: name of category
#
- category: $course$/ejemplos


#
# multichoice:
#   data: quiz_name, question, [% points, answer1, feedback1], ...
#   options: image, grade, penalty, shuffle, feedback
#
- multichoice:
  - Name - Multichoice
  - Question = Escoge las opciones correctas
  - [50, 'uno mas uno es dos', Ok]
  - [50, 'dos mas dos es cuatro', Ok]
  - [-50, 'Tres más tres es cinco', 'Mal']
  - [-50, 'Tres más cuatro es ocho', '']
  penalty: 0.3


#
# matching:
#   data: quiz_name, question, [% points, answer1, feedback1], ...
#   options: image, grade, penalty, shuffle, feedback
#
- matching:
  - Name - Matching
  - Question = escoge la respuesta correcta en cada caso
  - ['pregunta1', 'respuesta1']
  - ['pregunta2', 'respuesta2']
  - ['pregunta3', 'respuesta3']
  grade: 2


#
# cloze options: shuffle, feedback
#
- cloze:
  - Name - Cloze question
  - [SaddleBrown, black, '#E8C840', '#E8C840']
  - "{1:SHORTANSWER:%100%1.0~%100%1}"
  shuffle: 1
  feedback: 'Muy Bien'

Nota: Todos los programas se suministran bajo licencia GPL v3
« Última modificación: 13/Dic./2015, 13:20:34 p. m. por Carlos »