markus-autotesting-core
markus-autotesting-core defines the data types for MarkUs autotester test settings. The types are msgspec structs, so one definition gives you both:
- validation: decoding settings JSON into typed objects, rejecting invalid settings
- a JSON schema: used by MarkUs to render the test settings form
Each tester (Python, Java, Haskell, …) defines its own settings by subclassing the base types here.
Installation
pip install markus-autotesting-core
Requires Python 3.11 or later.
Usage
Defining a tester's settings
Subclass BaseTestData for the settings of one test group, and BaseTesterSettings for the tester as a whole:
from typing import Annotated, Literal
from msgspec import Meta
from markus_autotesting_core.types import BaseTestData, BaseTesterSettings
class PyTestData(BaseTestData, kw_only=True):
"""The settings for one Python test group."""
tester: Literal["pytest", "unittest"] = "pytest"
class PyTesterSettings(BaseTesterSettings):
"""The settings for the Python tester."""
test_data: Annotated[list[PyTestData], Meta(title="Test Groups", min_length=1)]
BaseTestData provides the fields every test group has:
| Field | Type | Default |
|---|---|---|
category |
list[str], no duplicates |
required |
script_files |
list[str], at least one, no duplicates |
required |
timeout |
int, in seconds |
30 |
feedback_file_names |
list[str] |
[] |
extra_info |
any | {} |
BaseTesterSettings is a tagged union on the tester_type field. A subclass's tag is its class name without the TesterSettings suffix, lowercased, so PyTesterSettings is "py". To use a different tag, pass tag=:
class CustomTesterSettings(BaseTesterSettings, tag="custom"): ...
Decoding settings
create_autotest_settings_class builds the type for a complete settings document from the tester classes you have:
import msgspec
from markus_autotesting_core.types import create_autotest_settings_class
AutotestSettings = create_autotest_settings_class([PyTesterSettings])
settings = msgspec.json.decode(
b'{"testers": [{"tester_type": "py", "test_data": [{"category": ["instructor"], "script_files": ["test.py"]}]}]}',
type=AutotestSettings,
)
settings.testers[0].tester_type # "py"
settings.testers[0].test_data[0].timeout # 30
Invalid settings raise msgspec.ValidationError, with the location of the problem:
msgspec.json.decode(
b'{"testers": [{"tester_type": "py", "test_data": [{"category": [], "script_files": ["a.py", "a.py"]}]}]}',
type=AutotestSettings,
)
# msgspec.ValidationError: `script_files` contains duplicate items: ['a.py'] - at `$.testers[0].test_data[0]`
msgspec.to_builtins(settings) converts decoded settings back to plain dicts and lists, with defaults filled in.
Generating the JSON schema
schema, components = msgspec.json.schema_components([PyTesterSettings])
Some values depend on the assignment, so the schema refers to definitions that the consumer (MarkUs) fills in before rendering the form:
| Definition | Used for | Filled in with |
|---|---|---|
#/definitions/files_list |
each entry of script_files |
the assignment's test files |
#/definitions/test_data_categories |
each entry of category |
the test categories |
#/definitions/extra_group_data |
extra_info |
MarkUs's test group settings |
msgspec's decoder doesn't check these definitions, or other keywords added with Meta(extra_json_schema=...). The one exception is uniqueItems, which BaseTestData checks when decoding.
Development
The project uses uv.
uv sync
uv run pytest
Linting and formatting use ruff, and run as pre-commit hooks:
uv run ruff check .
uv run ruff format .
Contributions are welcome: please open an issue or a pull request.
License
MIT. See LICENSE.
Metadata
Release files for markus-autotesting-core 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| markus_autotesting_core-0.2.0.tar.gz | 4.6 kB | Without provenance | Details for markus_autotesting_core-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| markus_autotesting_core-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for markus_autotesting_core-0.2.0-py3-none-any.whl |
Total release size: 10.1 kB
Release files / markus_autotesting_core-0.2.0.tar.gz
| Download URL | markus_autotesting_core-0.2.0.tar.gz |
|---|---|
| Size | 4.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
44ffe5b6ae4fa01945db15a75fc35967ccf478ec8d2ed80f58e6480018829de2
|
|
BLAKE2b-256 checksum How to use checksums |
d43005e208aac14fbacf8f328be01eaae8fdc51d7d664bca8d7931c320bbf011
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / markus_autotesting_core-0.2.0-py3-none-any.whl
| Download URL | markus_autotesting_core-0.2.0-py3-none-any.whl |
|---|---|
| Size | 5.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bbf6c939bb365eeb8d1bdb0de687aaeda1b8b3ae65e1c65461cdc2d541043805
|
|
BLAKE2b-256 checksum How to use checksums |
3577d64afa2f60a264ab73cb9265e9cf4367ce2a26bc954b1941f87bc47fe88b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for markus-autotesting-core 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.