Skip to main content

A basic collection of tools to aid in the process of grading Python assignments while also attempting to reduce cheating through various methods.

Project description

Grading Utils

A collection of utilities for grading Python assignments.

Utilities are based off some common unit testing patterns. Overall, syntax is modelled off JavaScript's Jest syntax, with some modifications (hence camelCase, for example).

Design Philosophy:

  • security
  • simplicity
  • immutability

Matchers and Modifiers

The most common operations with this module will involve matching test values to expected values. All matchers begin with the expect(value) syntax, and are chained by some matcher. For example, if we want to test $f(x) = x^2$, we write:

from grading_utils.GradingUtils import expect

expect(f(2)).toEqual(4)

In this case, we could also write:

expect(f(2)).toBe(4)

which will check for referential equality amonst the two objects. However, use caution when using .toBe() to compare objects for equality, as this will not use obj.__eq__ or obj.__hash__ to compare objects. Matchers behave similarly to Python's assert, but provide more context on error.

Generally, matchers accept any type for which they are logically defined. For example, .toBeApprox(2.5, eps=0.1) works for numeric types.

Matchers with Callable Objects

Typically, we want to check the output of a function, so we call the function and pass its result to the expectation (expect(f(x))). Occasionally, matchers need to track the way functions behave. For example, let avg(l: iter) = sum(iter) / len(iter). If we want to check whether [] throws ZeroDivisionError, we can write:

expect(avg).toThrow(ZeroDivisionError, [])

Thus, we pass the function (uncalled) to our expect call, then we pass toThrow's custom argument (the exception to except), and then all arguments to the function to the .toThrow call. This is an unfortunate limitation, but this works for the time being. In the future, some decorator workaround may be implemented.

List of Matchers

The following matchers are currently defined:

  • toBe
  • toEqual
  • toBeApprox
  • toMatchType
  • toMatch
  • toContain
  • toBeGreaterThan
  • toBeLessThan
  • toThrow

Modifiers

Modifiers are used to modify the behavior of matchers, by modifying the underling "Expectation" object. Most commonly, we may want to expect that a certain condition is not met. We can chain modifiers for thus purpose. Modifiers use ._modifier_name syntax, with () if arguments are needed. There are currently only 3 modifiers:

._not

This modifier negates the expectation. For $$f(x) = x^2$$:

expect(f(2))._not.toBeGreaterThan(2) # throws GradingError
._exception(e)

If we want to throw a custom exception when a matcher fails.

expect(f(2))._exception(UrAnAwfulProgrammerError).toBe(4)
._maxtime(s)

This is one of 3 existing options for timing. The _maxtime modifier should be used similarly to a matcher with callables. To set a 2-second time limit on slow_reducer(some_set), and expect a result of True we write:

expect(slow_reducer)._maxtime(2, some_set).toBe(True)

For all timing semantics, see the dedicated timing section.

Looking Forward

_and and _or are some potential future modifiers.

Timing

One critical aspect of any timer implementation is that for long running functions, we want to keep grading time down; execution should be immediately stopped when the time limit is reached, with a fail error. This avoids functions from taking needlessly long times when they will fail anyways. All times are given in seconds.

Three methods are provided for time limiting functions:

with timer(5):
    expect(slow_reducer(some_set)).toBe(True)

Or, when defining functions:

@time_limit(5)
def slow_reducer(some_set):
    pass # implementation here
expect(slow_reducer(some_set)).toBe(True)

Naturally, this can be easily used to wrap student solutions.

Finally, the _maxtime modifier can be used directly:

expect(slow_reducer)._maxtime(2, some_set).toBe(True)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grading-utils-0.2.tar.gz (5.1 kB view details)

Uploaded Source

File details

Details for the file grading-utils-0.2.tar.gz.

File metadata

  • Download URL: grading-utils-0.2.tar.gz
  • Upload date:
  • Size: 5.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.7.1 importlib_metadata/4.10.0 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

File hashes

Hashes for grading-utils-0.2.tar.gz
Algorithm Hash digest
SHA256 7c1398f282070652dc91113d90b49d5a4bc269f0a1fbe3c10c75cfe9abed3260
MD5 91bdc78ed8d44f32f6f8c8cfb6524141
BLAKE2b-256 fc83f861567848f27f6061df0586296be18fc3e5b0f80cb4c08214af39333416

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page