This exercise type allows you to write, run, and evaluate Python code using Python code.
This exercise uses a fully functional text editor that supports syntax highlighting as an input field. Writing evaluations happens in a very similar environment, however, authors have the option to split their checks in multiple different blocks of code. Because we allow authors to grade Python with Python, this exercise type is extremely versatile with one major drawback, making Python exercises can be as easy or difficult as you want them to be.
Creating an exercise
Initially, creating a Python exercise is quite similar to creating other types of exercises on the SOWISO platform. The title and question field allow you to create the title and actual question for your Python exercise. You can also pre-define Python code for your students using the `placeholder` button under the `+ add` submenu.
Enabling external modules
In the `general` tab under `allow modules` we allow you to whitelist external libraries that you want your students to use in a Python exercise. The most notable are `math`, `numpy`, and `scipy`.
The Python exercise also works with SOWISO’s normal random variable system, even in the Python code itself.
The biggest difference between other exercise types is the manner in which Python exercises are evaluated. We allow teachers to write Python code to evaluate students’ Python code. This works by leveraging Python’s `assert` keyword. `assert` checks if an expression that follows it evaluates to `True`, if it doesn’t the Python program will halt. On the SOWISO platform, that means the student did not pass the evaluation. `assert` also allows you to specify a string that will be shown when the assertion is `False`, this is how we show feedback. Assertions have the general form:
> assert [expression], [feedback]
Additionally, we provide two constants `STDIN` and `STDOUT` that contain the student’s code and its output as strings.
> assert STDOUT == “Hello, world!\n”, “You did not print ‘Hello, world!’.”
This assertion checks whether the output of the student’s code is equal to “Hello, world!\n”. If it’s not, the feedback “You did not print ‘Hello, world!’.” is shown to the student. `STDIN` and `STDOUT` allow you to define simple and intuitive evaluations. However, be aware that especially `STDIN` can easily be abused. If you check for the use of a `for` loop, like so:
> assert “for” in STDIN, “Please use a for loop.”
Students can simply get around this check by writing `for` anywhere in their code, e.g. as a dummy variable or as a comment.
You can evaluate the contents of variables and functionalities of functions by simply referencing them in your evaluation code, the scope is shared between input and evaluation code. For example, if you ask your student to define a variable called `var` that contains an integer:
> assert isinstance(var, int), “`var` should contain an integer.”
We recommend constraining function and/or variable names in the question, if you want to evaluate their properties. While it’s possible to allow students to use their own names, it’s a lot easier to just constrain them beforehand and use relatively simple assertions.
Another helpful evaluation function to be aware of is `locals()`, `locals()` returns the names of all classes, functions and variables defined in the student’s scope. With `locals()` you can check whether a function or variable is actually defined by the student. Like so:
> assert “var” in locals(), “Please define the variable `var`.”
This is important to check for, since writing assertions that include references to `var` while it’s not defined by the student, will result in your evaluation code crashing. It is therefore recommended that you always start by checking if the variable or function you want to evaluate is actually defined.
As mentioned above, `STDIN` might not always suit your evaluation needs if you want more specific checks. If that is the case, the `ast` (abstract syntax trees) module will be your best friend. `ast` is a module that converts Python code to a parseable tree structure. To use `ast` import it like so:
> import ast
Then compile `STDIN`:
> module = compile(STDIN, “”, mode=“exec”, flags=ast.PyCF_ONLY_AST)
Now you can use `module` for very specific checking by using `ast` methods on `module`. You can find all of the `ast` functionality here. Be aware that the Python exercise currently runs Python 3.6.
We recommend using a separate check only containing:
> assert False, ast.dump(module)
for debugging when using `ast`.
While the Python exercise type is very versatile, it does not cover all functionalities of native Python. Having students write their own interactive scripts with `input()` is not something that the current implementation supports. Additionally, the output of students' code is also limited, the Python exercise type does not support the plotting of graphs or images at this moment.