core

Main functionality.

In order to avoid tqdm’s experimental warning

Command-line arguments

The function below just parses command-line arguments and pass them to the build function below.


source

main

 main ()

Parses command-line arguments to be passed to build

Auxiliary functions

A function to obtain the __init__ parameters for a class from the corresponding settings.


source

init_parameters_from_settings

 init_parameters_from_settings (cls_settings:dict)

Returns a dictionary with the initialization parameters for a question

Type Details
cls_settings dict Settings for the class, which should include statement, feedback and, optionally, time
Returns dict Exact parameters that must be passed when instantiating the class.

The name for a testing file

input_file = '_input.yaml'
output file: quiz.yaml
pictures base directory: tc/midterm3

categories:

  - name: Test category

    classes:

      - name: TestClass

        question base name: Test class
            
        init parameters:
            
            distribution: Gaussian

        statement: |
          Consider a random variable, $X$, with mean $ \mu = !mean $ and variance...
          

        feedback: |
          Clearly, $Y$ is...
          

        time: 15
        
        number of instances: 2
Overwriting _input.yaml

The initialization parameters for the first class in the first category can be obtained as

input_data = py2gift.util.yaml_to_dict(input_file)    
init_parameters_from_settings(input_data['categories'][0]['classes'][0])
{'statement': un-filled template:
 Consider a random variable, $$X$$, with mean $$ \mu = $mean $$ and variance...,
 'feedback': Clearly, $Y$ is...,
 'time': 15,
 'distribution': 'Gaussian'}

If init_parameters is absent,

no_init_input_file = '_input2.yaml'
output file: quiz.yaml
pictures base directory: tc/midterm3

categories:

  - name: Test category

    classes:

      - name: TestClass

        question base name: Test class

        statement: |
          Consider a random variable, $X$, with mean $ \mu = !mean $ and variance...
          

        feedback: |
          Clearly, $Y$ is...
          

        time: 15
        
        number of instances: 2
Overwriting _input2.yaml

, then only basic parameters will be passed when instatiating the class

input_data = py2gift.util.yaml_to_dict(no_init_input_file)    
init_parameters_from_settings(input_data['categories'][0]['classes'][0])
{'statement': un-filled template:
 Consider a random variable, $$X$$, with mean $$ \mu = $mean $$ and variance...,
 'feedback': Clearly, $Y$ is...,
 'time': 15}

Processing of a bunch of questions

Building a GIFT file from generators’ settings

The workhorse of the library.


source

build

 build (settings:str|dict, local_run:bool, questions_module:module,
        parameters_file:str|dict='parameters.yaml', no_checks:bool=False,
        embed_images:bool=False)

Generates a GIFT file

Type Default Details
settings str | dict Settings for all the questions (generators)
local_run bool If True, pictures will not be copied to a remote host
questions_module module A module or structure to hold the classes referenced in the settings
parameters_file str | dict parameters.yaml Parameters to be passed to “gift-wrapper”
no_checks bool False If True LaTeX formulas are not be checked
embed_images bool False If True, images will be embedded in the questions (rather than linked)
Returns None

This function expects, among other things, an input file (defined above), a module implementing the classes referenced in the latter, and a parameters file.

Module with questions

This can be used in the same way as a module would.

class FakeModule:
    
    class TestClass(py2gift.question.NumericalQuestionGenerator):
        "Dumb testing class"
    
        def __init__(
            self, 
            statement: py2gift.question.TemplatedLatexText, # Statement of the question
            feedback: py2gift.question.TemplatedLatexText, # Feedback of the question
            distribution: str, # ?
            time: int | None = None, # Expectated time required to carry out the question
            prng: np.random.RandomState = np.random.RandomState(42) # Pseudo-random numbers generator
        ) -> None:

            super().__init__(statement, feedback, time, prng)
            
            self.distribution = distribution
        
        def setup(self):
            
            mean = np.random.rand()

            self.statement.fill(mean=mean)

            self.solution = 42
            self.error = '10%'

Parameters file

parameters_file = '_parameters.yaml'
images hosting:

  ssh:
    user: mvazquez

    # below, one should specify either a password for the user or  "public key" file but NOT both of them

    password:

    # "~" stands for the user's home directory (in Linux for one...)
    public_key: ~/.ssh/id_rsa_mymachine.pub

  copy:
    # machine into which files will be copied
    host: hidra1

    # the path that in the remote machine acts as root of the publicly visible directories hierarchy (hence it's not
    # visible from outside);  it *should* exist ("." stands for the working directory when you ssh into the machine)
    public filesystem root: ./public_html

  # public address from which the images will hang
  public URL: http://www.tsc.uc3m.es/~mvazquez/

latex:

  # auxiliary TeX file that will be created to check that formulas can be compiled
  auxiliary file: __latex_check.tex
Overwriting _parameters.yaml
build(input_file, local_run=True, questions_module=FakeModule, parameters_file=parameters_file, no_checks=True)
file "quiz.gift.txt" created

The file actually created underneath by build (the name, quiz.yaml, was set above in the input_file)

pictures base directory: tc/midterm3
categories:
  - name: Test category
    questions:
      - class: Numerical
        statement: "Consider a random variable, $X$, with mean $ \\mu = 0.863 $ and\
          \ variance...\n"
        feedback: "Clearly, $Y$ is...\n"
        time: '15'
        solution:
          value: 42
          error: 10%
        name: Test class I
      - class: Numerical
        statement: "Consider a random variable, $X$, with mean $ \\mu = 0.91 $ and\
          \ variance...\n"
        feedback: "Clearly, $Y$ is...\n"
        time: '15'
        solution:
          value: 42
          error: 10%
        name: Test class II

is ultimately processed by gift_wrapper to yield

$CATEGORY: $course$/Test category

::Test class I::[html]Consider a random variable, \\(X\\), with mean \\( \\mu \= 0.863 \\) and variance...<br><br><br><i>Estimated time\: 15 minutes</i><br>{
#   =%100%42:4.2#
    ####Clearly, \\(Y\\) is...
}

::Test class II::[html]Consider a random variable, \\(X\\), with mean \\( \\mu \= 0.91 \\) and variance...<br><br><br><i>Estimated time\: 15 minutes</i><br>{
#   =%100%42:4.2#
    ####Clearly, \\(Y\\) is...
}

This is the file that is actually imported from Moodle, and quiz.yaml is mostly a side effect.

!rm quiz.yaml quiz.gift.txt

One can also pass directly the dict with the settings.

settings = py2gift.util.yaml_to_dict(input_file)

build(settings, local_run=True, questions_module=FakeModule, parameters_file=parameters_file, no_checks=True)
file "quiz.gift.txt" created
pictures base directory: tc/midterm3
categories:
  - name: Test category
    questions:
      - class: Numerical
        statement: "Consider a random variable, $X$, with mean $ \\mu = 0.115 $ and\
          \ variance...\n"
        feedback: "Clearly, $Y$ is...\n"
        time: '15'
        solution:
          value: 42
          error: 10%
        name: Test class I
      - class: Numerical
        statement: "Consider a random variable, $X$, with mean $ \\mu = 0.793 $ and\
          \ variance...\n"
        feedback: "Clearly, $Y$ is...\n"
        time: '15'
        solution:
          value: 42
          error: 10%
        name: Test class II

Processing a single question

This is mostly intended for previewing a question in a jupyter notebook.

Building a single question

This function returns settings that allow building a question using gift-wrapper.


source

build_question

 build_question (question_generator:py2gift.question.QuestionGenerator,
                 category_name:str, settings:dict, n_question:int=0)

Returns the settings for building a question using “gift-wrapper”

Type Default Details
question_generator QuestionGenerator The question generator that will generate the appropirate settings
category_name str The name of category the class belongs to
settings dict User settings
n_question int 0 The number of instances to be returned
Returns dict Settings that allow building the question using “gift-wrapper”

For testing, we need some settings. It is more natural to read and write them in a file.

settings_file = '_settings.yaml'
output file: quiz.yaml
pictures base directory: pics

categories:

  - name: Category 1

    classes:

      - name: A

        question base name: A numerical question

        statement: What is...

        feedback: Well...

        parameters:

          - a: 5
            b: 3

      - name: A

        question base name: Another numerical question

        statement: What is...

        feedback: Well...
        
        number of instances: 2

  # -----------------------------

  - name: Category 2

    classes:

      - name: B

        question base name: A multiple-choice question

        init parameters:

          nodes: ['S1', 'S2']

        statement: |
          Consider...

        feedback: |
          We must...

        parameters: &dijkstra_parameters

          - n: 0

          - n: 1
            
  - name: Category 3

    classes:

      - name: C

        question base name: Another numerical question

        statement: What is...

        feedback: Well...
        
        number of instances: 2
Overwriting _settings.yaml

Next, we need to define the classes referenced above (A, B and C)

class A(py2gift.question.NumericalQuestionGenerator):
    
    def setup(self, a: int, b:int):
        
        self.solution = 42
        self.error =  '10%'

class B(py2gift.question.MultipleChoiceQuestionGenerator):
    
    def __init__(
        self, statement: py2gift.question.TemplatedLatexText, feedback: py2gift.question.TemplatedLatexText,
        nodes: list,
        time: int | None = None, prng: np.random.RandomState = np.random.RandomState(42)) -> None:
        
        super().__init__(statement, feedback, time, prng)
        
        self.nodes = nodes
    
    
    def setup(self, n:int):
        
        self.wrong_answers = [
            ['yes', 50],
            ['no', -50],
            ['nope', -50],
            ['yessss!!!', 50]
        ]

class C(py2gift.question.NumericalQuestionGenerator):
    
    def setup(self):
        
        self.solution = 52
        self.error =  '10%'
build_question(A, category_name='Category 1', settings=py2gift.util.yaml_to_dict(settings_file))
{'class': 'Numerical',
 'statement': 'What is...',
 'feedback': 'Well...',
 'solution': {'value': 42, 'error': '10%'}}
build_question(C, category_name='Category 3', settings=py2gift.util.yaml_to_dict(settings_file))
{'class': 'Numerical',
 'statement': 'What is...',
 'feedback': 'Well...',
 'solution': {'value': 52, 'error': '10%'}}

Previewing

The settings of a question (in the form of a dictionary),

question_settings = {
    'class': 'Numerical',
    'statement': 'What is the value of $\\pi$?',
    'solution': {'value': 3.14, 'error': '50%'},
    'feedback': 'well, $\\pi$'
}

, can be turned into a markdown string by py2gift.markdown.settings_to_markdown

py2gift.util.render_latex(py2gift.markdown.settings_to_markdown(question_settings))

Statement

What is the value of \(\Large \pi\)?

Feedback

well, \(\Large \pi\)

Solution

3.14 (error: .57)


source

generator_to_markdown

 generator_to_markdown (settings:str|pathlib.Path|dict, category:str, cls:
                        <module'py2gift.question'from'/home/runner/work/py
                        2gift/py2gift/py2gift/question.py'>)

Returns markdown text from a generator

Type Details
settings str | pathlib.Path | dict Settings
category str Category of the question
cls py2gift.question Class implementing the generator
Returns str Markdown text
py2gift.util.render_latex(generator_to_markdown(settings_file, category='Category 1', cls=A))

Statement

What is…

Feedback

Well…

Solution

42 (error: .2)

Preprocessing tex files

Function to turn a \(\TeX\) file into an svg. It returns a markdown string that allows to visualize it in a cell.


source

latex_to_markdown

 latex_to_markdown (input_file:str|pathlib.Path,
                    delete_input_file_afterwards:bool=False)

Returns markdown text that shows the result of compiling a TeX file

Type Default Details
input_file str | pathlib.Path TeX file
delete_input_file_afterwards bool False If True the TeX file is deleted after conversion to svg
Returns str Markdown text

A sample \(\TeX\) file,

tex_file = '_sample.tex'

, is written

\documentclass[]{standalone}

\usepackage[utf8]{inputenc}

\usepackage{tikz}


\begin{document}

\begin{tikzpicture}
    \node[draw, text width=60, align=center,font=\small,minimum height=80] {The Ingenious Gentleman Don Quixote of La Mancha};
\end{tikzpicture}

\end{document}
Overwriting _sample.tex

However, you can only run the cell below if you have a \(\LaTeX\) installation with TikZ

#py2gift.util.render_latex(latex_to_markdown(tex_file, delete_input_file_afterwards=True))