Scenario runner: stops when overridden base parameters leave the start out of balance (new field startlikevekt: krev, kalibrer, ubalanse); stops on non-finite results; says that models with a court queue drift slowly even without a shock and prints the drift before the shock; queue in months of inflow; never deletes files it did not write; stricter limits. Check: anchored on the note's own checksums for core and reference files, runs the scenario files too, exact comparison for the diagnosis, honest wording when parts were skipped or an extension is broken. Launcher: unknown field names in input are rejected with a suggestion; unwritable folders give a message, not a traceback. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
# Copyright (c) 2026 Kjell Tore Guttormsen. MIT License, see LICENSE.
|
|
"""Felles hjelpere for testene: stier, kjøring av kjor.py og en kopi av pluginens modell."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROT = Path(__file__).resolve().parent.parent
|
|
MODELL = ROT / "modell"
|
|
KJOR = MODELL / "kjor.py"
|
|
FASIT = ROT / "fasit"
|
|
EKSEMPLER = ROT / "eksempler"
|
|
DOMSTOL = EKSEMPLER / "eksempel_domstol.json"
|
|
NORGE = EKSEMPLER / "norge_2025.json"
|
|
|
|
|
|
def kjor(
|
|
*args: str,
|
|
python: list[str] | None = None,
|
|
hjem: Path | None = None,
|
|
cwd: Path | None = None,
|
|
) -> subprocess.CompletedProcess[str]:
|
|
"""Kjør kjor.py som brukeren gjør, og fang utskrift og exit-kode.
|
|
|
|
python: tolken (med valg), standard er den som kjører testene (har numpy og scipy).
|
|
hjem: HOME for prosessen, slik at standardmappa ~/.dynamisk-rettsstat aldri er brukerens egen.
|
|
"""
|
|
miljo = dict(os.environ, PYTHONIOENCODING="utf-8", PYTHONDONTWRITEBYTECODE="1")
|
|
miljo.pop("DYNAMISK_RETTSSTAT_VENV", None)
|
|
if hjem is not None:
|
|
miljo["HOME"] = str(hjem)
|
|
return subprocess.run(
|
|
[*(python or [sys.executable]), str(KJOR), *args],
|
|
capture_output=True, text=True, encoding="utf-8", env=miljo, cwd=str(cwd or ROT), check=False,
|
|
)
|
|
|
|
|
|
def fasit(navn: str) -> str:
|
|
"""Innholdet i en fasitfil."""
|
|
return (FASIT / navn).read_text(encoding="utf-8")
|
|
|
|
|
|
def lag_venv_omvei(data: Path, *python: str) -> Path:
|
|
"""Lag en «egen mappe» i data/venv der bin/python er et lite skript som starter en gitt Python.
|
|
|
|
Testene installerer ingenting: omveien peker på en Python som allerede finnes.
|
|
"""
|
|
bin_mappe = data / "venv" / "bin"
|
|
bin_mappe.mkdir(parents=True)
|
|
tolk = bin_mappe / "python"
|
|
kommando = " ".join(f'"{p}"' for p in python)
|
|
tolk.write_text(f'#!/bin/sh\nexec {kommando} "$@"\n', encoding="utf-8")
|
|
tolk.chmod(0o755)
|
|
return tolk
|
|
|
|
|
|
@pytest.fixture
|
|
def hjem(tmp_path: Path) -> Path:
|
|
"""En tom hjemmemappe for prosessen."""
|
|
mappe = tmp_path / "hjem"
|
|
mappe.mkdir()
|
|
return mappe
|
|
|
|
|
|
@pytest.fixture
|
|
def kopi(tmp_path: Path) -> Path:
|
|
"""En kopi av modell/, fasit/ og eksempler/ som testen kan endre. Returnerer kopiens rot.
|
|
|
|
Kopien er ikke merket som arbeidskopi (ingen LES-MEG.md), som en klone av repoet.
|
|
"""
|
|
rot = tmp_path / "kopi"
|
|
for navn in ("modell", "fasit", "eksempler"):
|
|
shutil.copytree(ROT / navn, rot / navn, ignore=shutil.ignore_patterns("__pycache__"))
|
|
return rot
|