morvix 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- morvix-0.1.0/.github/workflows/ci.yml +86 -0
- morvix-0.1.0/.github/workflows/publish.yml +38 -0
- morvix-0.1.0/.gitignore +23 -0
- morvix-0.1.0/CLAUDE.md +81 -0
- morvix-0.1.0/LICENSE +21 -0
- morvix-0.1.0/PKG-INFO +126 -0
- morvix-0.1.0/README.md +83 -0
- morvix-0.1.0/documentation.md +831 -0
- morvix-0.1.0/morvix/__init__.py +10 -0
- morvix-0.1.0/morvix/__main__.py +8 -0
- morvix-0.1.0/morvix/adapters/__init__.py +117 -0
- morvix-0.1.0/morvix/adapters/c.py +85 -0
- morvix-0.1.0/morvix/adapters/cpp.py +83 -0
- morvix-0.1.0/morvix/adapters/java.py +108 -0
- morvix-0.1.0/morvix/adapters/nasm.py +94 -0
- morvix-0.1.0/morvix/adapters/python.py +53 -0
- morvix-0.1.0/morvix/adapters/rust.py +70 -0
- morvix-0.1.0/morvix/app.py +75 -0
- morvix-0.1.0/morvix/banner.py +22 -0
- morvix-0.1.0/morvix/cases.py +129 -0
- morvix-0.1.0/morvix/commands/__init__.py +1 -0
- morvix-0.1.0/morvix/commands/bruteforce_cmd.py +45 -0
- morvix-0.1.0/morvix/commands/clean_cmd.py +53 -0
- morvix-0.1.0/morvix/commands/config_cmd.py +179 -0
- morvix-0.1.0/morvix/commands/exit_cmd.py +14 -0
- morvix-0.1.0/morvix/commands/gen_cmd.py +219 -0
- morvix-0.1.0/morvix/commands/help_cmd.py +99 -0
- morvix-0.1.0/morvix/commands/import_cmd.py +86 -0
- morvix-0.1.0/morvix/commands/init_cmd.py +111 -0
- morvix-0.1.0/morvix/commands/model_cmd.py +56 -0
- morvix-0.1.0/morvix/commands/open_cmd.py +69 -0
- morvix-0.1.0/morvix/commands/package_cmd.py +109 -0
- morvix-0.1.0/morvix/commands/reference_cmd.py +60 -0
- morvix-0.1.0/morvix/commands/result_cmd.py +228 -0
- morvix-0.1.0/morvix/commands/run_cmd.py +139 -0
- morvix-0.1.0/morvix/commands/runner_cmd.py +327 -0
- morvix-0.1.0/morvix/commands/status_cmd.py +75 -0
- morvix-0.1.0/morvix/commands/workflow_cmd.py +140 -0
- morvix-0.1.0/morvix/comparators.py +108 -0
- morvix-0.1.0/morvix/compare.py +110 -0
- morvix-0.1.0/morvix/components/__init__.py +1 -0
- morvix-0.1.0/morvix/components/choice.py +33 -0
- morvix-0.1.0/morvix/components/confirm.py +41 -0
- morvix-0.1.0/morvix/components/form.py +254 -0
- morvix-0.1.0/morvix/components/progress.py +45 -0
- morvix-0.1.0/morvix/components/selection.py +235 -0
- morvix-0.1.0/morvix/components/table.py +114 -0
- morvix-0.1.0/morvix/context.py +74 -0
- morvix-0.1.0/morvix/errors.py +45 -0
- morvix-0.1.0/morvix/execmodels/__init__.py +3 -0
- morvix-0.1.0/morvix/execmodels/args.py +36 -0
- morvix-0.1.0/morvix/execmodels/file.py +60 -0
- morvix-0.1.0/morvix/execmodels/interactive.py +157 -0
- morvix-0.1.0/morvix/execmodels/library.py +119 -0
- morvix-0.1.0/morvix/generators.py +313 -0
- morvix-0.1.0/morvix/help_text.py +178 -0
- morvix-0.1.0/morvix/judge.py +203 -0
- morvix-0.1.0/morvix/layout.py +48 -0
- morvix-0.1.0/morvix/manifest.py +95 -0
- morvix-0.1.0/morvix/messages.py +57 -0
- morvix-0.1.0/morvix/models.py +124 -0
- morvix-0.1.0/morvix/packaging.py +167 -0
- morvix-0.1.0/morvix/process.py +337 -0
- morvix-0.1.0/morvix/project.py +250 -0
- morvix-0.1.0/morvix/readme.py +151 -0
- morvix-0.1.0/morvix/registry.py +178 -0
- morvix-0.1.0/morvix/results.py +161 -0
- morvix-0.1.0/morvix/runner_build.py +82 -0
- morvix-0.1.0/morvix/runner_core/morvix_runner.py +1245 -0
- morvix-0.1.0/morvix/runner_core/run.sh +36 -0
- morvix-0.1.0/morvix/shapes.py +249 -0
- morvix-0.1.0/morvix/shell.py +196 -0
- morvix-0.1.0/morvix/suggestions.py +113 -0
- morvix-0.1.0/morvix/theme.py +75 -0
- morvix-0.1.0/morvix/version.py +7 -0
- morvix-0.1.0/morvix/workflow.py +89 -0
- morvix-0.1.0/pyproject.toml +47 -0
- morvix-0.1.0/test_project.zip +0 -0
- morvix-0.1.0/tests/conftest.py +56 -0
- morvix-0.1.0/tests/test_commands.py +180 -0
- morvix-0.1.0/tests/test_compare.py +204 -0
- morvix-0.1.0/tests/test_generators.py +139 -0
- morvix-0.1.0/tests/test_java_multifile.py +62 -0
- morvix-0.1.0/tests/test_judge.py +201 -0
- morvix-0.1.0/tests/test_manifest.py +152 -0
- morvix-0.1.0/tests/test_packaging.py +146 -0
- morvix-0.1.0/tests/test_process.py +158 -0
- morvix-0.1.0/tests/test_readme_honesty.py +37 -0
- morvix-0.1.0/tests/test_regressions.py +71 -0
- morvix-0.1.0/tests/test_runner_core.py +251 -0
- morvix-0.1.0/tests/test_runner_stdlib.py +45 -0
- morvix-0.1.0/tests/test_rust.py +43 -0
- morvix-0.1.0/tests/test_shapes.py +208 -0
- morvix-0.1.0/tests/test_valgrind.py +77 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ${{ matrix.os }}
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest, macos-latest]
|
|
15
|
+
python: ["3.9", "3.12"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
- uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python }}
|
|
21
|
+
- uses: actions/setup-java@v5
|
|
22
|
+
with:
|
|
23
|
+
distribution: temurin
|
|
24
|
+
java-version: "21"
|
|
25
|
+
# valgrind is Linux-only; install it so the memory-correctness test runs
|
|
26
|
+
# for real rather than skipping. gcc/g++ and rustc are preinstalled on the
|
|
27
|
+
# GitHub runners, so the C/C++/Rust adapter tests run too.
|
|
28
|
+
- name: Install valgrind (Linux)
|
|
29
|
+
if: runner.os == 'Linux'
|
|
30
|
+
run: sudo apt-get update && sudo apt-get install -y valgrind
|
|
31
|
+
- run: pip install -e ".[dev]"
|
|
32
|
+
- run: pytest -q
|
|
33
|
+
|
|
34
|
+
# The sacred path: prove a Receiver can run a package with ONLY system
|
|
35
|
+
# python3 - no Morvix install anywhere. One job builds a package; a second,
|
|
36
|
+
# deliberately Morvix-free, job unpacks it and runs ./run.sh.
|
|
37
|
+
build-package:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v6
|
|
41
|
+
- uses: actions/setup-python@v6
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.12"
|
|
44
|
+
- run: pip install -e .
|
|
45
|
+
- name: Build a shareable package
|
|
46
|
+
run: |
|
|
47
|
+
mkdir demo && cd demo
|
|
48
|
+
printf 'import sys\nprint(sum(int(x) for x in sys.stdin.read().split()))\n' > sol.py
|
|
49
|
+
morvix init --name demo --language python
|
|
50
|
+
morvix import sol.py
|
|
51
|
+
morvix reference sol.py
|
|
52
|
+
morvix gen --random --shape ints --count 5 --seed 1
|
|
53
|
+
morvix gen --expected
|
|
54
|
+
morvix package --zip --out ../pkg.zip
|
|
55
|
+
cp sol.py ../sol.py
|
|
56
|
+
- uses: actions/upload-artifact@v7
|
|
57
|
+
with:
|
|
58
|
+
name: receiver-package
|
|
59
|
+
path: |
|
|
60
|
+
pkg.zip
|
|
61
|
+
sol.py
|
|
62
|
+
|
|
63
|
+
receiver-clean:
|
|
64
|
+
needs: build-package
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/setup-python@v6
|
|
68
|
+
with:
|
|
69
|
+
python-version: "3.12"
|
|
70
|
+
- uses: actions/download-artifact@v8
|
|
71
|
+
with:
|
|
72
|
+
name: receiver-package
|
|
73
|
+
# No checkout, no pip install: Morvix must not be present on this runner.
|
|
74
|
+
- name: Confirm Morvix is absent
|
|
75
|
+
run: |
|
|
76
|
+
if python3 -c "import morvix" 2>/dev/null; then
|
|
77
|
+
echo "morvix is importable here - this job must be Morvix-free"; exit 1
|
|
78
|
+
fi
|
|
79
|
+
echo "morvix is absent - good"
|
|
80
|
+
- name: Unpack and run ./run.sh with only system python3
|
|
81
|
+
run: |
|
|
82
|
+
mkdir r && cd r
|
|
83
|
+
unzip ../pkg.zip
|
|
84
|
+
cp ../sol.py .
|
|
85
|
+
sh run.sh sol.py | tee out.txt
|
|
86
|
+
grep -q "passed" out.txt
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when you create a GitHub Release. Uses PyPI Trusted
|
|
4
|
+
# Publishing (OIDC) - no API token is stored anywhere. The build and the
|
|
5
|
+
# upload are split so the upload job is the only one with id-token permission.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
release:
|
|
9
|
+
types: [published]
|
|
10
|
+
workflow_dispatch: # lets you trigger a publish by hand too
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
- uses: actions/setup-python@v6
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
- run: pip install build
|
|
21
|
+
- run: python -m build
|
|
22
|
+
- uses: actions/upload-artifact@v7
|
|
23
|
+
with:
|
|
24
|
+
name: dist
|
|
25
|
+
path: dist/
|
|
26
|
+
|
|
27
|
+
publish:
|
|
28
|
+
needs: build
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
environment: pypi # must match the environment set on PyPI's publisher
|
|
31
|
+
permissions:
|
|
32
|
+
id-token: write # required for trusted publishing (OIDC)
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/download-artifact@v8
|
|
35
|
+
with:
|
|
36
|
+
name: dist
|
|
37
|
+
path: dist/
|
|
38
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
morvix-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
|
|
11
|
+
# Tooling
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.mypy_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
.coverage
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# OS
|
|
19
|
+
.DS_Store
|
|
20
|
+
|
|
21
|
+
# Local scratch / sandboxes used while testing morvix by hand
|
|
22
|
+
/scratch/
|
|
23
|
+
/sandbox/
|
morvix-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
Morvix is a Python CLI that lets a student build test cases from their own solution, run their code
|
|
8
|
+
against them, and package the harness to share with classmates. The full design lives in
|
|
9
|
+
`documentation.md` (831 lines) - read the relevant section before changing behavior; the code is
|
|
10
|
+
organized to mirror it and many comments cite section numbers (e.g. "Section 14.6").
|
|
11
|
+
|
|
12
|
+
## Dev commands
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]" # set up
|
|
16
|
+
.venv/bin/morvix # interactive shell
|
|
17
|
+
.venv/bin/morvix <cmd> ... # one-shot (same verbs as the shell)
|
|
18
|
+
.venv/bin/python -m compileall -q morvix # quick syntax check of everything
|
|
19
|
+
.venv/bin/pytest # run the test suite
|
|
20
|
+
.venv/bin/pytest tests/test_x.py::test_y # a single test
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The toolchains used by the language adapters (`gcc`/`g++`, `nasm`, `javac`/`java`, `rustc`,
|
|
24
|
+
`valgrind`) must be on PATH to exercise those paths. `rustc` and `valgrind` are commonly absent on
|
|
25
|
+
macOS; those features degrade with an honest warning rather than faking results.
|
|
26
|
+
|
|
27
|
+
## The architecture that matters
|
|
28
|
+
|
|
29
|
+
Everything hangs on **three orthogonal axes that never multiply against each other** (Section 4.1).
|
|
30
|
+
When adding capability, add to exactly one axis:
|
|
31
|
+
|
|
32
|
+
- **Language adapter** (`morvix/adapters/<lang>.py`) - turns source into something runnable. Knows
|
|
33
|
+
nothing about tests. Subclass `Adapter`, implement `build/run_spec/describe`, call `register()`.
|
|
34
|
+
- **Execution model** (`morvix/models.py` for `stdio`; `morvix/execmodels/<name>.py` for the rest) -
|
|
35
|
+
how a runnable thing is driven and what its observable output is. A function
|
|
36
|
+
`(case, env, limits) -> Observation` registered with `register_model`.
|
|
37
|
+
- **Comparison strategy** (`morvix/compare.py` for exact/whitespace; `morvix/comparators.py` for
|
|
38
|
+
float/hash/checker) - given output + expected, decide pass/fail. A function
|
|
39
|
+
`(CompareInput) -> Verdict` registered with `register_comparator`.
|
|
40
|
+
|
|
41
|
+
`morvix/judge.py` is the engine that ties them together: build once, run each case through the
|
|
42
|
+
model, then combine the enabled dimensions (output match + expected exit/signal + memory) so a case
|
|
43
|
+
can require all of them at once (Section 14.7). `morvix/process.py` is the bottom layer (spawn,
|
|
44
|
+
rlimits, timing, `wait4`-based per-child memory, `LC_ALL=C` locale) and is the single place that
|
|
45
|
+
papers over Linux/macOS differences.
|
|
46
|
+
|
|
47
|
+
The stack, top to bottom: shell/CLI (`app`, `shell`, `registry`) -> shared components
|
|
48
|
+
(`components/`) -> commands (`commands/`) -> orchestration (`project`, `generators`, `manifest`,
|
|
49
|
+
`packaging`, `workflow`, `results`) -> the three axes -> `process`.
|
|
50
|
+
|
|
51
|
+
## Key conventions and invariants
|
|
52
|
+
|
|
53
|
+
- **Two entry points, one vocabulary.** `morvix/registry.py` builds one argparse parser used by both
|
|
54
|
+
the REPL and one-shot mode. Each command module exposes `NAME`, `configure(parser)`,
|
|
55
|
+
`run(ctx, args) -> int`, and an optional `complete(ctx, prev_words, word)`. Errors raise (they do
|
|
56
|
+
not `sys.exit`) so the shell survives them.
|
|
57
|
+
- **One shared UI layer.** Commands never hand-roll a menu, prompt, table, or message. They compose
|
|
58
|
+
from `morvix/components/` (selection, choice, form, confirm, table, progress) and print only via
|
|
59
|
+
`ctx.messenger`. Each component has a non-interactive fallback driven by `ctx.interactive`.
|
|
60
|
+
- **The directory is the state.** No database. `config/project.json` + `config/cases.json` +
|
|
61
|
+
`config/runners/*.json` are the editable truth; `morvix.json` is the generated, shareable manifest
|
|
62
|
+
regenerated on every `ctx.save_project()`. Config is JSON throughout.
|
|
63
|
+
- **The runner core is sacred and standalone.** `morvix/runner_core/morvix_runner.py` ships verbatim
|
|
64
|
+
inside packages, must import **nothing** from `morvix`, must be **stdlib-only**, and must run on a
|
|
65
|
+
clean machine with just Python 3. It re-implements the judge logic; if you change judging behavior
|
|
66
|
+
in `judge.py`/`process.py`/`compare.py`, keep the runner core in sync. `run.sh` is its wrapper and
|
|
67
|
+
is placed at the package root by `packaging.py` so `./run.sh` works.
|
|
68
|
+
- **A package never contains the author's source** (`solutions/`), the brute-force reference, or
|
|
69
|
+
`config/`. See `packaging.build_package`.
|
|
70
|
+
- **Honesty is a feature.** Expected answers come from one peer's solution, not an authority. The
|
|
71
|
+
correctness disclaimer is always included in the generated README (`readme.py`). Smart suggestions
|
|
72
|
+
(`suggestions.py`) explain and ask - they never change behavior silently.
|
|
73
|
+
- **Help text has one home.** `morvix/help_text.py` powers both `help` and the autocomplete meta
|
|
74
|
+
column; keep summaries there in sync with what a command actually does.
|
|
75
|
+
|
|
76
|
+
## Style
|
|
77
|
+
|
|
78
|
+
Comments are plain-English header blocks per file/function with occasional `# - bullet` lists for
|
|
79
|
+
multi-step logic; sparse inline comments; no heavy docstrings. Keep code simple - this is open
|
|
80
|
+
source and meant to be readable by a newcomer. Commit messages are conventional (`feat:`, `fix:`,
|
|
81
|
+
`chore:`, `refactor:`, `docs:`, `test:`), lowercase, no body or trailers.
|
morvix-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Krzysztof Adamczyk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
morvix-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: morvix
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A test-authoring, test-running, and test-sharing CLI for university programming assignments.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Krzysztof-Ad/morvix
|
|
6
|
+
Project-URL: Repository, https://github.com/Krzysztof-Ad/morvix
|
|
7
|
+
Author: Krzysztof Adamczyk
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 Krzysztof Adamczyk
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: assignments,cli,education,judge,testing,university
|
|
31
|
+
Classifier: Development Status :: 4 - Beta
|
|
32
|
+
Classifier: Environment :: Console
|
|
33
|
+
Classifier: Intended Audience :: Education
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Topic :: Software Development :: Testing
|
|
37
|
+
Requires-Python: >=3.9
|
|
38
|
+
Requires-Dist: prompt-toolkit>=3.0
|
|
39
|
+
Requires-Dist: rich>=13.0
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
# Morvix
|
|
45
|
+
|
|
46
|
+
A test-authoring, test-running, and test-sharing CLI for university programming assignments.
|
|
47
|
+
|
|
48
|
+
Most courses don't hand out test suites, so students end up writing their own: they build test
|
|
49
|
+
cases from their own solution, run their program against them, and share the cases on GitHub so
|
|
50
|
+
classmates can check their code too. Morvix automates that whole loop - building, running, and
|
|
51
|
+
sharing these self-made test harnesses - quickly and consistently, across languages and platforms.
|
|
52
|
+
|
|
53
|
+
It's an honest tool. The "expected answers" come from one student's own solution, so passing every
|
|
54
|
+
test does **not** prove a solution is correct - it proves it agrees with that one reference on the
|
|
55
|
+
cases tried. Morvix says so plainly (it's baked into every package's README) and makes the real
|
|
56
|
+
signal - lots of independent solutions agreeing - easy to see.
|
|
57
|
+
|
|
58
|
+
> Morvix is not an online judge, not a grading server, and not an AI tool. It runs locally and
|
|
59
|
+
> offline. Linux and macOS are the primary targets; Windows works on a best-effort basis.
|
|
60
|
+
|
|
61
|
+
## Install
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
pip install morvix # or, from a clone:
|
|
65
|
+
pip install .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Needs Python 3.9+. The only dependencies are `prompt_toolkit` and `rich`. The runner that ships
|
|
69
|
+
inside shared packages is pure standard library, so whoever you share with needs nothing but
|
|
70
|
+
Python 3.
|
|
71
|
+
|
|
72
|
+
## Quick start (the Author)
|
|
73
|
+
|
|
74
|
+
Run `morvix` with no arguments to open the interactive shell (live autocomplete, history, a status
|
|
75
|
+
bar), or use any command one-shot from your normal shell. What you can do one way is identical the
|
|
76
|
+
other way.
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
cd my-assignment
|
|
80
|
+
morvix init # create a project here (guided)
|
|
81
|
+
morvix config cpp # how to build/run your language
|
|
82
|
+
morvix import solution.cpp # the solution under test
|
|
83
|
+
morvix reference solution.cpp # it also defines the expected answers
|
|
84
|
+
morvix gen --random --count 100 # generate inputs from the built-in shapes
|
|
85
|
+
morvix gen --expected # compute answers by running the reference
|
|
86
|
+
morvix run --all # build, run, judge - with a live table
|
|
87
|
+
morvix runner new full # a named, shareable run profile
|
|
88
|
+
morvix package --zip # bundle it up to share (your source is left out)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Quick start (the Receiver)
|
|
92
|
+
|
|
93
|
+
You got a package from a classmate. You don't need Morvix at all:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
unzip their-tests.zip && cd their-tests
|
|
97
|
+
./run.sh my_solution.cpp # builds your code, runs every test, reports
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If you *do* have Morvix, open it in the unpacked directory and you get the rich view - browse the
|
|
101
|
+
tests, re-run selectively, and diff your per-case results against the author's.
|
|
102
|
+
|
|
103
|
+
## What's in the box
|
|
104
|
+
|
|
105
|
+
- **Languages**: C, C++, NASM, Python, Java, Rust - each a small adapter. Adding one is one file.
|
|
106
|
+
- **Execution models**: `stdio`, `library` (link & assert), `args`, `file`, `interactive`.
|
|
107
|
+
- **Comparison**: byte-exact, whitespace-insensitive, float-tolerant, hash, a custom checker, and
|
|
108
|
+
expected exit status / crash - combinable per case.
|
|
109
|
+
- **Limits & checks**: wall/CPU time, peak memory (approximate), hard memory caps, output caps, and
|
|
110
|
+
an optional valgrind memory-correctness pass.
|
|
111
|
+
- **Generation**: a built-in random-shape library, custom generators, stress testing against a
|
|
112
|
+
brute force, and crash-case candidates.
|
|
113
|
+
- **Sharing**: zip / tar / tar.gz / tar.xz packages with an auto-generated README and a manifest.
|
|
114
|
+
- **Workflows**: record a sequence of commands and replay it on the next assignment.
|
|
115
|
+
|
|
116
|
+
These three axes - language, execution model, comparison - are kept independent, so they never
|
|
117
|
+
multiply against each other. That's the design decision everything else hangs on.
|
|
118
|
+
|
|
119
|
+
## Design
|
|
120
|
+
|
|
121
|
+
The full design is in [documentation.md](documentation.md): the architecture, every command, the
|
|
122
|
+
file formats, and the reasoning behind each choice.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
[MIT](LICENSE) (c) Krzysztof Adamczyk
|
morvix-0.1.0/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Morvix
|
|
2
|
+
|
|
3
|
+
A test-authoring, test-running, and test-sharing CLI for university programming assignments.
|
|
4
|
+
|
|
5
|
+
Most courses don't hand out test suites, so students end up writing their own: they build test
|
|
6
|
+
cases from their own solution, run their program against them, and share the cases on GitHub so
|
|
7
|
+
classmates can check their code too. Morvix automates that whole loop - building, running, and
|
|
8
|
+
sharing these self-made test harnesses - quickly and consistently, across languages and platforms.
|
|
9
|
+
|
|
10
|
+
It's an honest tool. The "expected answers" come from one student's own solution, so passing every
|
|
11
|
+
test does **not** prove a solution is correct - it proves it agrees with that one reference on the
|
|
12
|
+
cases tried. Morvix says so plainly (it's baked into every package's README) and makes the real
|
|
13
|
+
signal - lots of independent solutions agreeing - easy to see.
|
|
14
|
+
|
|
15
|
+
> Morvix is not an online judge, not a grading server, and not an AI tool. It runs locally and
|
|
16
|
+
> offline. Linux and macOS are the primary targets; Windows works on a best-effort basis.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
pip install morvix # or, from a clone:
|
|
22
|
+
pip install .
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Needs Python 3.9+. The only dependencies are `prompt_toolkit` and `rich`. The runner that ships
|
|
26
|
+
inside shared packages is pure standard library, so whoever you share with needs nothing but
|
|
27
|
+
Python 3.
|
|
28
|
+
|
|
29
|
+
## Quick start (the Author)
|
|
30
|
+
|
|
31
|
+
Run `morvix` with no arguments to open the interactive shell (live autocomplete, history, a status
|
|
32
|
+
bar), or use any command one-shot from your normal shell. What you can do one way is identical the
|
|
33
|
+
other way.
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
cd my-assignment
|
|
37
|
+
morvix init # create a project here (guided)
|
|
38
|
+
morvix config cpp # how to build/run your language
|
|
39
|
+
morvix import solution.cpp # the solution under test
|
|
40
|
+
morvix reference solution.cpp # it also defines the expected answers
|
|
41
|
+
morvix gen --random --count 100 # generate inputs from the built-in shapes
|
|
42
|
+
morvix gen --expected # compute answers by running the reference
|
|
43
|
+
morvix run --all # build, run, judge - with a live table
|
|
44
|
+
morvix runner new full # a named, shareable run profile
|
|
45
|
+
morvix package --zip # bundle it up to share (your source is left out)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick start (the Receiver)
|
|
49
|
+
|
|
50
|
+
You got a package from a classmate. You don't need Morvix at all:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
unzip their-tests.zip && cd their-tests
|
|
54
|
+
./run.sh my_solution.cpp # builds your code, runs every test, reports
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
If you *do* have Morvix, open it in the unpacked directory and you get the rich view - browse the
|
|
58
|
+
tests, re-run selectively, and diff your per-case results against the author's.
|
|
59
|
+
|
|
60
|
+
## What's in the box
|
|
61
|
+
|
|
62
|
+
- **Languages**: C, C++, NASM, Python, Java, Rust - each a small adapter. Adding one is one file.
|
|
63
|
+
- **Execution models**: `stdio`, `library` (link & assert), `args`, `file`, `interactive`.
|
|
64
|
+
- **Comparison**: byte-exact, whitespace-insensitive, float-tolerant, hash, a custom checker, and
|
|
65
|
+
expected exit status / crash - combinable per case.
|
|
66
|
+
- **Limits & checks**: wall/CPU time, peak memory (approximate), hard memory caps, output caps, and
|
|
67
|
+
an optional valgrind memory-correctness pass.
|
|
68
|
+
- **Generation**: a built-in random-shape library, custom generators, stress testing against a
|
|
69
|
+
brute force, and crash-case candidates.
|
|
70
|
+
- **Sharing**: zip / tar / tar.gz / tar.xz packages with an auto-generated README and a manifest.
|
|
71
|
+
- **Workflows**: record a sequence of commands and replay it on the next assignment.
|
|
72
|
+
|
|
73
|
+
These three axes - language, execution model, comparison - are kept independent, so they never
|
|
74
|
+
multiply against each other. That's the design decision everything else hangs on.
|
|
75
|
+
|
|
76
|
+
## Design
|
|
77
|
+
|
|
78
|
+
The full design is in [documentation.md](documentation.md): the architecture, every command, the
|
|
79
|
+
file formats, and the reasoning behind each choice.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
[MIT](LICENSE) (c) Krzysztof Adamczyk
|