API

If you are looking for information on a specific function, class or method, this part of the documentation is for you.

This API documentation is generated using autodoc module of sphinx and curated documentation within source files. It is intented for developers to want to use classes and methods of worksheet.cc project. See Tutorial for an examples of usage.

Library

class wklib.Exercise(content: str)

This class models an exercise which might depend on some parameters. This exercise can be evaluated to produce an specific result which anyone could use as an usual exercise in classrooms.

To create an instance, you need to pass some text as its content:

>>> import wklib
>>> e = wklib.Exercise("Calculate 2 + 2")

In that example, the exercise does not depend on anything. But this could depend on some parameters. By convention, the parameters are put in parameters field in YAML-headers. Thus

>>> import wklib
>>> e2 = wklib.Exercise("""
... ---
... parameters:
...   a: '6'
... ---
...
... Calculate {{ params['a'] }} + 2
... """)

creates an instance of exercise to depend on parameter \(a\). Note that for accessing to the evaluation of the parameters, we use params hash.

Every exercise has associated a date of creation which is the date of instance creation. This can be accessed with self.creation. This is a string with ISO 8601 format.

Users can access to the content of the exercise using wklib.Exercise.text() method. In previous examples:

>>> e.text
'Calculate 2 + 2'
>>> e2.text
'Calculate {{ params['a'] }} + 2'

You can use also self.content, but it includes YAML headers, instead of previous method:

>>> e.content
'Calculate 2 + 2'
>>> e2.content
'\n---\nparameters:\n    a : '6'\n---\n\nCalculate {{ params['a'] }} + 2\n'

Both methods return raw content, without parameters being interpreted. Also notice that you can use simply print(e) because we overwrite __repr__.

To access to YAML-headers, you can use any method of frontmatter.Post, which can be accessed with self.post. For example, if you want to access to all keys from YAML header, you can type:

>>> sorted(e.post.keys())
[]
>>> sorted(e2.post.keys())
['parameters']

If you want to evaluated the exercise, that is, obtain an exercise with specific values of the parameters, then you need to use wklib.Exercise.value() method:

>>> e.value
'Calculate 2 + 2'
>>> e2.value
"\n---\nparameters:\n    a: '6'\n---\n\nCalculate 6 + 2"
>>> print(e2.value)

---
parameters:
   a: '6'
---

Calculate 6 + 2
Parameters:

content (str) – The content of the exercise. Just a string with optional YAML headers, delimited by --- lines at the very beginning of the text and just before the rest of the text.

__init__(content: str)

Creates an Exercise form a content string, which has an optional YAML-header.

The exercise consists of three variables:

self.content

which is a copy of content.

self.post

which is a frontmatter.Post built from the content. It allows to manage easyly the optional YAML block.

self.creation

The time of creation: datetime.datetime.now() represented as datetime.datetime.isoformat().

Parameters:

content (str) – The content of the exercise. Just a string with optional YAML headers

__repr__()

Returns self.content of the exercise. This includes YAML header, if any.

property text: str

Returns the text of the exercise without YAML header, if any.

>>> import wklib
>>> e = wklib.Exercise("""
... ---
... solution: 4
... resolution: 2 + 2 = (1 +1) + (1 + 1) = 1 + 1 + 1 + 1 = 4
... ---
...
... Calculate 2 + 2
... """)
>>> e.text
'Calculate 2 + 2'
Returns:

returns the content of the exercise, that is self.post.content

Return type:

str

property solution

Returns the solution of the exercise, that is solution if YAML header contains it as field.

>>> import wklib
>>> e = wklib.Exercise("""
... ---
... solution: 4
... resolution: 2 + 2 = (1 +1) + (1 + 1) = 1 + 1 + 1 + 1 = 4
... ---
...
... Calculate 2 + 2
... """)
>>> e.solution
4
Returns:

solution header if solution is present in YAML header and None otherwise.

Return type:

Union(str, None)

property resolution

Returns the resolution of the exercise, that is resolution if YAML header contains it as field.

>>> import wklib
>>> e = wklib.Exercise("""
... ---
... solution: 4
... resolution: 2 + 2 = (1 +1) + (1 + 1) = 1 + 1 + 1 + 1 = 4
... ---
...
... Calculate 2 + 2
... """)
>>> e.resolution
'2 + 2 = (1 + 1) + (1 + 1) = 1 + 1 + 1 + 1'
Returns:

resolution header of resolution is present in YAML header and None otherwise.

Return type:

Union(str, None)

property id: str

Returns a unique hash identification. This is mainly for reference purposes.

>>> import wklib
>>> e = wklib.Exercise("Calculate 2 + 2")
>>> e.id
'496c889309ba0f695582a4968466685173e9c7f823d7f81dc416412216f738a5'
# The previous string depends on the moment of instance creation
# It is different each time
Returns:

the hashlib.sha3_256() of self.content concatenated to self.creation

Return type:

str

property params: dict

Returns the evaluated parameters. It evaluates the self.post['parameters'] present in the YAML headers of the exercise. If it is not present, it returns {}.

>>> import wklib
>>> e = wklib.Exercise("""
... ---
... parameters:
...   a: random.randint(1,100)
... ---
...
... Calculate {{ params['a'] }} + 2
... """)
>>> e.params
{'a': 92}
Returns:

the evaluation of parameters present in YAML headers

Return type:

dict

property value: str

It applies the Jinja templating system in the whole exercise. It uses wklib.Exercise.params() to evaluate the rest of the content of the exercise, that is, it renders the exercise as Jinja template with hash params = self.params.

>>> import wklib
>>> e = wklib.Exercise("""
... ---
... parameters:
...   a: random.randint(1,100)
... ---
...
... Calculate {{ params['a'] }} + 2
... """)
>>> print(e.value)

---
parameters:
    a: random.randint(1,100)
---

Calculate 26 + 2
Returns:

The evaluation of self.content using self.params() as hash

Return type:

str

__weakref__

list of weak references to the object

class wklib.Collection(mylist, multiplicity={})

Just a set of exercises.

>>> a = wklib.Exercise("Calculate 2 + 2")
>>> b = wklib.Exercise("Calculate 3 + 4")
>>> c = wklib.Collection([a, b])

The set of exercises is accessed with self.exercises:

>>> c.exercises
[Calculate 2 + 2, Calculate 3 + 4]

You can use parameter multiplicity to repeat exercises:

>>> c.wklib.Collection([a, b], {0:3, 1:2}]
>>> c.exercises
[Calculate 2 + 2, Calculate 2 + 2, Calculate 2 + 2, Calculate 3 + 4, Calculate 3 + 4]
__init__(mylist, multiplicity={})

Creates a list of exercises. It stores that in self.exercises. If multiplicity is set, then the number of instances of certain elements of mylist is repeated accordingly.

Parameters:
  • mylist (list) – the list of element of the class Exercise.

  • multiplicity (dict) –

    the multiplicity (number of occurrences) of specific elements of mylist. The format of multiplicity is

    { position of element(i)  -> number of occurrences }.

    Example: if mylist = [a, b, c] and multiplicity = {0: 3}, then this function creates a collection of [a, a, a, b, c].

    Attention

    Note that the multiplicity begins from index 0.

__repr__()

Returns the representation of Collection as string. It just prints the comma-separated list of self.exercises

value(mytemplate, myhash={}) str

Evaluates all exercises in self.exercises and passes to mytemplate with optional myhash dict.

Specifically, it applies the Jinja templating system to all exercises and passes the result to mytemplate.

For example:

>>> import wklib
>>> a = wklib.Exercise("Calculate 2 + 2")
>>> b = wklib.Exercise("Calculate 3 + 4")
>>> c = wklib.Collection([a, b])
>>> t = "Worksheet: {% for e in exercises %}{{e}}|{% endfor %}"
>>> c.value(t)
'Worksheet: Calculate 2 + 2|Calculate 3 + 4|'

If we want to have title variable, we can pass its value in the hash:

>>> import wklib
>>> a = wklib.Exercise("Calculate 2 + 2")
>>> b = wklib.Exercise("Calculate 3 + 4")
>>> c = wklib.Collection([a, b])
>>> t = "Worksheet: {{title}} {% for e in exercises %}{{e}}|{% endfor %}"
>>> c.value(t, {'title': "This is my title"})
'Worksheet: This is my title Calculate 2 + 2|Calculate 3 + 4|'
Parameters:
  • mytemplate (str) –

    The template to which all data is passed.

    Attention

    Note that the syntax of the template is specific to Jinja. If someday, in a hypothetical future, the template system engine were to be changed, then the syntax of the templates would have to change as well (see #17).

  • myhash (dict) – Extra variables to pass to mytemplate

Returns:

The evaluation of mytemplate with self.exercises evaluated and myhash

Return type:

str

__weakref__

list of weak references to the object

wklib.extract_assignments(listofwords: List[str] | None, splitter: str = '=') dict

From a list of words separated by spaces, extracts assignments of values to variables. This function is mainly used in Terminal User Interface to extract optional metadata (with --metadata argument)

Example:

>>> splitter = ':'
>>> listofwords = "date:2022-04-02 title:'this is a title'"
>>> extract_assignments(listofwords, splitter)
{'date': '2022-04-22', 'title': 'this is a title'}

Note we just split once. So,

>>> splitter = ':'
>>> listofwords = "date:foo:bar"
>>> extract_assignments(listofwords, splitter)
{'date': 'foo:bar'}

Note that words without splitter will be ignored.

>>> splitter = ':'
>>> listofwords == "foo date:2022-04-02"
>>> extract_assignments(listofwords, splitter)
{'date': '2022-04-22'}
# 'foo' is ignored because it lacks splitter
Parameters:
  • listofwords (Optional[List[str]]) – A list of strings separated with spaces

  • splitter (str) – The character which is used to separate the listofwords into a hash of the form {variable, value}. By default it is =.

Returns:

The hash which contains the assignments of variables and their values.

Return type:

dict

wklib.evaluate_assignments(assignments: dict | None, evals: list | None) dict

Evaluates the assignments of values to variables from assignments which appear in evals list. This function is used mainly in Terminal User Interface to evaluate the optional metadata (with --evals argument)

Example:

>>> assignments == {'revision': '1'}
>>> evals = ['revision']
>>> evaluate_assignments(assignments, evals)
{'revision': 1}

If the cast is not possible, it casts the variable as str and not returning any error; just prints a warning message.

Parameters:
  • assignments (Optional[dict]) – A hash with assignments, that is {variable: value}

  • evals (Optional[list]) – A list of variables to be evaluated

Returns:

The hash which contains the assignments of variables and their values, which have been evaluated.

Return type:

dict

wklib.save(filename: str, content: str)

Saves content to file which is called filename. It is mainly used in Terminal User Interface

>>> save('foo.txt', "This is a test")
Parameters:
  • filename (str) – The name of the file in which content will be saved

  • content (str) – The content to save

wklib.run_process(command: str, filename: str, options: str = '', repetitions=1)

Runs command to filename. It is used mainly in Terminal User Interface to run postprocess (see --postprocess argument)

Example:

# The file 'foo.txt' has the content 'This is a test'
>>> run_process("cat", "foo.txt")
'This is a test'
Parameters:
  • command (str) – The shell commandline command to run

  • filename (str) – The name of the file to apply the command

  • options (str) – Options to command

  • repetitions (int) – Number of consecutive application of command

wklib.shortcut_run_process(command: str, filename: str, options: str = '')

Runs usual commands using shortcuts of run_process().

It is mainly used in Terminal User Interface to run common postprocessing tasks like LaTeX compilation.

>>> shortcut_run_process("pdflatex", "mydocument.tex")
# It complies "mydocument.tex" using pdflatex (producing "mydocument.pdf")
Parameters:
  • command (str) –

    This is a predefined set of commands:

    • lualatex: for LuaLaTeX processor. With options --halt-on-error --interaction=batchmode.

    • pdflatex: for PDFLaTeX processor. With option --halt-on-error.

    • context: for ConTeXt processor with options --purgeall --noconsole --batchmode.

  • filename (str) – The name of the file to apply the command

  • options (str) – Extra options to pass to command.

class wklib.Worksheet(template: str, exercises: List[str], multiplicity: Mapping[int, int] | None = {})

This class implements the concept of worksheet, that is, a collection of exercises.

In our case, the exercises are evaluated and passed to template. It produces an string outcome, which could be saved in a file and, optionally, process it to produce another file. Typically, a worksheet could be a PDF with several exercises which depend on some parameters that are evaluated to concrete exercises.

This class consists of:

  • a template, which can be accessed via self.template

  • a collection of exercises, which can be accessed via self.exercises.

__init__(template: str, exercises: List[str], multiplicity: Mapping[int, int] | None = {})

It creates a worksheet with given template and exercises files. The main purpose of the parameter multiplicity is to repeat specific exercises avoiding to repeat them in exercise list.

Example:

>>> import wklib
>>> w = wklib.Worksheet("template.txt", ["exercise-1.txt", "exercise-2.txt"])
Parameters:
  • template (str) – The template written in Jinja syntax which we pass evaluated files

  • exercises (List[str]) – A non-empty list of exercise files to render before pass them to template file

  • multiplicity (Optional[dict[int, int]]) –

    The multiplicity of each file of exercises in the form {position in the list mylist: its multiplicity}.

    Example: {0: 2, 3:5} which means that exercise in exercises at position 0 has multiplicity 2 and exercise at poaition 3 has multiplicity 5.

Returns:

A worksheet of exercises and template.

Return type:

wklib.Worksheet

__repr__()

Returns the representation as string of Worksheet. It just prints out the template file and the list of exercises.

value(metadata, savingfile: str = None, postprocess: str = None)

Returns the numerical value of the worksheet, that is the evaluated exercises passed to template. metadata argument is a hash with extra metada pass to self.template.

If savingfile is not None, then the result is saved, also, in a file specified in that name.

If postprocess is not None, then the result is saved in savingfile and then processed with command specified with postprocess. Several output files could be generated as a result of this processing.

Example:

$ cat template.txt
Worksheet:
{% for e in exercises %}
-{{e}}
{% endfor %}
$ cat exercise-1.txt
Calculate 2 + 2
$ cat exercise-2.txt
Calculate 3 + 4
# in the same path of previous files
>>> import wklib
>>> w = wklib.Worksheet('template.txt', ['exercise-1.txt', 'exercise-2.txt'])
>>> print(w.value({}))
Worksheet:
-Calculate 2 + 2
-Calculate 3 + 4

A more complex example is this:

# In 'src/' directory, we run python
>>> import wklib
>>> w = wklib.Worksheet("templates/exercise.midsize.context", ["exercises/pythagorean-theorem.calculate-hypotenuse.ca.md", "exercises/pythagorean-theorem.calculate-cathetus.ca.md"])
>>> w.value({'lang': 'ca'}, 'test.context', postprocess='context')
# test.context is saved in 'src' directory
# test.pdf is generated in 'src' directory.
Parameters:
  • metadata (dict) – A hash to pass to the template an extra information.

  • savingfile (str) – The filename to save the output.

  • postprocess (str) – The postprocess to run against savingfile. It is not arbitrary command: just a few predefined commands: lualatex, pdflatex and context for running LuaLaTeX, PDFLaTeX and ConTeXt, respectively.

Returns:

A string which represents the numerical value of the worksheet.

Return type:

str

__weakref__

list of weak references to the object

Terminal User Interface

This covers the functions to implement the terminal user interface wk.py (see Usage).

wk.cast_multiplicity(multiplicity: dict = {})

We cast multiplicity to a hash of type int:int.

>>> m = {'0': '1', '1': '3'}
>>> cast_multiplicity(m)
{0: 1, 1: 3}

It is mainly used to eval the --multiplicity option in Terminal User Interface (without having to use --evals which would imply more complexity for end users).

Parameters:

multiplicity (dict) – The dict of the multiplicity. Commonly as {str: str}.

Returns:

A dict of the form {int:int}.

Return type:

dict