Skip to content
Snippets Groups Projects
README.jinja.md 8.16 KiB
Newer Older
  • Learn to ignore specific revisions
  • tuhe's avatar
    tuhe committed
    # 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
    
    
    tuhe's avatar
    tuhe committed
     - Maintain a (working) version for debugging as well as a version handed out to students (with code missing)
     - Use LaTeX references in source code to link to course material (i.e. `\ref{mylabel}` -> *"(see equation 2.1 in exercise 5)"*)
     - Including code snippets and console output in lectures notes/exercises/beamer slides
     - Automatically create student solutions
    
    tuhe's avatar
    tuhe committed
    This framework address these problems and allow you to maintain a **single**, working project repository. Below is an example of the snippets produced and included using simple `\inputminted{python}{...}` commands (see the `examples/` directory):
    
    ![LaTeX sample]({{resources}}/docs/latex_nup.png)
    
    tuhe's avatar
    tuhe committed
    
    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
    
    tuhe's avatar
    tuhe committed
    the sources based on the tags.  The following will show most common usages:
    
    tuhe's avatar
    tuhe committed
    ## 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`
    
    tuhe's avatar
    tuhe committed
    ```python
    
    {{ 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 }}
    ```
    
    
    tuhe's avatar
    tuhe committed
    ## The #!b-tag
    
    The #!b-tag allows you more control over what is cut out. The instructor file:
    
    tuhe's avatar
    tuhe committed
    ```python
    
    {{ 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. 
    
    
    tuhe's avatar
    tuhe committed
    ### Extra arguments
    
     - `silent`: No output
     - `nolines`: Don't printn umber of removed lines
     - `noerror`: Don't raise Exceptions (useful in top-level code blocks)
    
    tuhe's avatar
    tuhe committed
    ## 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. 
    
    
    
    tuhe's avatar
    tuhe committed
    ## 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
    
    tuhe's avatar
    tuhe committed
    ```python
    
    {{ cs101_instructor.o_tag_py }}
    ```
    This example will produce two files `cs101_output/o_tag_a.txt`, `cs101_output/o_tag_b.txt`:
    
    {{ cs101_output.o_tag_a_txt }}
    
    {{ cs101_output.o_tag_b_txt }}
    
    tuhe's avatar
    tuhe committed
    ## 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
    
    tuhe's avatar
    tuhe committed
    ```python
    
    {{ cs101_instructor.i_tag_py }}
    ```
    This example will produce two files `cs101_output/i_tag_a.shell`, `cs101_output/i_tag_b.shell`:
    
    tuhe's avatar
    tuhe committed
    ```pycon
    
    {{ cs101_output.i_tag_a_shell }}
    
    tuhe's avatar
    tuhe committed
    ```
    
    {{ cs101_output.i_tag_b_shell }}
    
    ```
    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 not 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`):
    
    
    ![LaTeX sample]({{resources}}/docs/index.png)
    
    The code for this document is:
    ```latex
    {{index_tex}}
    ``` 
    
    
    To use the references in code we first have to load the `references.bib` file and the `index.aux`-file and then:
     - Snipper allows you to directly insert this information using `\cite` and `\ref`
     - You can also define custom citation command which allows you to reference common sources like 
    
       - Lecture notes
        - Exercise sheets
        - Slides for a particular week
    
    Let's look at all of these in turn. The file we will consider in the instructor-version looks like this: (`examples/cs101_instructor/references.py`):
    
    tuhe's avatar
    tuhe committed
    ```python
    
    {{ cs101_instructor.references_py }}
    
    tuhe's avatar
    tuhe committed
    ```
    
    Note the last parts of the file contains the special commands `\nref` (references to lecture notes) and `\aref2` (assignment 2) which I want to define. 
    This can be done by changing the call to snipper as follows (`examples/process_cs101_references.py`)
    ```python
    {{ process_cs101_references_py }}
    
    tuhe's avatar
    tuhe committed
    ```
    
    And this then produce the output:
    ```python
    {{ cs101_students.references_py }}
    
    tuhe's avatar
    tuhe committed
    ```
    
    Since the aux/bibtex databases are just dictionaries it is easy to join them together from different sources. 
     I have written reference tags to lecture and exercise material as well as my notes and it makes reference management very easy. 
    
    # Partial solutions
    
    The default behavior for code removal (#!b and #!f-tags) is to simply remove the code and insert the number of missing lines.
    We can easily create more interesting behavior. The code for the following example can be found in `examples/b_example.py` and will deal with the following problem:
    ```python
    {{ cs101_output.sieve_py }}
    ```
    
    The examples below shows how we can easily define custom functions for processing the code which is to be removed; I have not included the functions here for brevity, 
    but they are all just a few lines long and all they do is take a list of lines (to be obfuscated) and return a new list of lines (the obfuscated code). 
    
    ### Example 1: Permute lines
    
    This example simple randomly permutes the line and prefix them with a comment tag to ensure the code still compiles
    ```python
    {{ cs101_output.obscure_1_py }}
    ```
    
    ### Example 2: Partial replacement
    
    This example replaces non-keyword, non-special-symbol parts of the lines:
    ```python
    {{ cs101_output.obscure_2_py }}
    ```
    
    
    ### Example 3: Half of the solution
    The final example displays half of the proposed solution:
    
    ```python
    {{ cs101_output.obscure_3_py }}
    ```
    
    tuhe's avatar
    tuhe committed
    
    
    
    tuhe's avatar
    tuhe committed
    # Citing
    
    tuhe's avatar
    tuhe committed
    ```bibtex
    {{bibtex}}
    
    tuhe's avatar
    tuhe committed
    ```