Newer
Older
# Snipper
A lightweight framework for removing code from student solutions.
## Installation
```console
pip install codesnipper
```
## What it does
This project address the following three challenges for administering a python-based course
- You need to maintain a (working) version for debugging as well as a version handed out to students (with code missing)
- You ideally want to make references in source code to course material *"(see equation 2.1 in exercise 5)"* but these tend to go out of date
- You want to include code snippets and code output in lectures notes/exercises/beamer slides
- You want to automatically create student solutions
This framework address these problems and allow you to maintain a **single**, working project repository.
The project is currently used in **02465** at DTU. An example of student code can be found at:
- https://gitlab.gbar.dtu.dk/02465material/02465students/blob/master/irlc/ex02/dp.py
A set of lectures notes where all code examples/output are automatically generated from the working repository can be found a
- https://lab.compute.dtu.dk/tuhe/books (see **Sequential decision making**)
# Usage
All examples can be found in the `/examples` directory. The idea is all our (complete) files are found in the instructor directory and snipper keeps everything up-to-date:
```text
examples/cs101_instructor # This directory contains the (hidden) instructor files. You edit these
examples/cs101_students # This directory contains the (processed) student files. Don't edit these
examples/cs101_output # This contains automatically generated contents (snippets, etc.).
```
The basic functionality is you insert special comment tags in your source, such as `#!b` or `#!s` and the script then process
the sources based on the tags. The following will show most basic usages:
## The #f!-tag
Let's start with the simplest example, blocking out a function (see `examples/cs101_instructor/f_tag.py`; actually it will work for any scope)
You insert a comment like: `#!f <exception message>` like so:
```python
{{ cs101_instructor.f_tag_py }}
```
To compile this (and all other examples) use the script `examples/process_cs101.py`
{{ process_cs101_py }}
```
The output can be found in `examples/students/f_tag.py`. It will cut out the body of the function but leave any return statement and docstrings. It will also raise an exception (and print how many lines are missing) to help students.
```python
{{ cs101_students.f_tag_py }}
```
## The #b!-tag
The #!b-tag allows you more control over what is cut out. The instructor file:
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
{{ cs101_instructor.b_tag_py }}
```
Is compiled into:
```python
{{ cs101_students.b_tag_py }}
```
This allows you to cut out text across scopes, but still allows you to insert exceptions.
## The #s!-tag
The #!s-tag is useful for making examples to include in exercises and lecture notes. The #!s (snip) tag cuts out the text between
tags and places it in files found in the output-directory. As an example, here is the instructor file:
```python
{{ cs101_instructor.s_tag_py }}
```
Note it allows
- naming using the #!s=<name> command
- automatically join snippets with the same name (useful to cut out details)
- The named tags will be matched, and do not have to strictly contained in each other
This example will produce three files
`cs101_output/s_tag.py`, `cs101_output/s_tag_a.py`, and `cs101_output/s_tag_b.py` containing the output:
```python
{{ cs101_output.s_tag_py }}
```
and
```python
{{ cs101_output.s_tag_a_py }}
```
and finally:
```python
{{ cs101_output.s_tag_b_py }}
```
I recommend using `\inputminted{filename}` to insert the cutouts in LaTeX.
## The #o!-tag
The #!o-tag allows you to capture output from the code, which can be useful when showing students the expected
behavior of their scripts. Like the #!s-tag, the #!o-tags can be named.
As an example, Consider the instructor file
{{ cs101_instructor.o_tag_py }}
```
This example will produce two files `cs101_output/o_tag_a.txt`, `cs101_output/o_tag_b.txt`:
```python
{{ cs101_output.o_tag_a_py }}
```
and
```python
{{ cs101_output.o_tag_b_py }}
```
## The #i!-tag
The #!i-tag allows you to create interactive python shell-snippets that can be imported using the minted `pycon` environment ('\inputminted{python}{input.shell}').
As an example, consider the instructor file
{{ cs101_instructor.i_tag_py }}
```
This example will produce two files `cs101_output/i_tag_a.shell`, `cs101_output/i_tag_b.shell`:
and
```pycon
{{ cs101_output.i_tag_b_py }}
```
Note that apparently there
is no library for converting python code to shell sessions so I had to write it myself, which means it can properly get confused with multi-line statements (lists, etc.). On the plus-side, it will automatically insert newlines after the end of scopes.
My parse is also known to be a bit confused if your code outputs `...` since it has to manually parse the interactive python session and this normally indicates a new line.
## References and citations (`\ref` and `\cite`)
One of the most annoying parts of maintaining student code is to constantly write "see equation on slide 41 bottom" only to have the reference go stale because slide 23 got removed. Well now anymore, now you can direcly refence anything with a bibtex or aux file!
Let's consider the following example of a simple document with a couple of references: (see `examples/latex/index.pdf`):

Bibliography references can be loaded from `references.bib`-files and in-document references from the `.aux` file.
For this example, we will insert references shown in the `examples/latex/index.tex`-document. To do so, we can use these tags:
```python
{{ citations_orig_py }}
```
We can manually compile this example by first loading the aux-files and the bibliographies as follows:
```python
{{ load_references_a_py }}
```
Next, we load the python file containing the reference code and fix all references based on the aux and bibliography data.
```python
{{ load_references_b_py }}
```
The middle command is a convenience feature: It allows us to specify a special citation command `\nref{..}` which always compiles to `\cite[\ref{...}]{herlau}`. This is useful if e.g. `herlau` is the bibtex key for your lecture notes. The result is as follows:
```python
{{ citations_py }}
```
Note this example uses the low-level api. Normally you would just pass the bibtex and aux-file to the main censor-file command.
## Additional features:
- You can name tags using `#!s=bar` to get a `foo_bar.py` snippet. This is useful when you need to cut multiple sessions. This also works for the other tags.