Skip to content
Snippets Groups Projects

Snipper

A lightweight framework for removing code from student solutions.

Installation

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:

A set of lectures notes where all code examples/output are automatically generated from the working repository can be found a

How it works

The basic functionality is quite simple. You start with your working script in your private repository and add special tags to the script. In this case I have added the tags #!b (cut a block) and #!f (cut function scope).

def myfun(): #!f The error I am going to raise
    """ The function docstring will not be removed"""
    print("This is a function")
    return 42
    
def a_long_function():
    a = 234
    print("a line")
    print("a line") #!b
    print("a line")
    print("a line") #!b Insert three missing print statements. 
    print("a line")
    return a
    
if __name__ == "__main__":
    myfun()

This will produce the following file:

def myfun():
    """ The function docstring will not be removed"""
    # TODO: 2 lines missing.
    raise NotImplementedError("The error I am going to raise")
    
def a_long_function():
    a = 234
    print("a line")
    # TODO: 3 lines missing.
    raise NotImplementedError("Insert three missing print statements.")
    print("a line")
    return a
    
if __name__ == "__main__":
    myfun()

You can also use the framework to capture code snippets, outputs and interactive python output. To do this, save the following in foo.py

def myfun(): #!s This snippet will be saved to foo.py in the output directory. 
    print("Hello") #!s 

print("Do not capture me") 
for i in range(4): #!o
    print("Output", i)
print("Goodbuy world") #!o
print("don't capture me")

# Interactive pythong example
print("Hello World") #!i #!i # this is a single-line cutout.

These block-tags will create a file foo.py (in the output directory) containing

def myfun():
    print("Hello") 

A file foo.txt containing the captured output

Output 0
Output 1
Output 2
Output 3
Goodbuy world

and a typeset version of an interactive python session in foo.pyi

>>> print("hello world")
Hello World"

All these files can be directly imported into LaTeX using e.g. minted: You never need to mix LaTeX code and python again!

Additional features:

  • Include references using \cite and \ref: This works by parsing your LaTeX .aux files and automatically keep your references in code synchronized with your written material. See the 02465 students repository for examples: None of the references to the exercise material or lecture notes are hard-coded!
  • 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.