# Automark

A minimalistic library that loads a Jupyter file and runs various tests on it, so it can assign a grade. Feature list is exactly 'what I needed at some point'.

* `automark.py`: Library of convenience code for use by an automark script.
* `mark_dir.py`: Runs an automark script on everything in a directory structure, as downloaded from Moodle, generating a spreadsheet. The spreadsheet will almost certainly contain problems that need to be resolved by a meat sack.
* `to_moodle.py`: Given the spreadsheet generated by above and a spreadsheet downloaded from Moodle this copies the marks over into the Moodle one.



## Automark Scripts

An automark script takes a single command line parameter, the filename of the script to mark, and works by printing out marks and information to the console, using the below format. Every line takes the form `kind: stuff` (ignoring blank lines); possible lines are:
* `Question: name` - All further messages apply to this question, until changed by another question line. Typically the name is the question number.
* `Mark: total / maximum` - Marks to assign to the current question. In the event of uncertainty it can also be low--high / maximum. Can be something like 0.25 / 0.5 if you're suitably mad.
* `Submark: group = number` - Mark for a group within a question; more a hint for a human as the number is folded into the `Mark` line. Can also give a low--high range.

* `Info: message` - Something that might be useful to a human checker, but not worth reporting back.
* `Warning: message` - Problem probably caused by the student. Ideally checked but probably them dropping marks with a bug.
* `Severe: message` - Problem that a human must look into.
* `Critical: message` - Error with the automarking process - results must be considered invalid.

Processing scripts ignore unrecognised lines.



## `automark.py`

A library to support automarking. Typically you start with:
```
injest = automark.InjestJupyter(automark.victim())
```
to load a Jupyter notebook (as provided on the command line). The inject object then provides an easy interface for accessing the output of each cell, running functions, getting data etc. If the workbook needs to load data you can send in a `cwd` parameter to save duplicating that for each workbook. Then you create Question() instances, to which you add judges. The question interface supports heavy configuration of how it calculates it's output, including the ability to pass uncertainty through as ranges of possible marks for a meat sack to resolve.

A Judge is just a function (one parameter, the above Injest object) that returns True if the code passes, False if it fails, and None if there is uncertainty and a human needs to check. The library provides a large number of functors for performing standard tests.

The best way to learn what this mini-library can do is to look at the provided examples.
