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

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

Carlos

  • Moderador Global
  • ****
  • Mensajes: 294
Generador offline de preguntas para Moodle
« en: 12/Dic/2015, 21:59:39 pm »
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) [Seleccionar]
# -*- coding: utf-8 -*-
import jinja2
import codecs
import yaml
import os


# Establece las opciones por defecto
options = {
  'template_path': 'templates',
  'template': 'moodle.xml',
  'feedback': '',
  'shuffle': 0,
  'grade': 1,
  'penalty': 0.5,
  'image': '',
}


def main():
  for f in os.listdir('.'):
    process(f)


def process(fi_name):
  global options

  # Comprueba que el fichero de entrada es de tipo yaml
  if fi_name[-5:].lower() != '.yaml':
    return
  print 'Process', fi_name
 

  # print yaml.dump([1,2,3, [4, 5, 6], 7])
  # return

  # Lee los datos del fichero yaml   
  text = codecs.open(fi_name, 'r', 'utf-8').read()
  database = []
  for data in yaml.load_all(text):
    database.append(data)


  # Lee las cuestiones
  for data in database:

    # Read external options
    try:
      opt = data[0]['options']
      for item in opt:
        options[item] = opt[item]
      print '  Template =', options['template']
      data = data[1:]
    except:
      pass

    # Load and run template
    templateEnv = jinja2.Environment(loader=jinja2.FileSystemLoader(options['template_path']))
    template = templateEnv.get_template(options['template'])
    outputText = template.render(database=data, opt=options)

    # Elimina el BOM del fichero UTF8
    while (outputText[:1].encode('ascii', 'xmlcharrefreplace') == ''):
      outputText = outputText[1:].strip('\n\t ')

    # Write output file
    fout_name = fi_name[:-5] + '.xml'
    fo = codecs.open(fout_name, 'w', 'utf-8-sig')
    fo.write(outputText)
    fo.close()
    print '  Write', fout_name
 
main()

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 pm por Carlos »