feat: model core, launcher, reproduction check and the first two skills
The core in modell/kjerne/ is an unmodified copy of sim.py, diagnose.py and forlop.py from den-dynamiske-rettsstaten @2badc25, pinned by sha256. kjor.py is the single entry point; kontroll.py reproduces the note's 22 data files and printed results. Skills: diagnose and forlop (Norwegian). Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
commit
464ad38b49
51 changed files with 11207 additions and 0 deletions
432
modell/kontroll.py
Normal file
432
modell/kontroll.py
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
# Copyright (c) 2026 Kjell Tore Guttormsen. MIT License, see LICENSE.
|
||||
"""Gjenskapingskontroll: sjekk at modellen i denne mappa regner som notatet.
|
||||
|
||||
Bruk:
|
||||
python3 kjor.py kontroll [--rask]
|
||||
python3 kontroll.py [--rask] (med en Python som har numpy og scipy)
|
||||
|
||||
Fire kontroller, hver med én linje dom og detaljer bare ved avvik:
|
||||
1. Kjernen: sha256 for filene i kjerne/ mot kjerne/KILDE.json.
|
||||
2. diagnose.py på begge eksempelfilene mot fasit/ (tekst).
|
||||
3. forlop.py på begge eksempelfilene mot fasit/ (tekst; trenger numpy og scipy).
|
||||
4. Full kjøring av sim.py i en midlertidig mappe: datafilene mot fasit/data/ byte for byte,
|
||||
med største absolutte avvik per kolonne når en fil er ulik, og utskriften mot
|
||||
fasit/sim_utskrift.txt. Om lag 1-2 min; --rask hopper over den.
|
||||
I tillegg kjøres grensetilfelle() i hver utvidelse i utvidelser/; hvert avvik skal være eksakt 0.
|
||||
|
||||
Nivået til slutt:
|
||||
- «bit for bit som notatet»: alt er likt byte for byte.
|
||||
- «innenfor toleranse»: teksten er lik, og hvert tall avviker med høyst én enhet i siste
|
||||
viste siffer (det som kan skje med andre versjoner av numpy og scipy, eller en annen maskin).
|
||||
- «endret»: alt annet. I en arbeidskopi (mappa over modell/ har LES-MEG.md, som
|
||||
arbeidskopi.py lager) er det en opplysning, ikke en feil: detaljene sier hvilke av
|
||||
notatets resultater som har flyttet seg, og hvor mye.
|
||||
|
||||
Exit-kode: 0 for bit for bit og innenfor toleranse, 1 for endret, 3 når numpy eller scipy
|
||||
mangler for noe av kontrollen (det som kunne kjøres, er kjørt), 2 for feil bruk.
|
||||
|
||||
Grensesnitt: main(argv: list[str]) -> int, som kjor.py kaller.
|
||||
Utvidelser: utvidelser/<navn>.py (ikke filer som begynner med _) med
|
||||
grensetilfelle() -> list av (beskrivelse, største absolutte avvik mot kjernen). Hver
|
||||
kjøres i en egen prosess med modell/kjerne og modell/ først i sys.path.
|
||||
Bare standardbiblioteket her; kjernen kjøres som egne prosesser med samme Python.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import difflib
|
||||
import hashlib
|
||||
import importlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
MODELL = Path(__file__).resolve().parent
|
||||
KJERNE = MODELL / "kjerne"
|
||||
ROT = MODELL.parent
|
||||
FASIT = ROT / "fasit"
|
||||
EKSEMPLER = ROT / "eksempler"
|
||||
EKSEMPELFILER = ("eksempel_domstol", "norge_2025")
|
||||
ARBEIDSKOPI_MERKE = "LES-MEG.md"
|
||||
|
||||
LIK, TOLERANSE, ENDRET, IKKE_KJORT = "lik", "toleranse", "endret", "ikke kjørt"
|
||||
RANG = {LIK: 0, TOLERANSE: 1, IKKE_KJORT: 2, ENDRET: 3}
|
||||
MAKS_LINJER = 40 # linjer med forskjeller som vises per sammenligning
|
||||
SLINGRING = 1e-9 # relativ slingring når avviket sammenlignes med én enhet i siste siffer
|
||||
|
||||
TALL = re.compile(r"[-+]?\d+(?:[.,]\d+)?(?:[eE][-+]?\d+)?")
|
||||
|
||||
MILJO = dict(os.environ, PYTHONIOENCODING="utf-8", PYTHONDONTWRITEBYTECODE="1")
|
||||
|
||||
UTVIDELSE_KJORER = """\
|
||||
import importlib.util, json, sys
|
||||
modell, fil = sys.argv[1], sys.argv[2]
|
||||
sys.path[:0] = [modell + "/kjerne", modell]
|
||||
spec = importlib.util.spec_from_file_location("utvidelse", fil)
|
||||
modul = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(modul)
|
||||
print()
|
||||
print(json.dumps([[str(b), float(a)] for b, a in modul.grensetilfelle()]))
|
||||
"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Dom:
|
||||
"""Resultatet av én kontroll."""
|
||||
|
||||
status: str
|
||||
linje: str
|
||||
detaljer: list[str] = field(default_factory=list)
|
||||
avvik: float = 0.0
|
||||
|
||||
|
||||
@dataclass
|
||||
class Sammenligning:
|
||||
"""Resultatet av å sammenligne en fil eller en utskrift med fasit."""
|
||||
|
||||
status: str
|
||||
avvik: float = 0.0
|
||||
detaljer: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
# ---------------- sammenligning ----------------
|
||||
|
||||
def enhet(tall: str) -> float:
|
||||
"""Én enhet i siste viste siffer: «1,28» -> 0,01, «7.21» -> 0,01, «1.11e-15» -> 1e-17."""
|
||||
mantisse, _, eksponent = tall.lower().partition("e")
|
||||
desimaler = len(mantisse.replace(",", ".").partition(".")[2])
|
||||
return float(10.0 ** (int(eksponent or "0") - desimaler))
|
||||
|
||||
|
||||
def verdi(tall: str) -> float:
|
||||
"""Tallet i en tekst, med punktum eller komma som desimaltegn."""
|
||||
return float(tall.replace(",", "."))
|
||||
|
||||
|
||||
def innenfor(fasit: str, naa: str) -> tuple[bool, float]:
|
||||
"""Er to tall like innenfor én enhet i siste viste siffer? Returnerer også avviket."""
|
||||
try:
|
||||
a, b = verdi(fasit), verdi(naa)
|
||||
except ValueError:
|
||||
return fasit == naa, 0.0 if fasit == naa else math.inf
|
||||
avvik = abs(a - b) if math.isfinite(a) and math.isfinite(b) else (0.0 if a == b else math.inf)
|
||||
return avvik <= max(enhet(fasit), enhet(naa)) * (1 + SLINGRING), avvik
|
||||
|
||||
|
||||
def vis_tall(x: float) -> str:
|
||||
"""Et avvik med norsk desimaltegn."""
|
||||
if x == 0:
|
||||
return "0"
|
||||
if math.isinf(x):
|
||||
return "uendelig"
|
||||
return f"{x:.1e}".replace(".", ",")
|
||||
|
||||
|
||||
def forskjeller(fasit: list[str], naa: list[str]) -> list[str]:
|
||||
"""Linjene som er ulike, som en kort diff (notatet / nå)."""
|
||||
linjer = list(difflib.unified_diff(fasit, naa, "notatet", "nå", lineterm="", n=0))
|
||||
if len(linjer) > MAKS_LINJER:
|
||||
linjer = [*linjer[:MAKS_LINJER], f"... ({len(linjer) - MAKS_LINJER} linjer til)"]
|
||||
return linjer
|
||||
|
||||
|
||||
def sammenlign_tekst(fasit: str, naa: str) -> Sammenligning:
|
||||
"""Sammenlign en utskrift med fasit: lik, innenfor toleranse eller endret."""
|
||||
if fasit == naa:
|
||||
return Sammenligning(LIK)
|
||||
a, b = fasit.splitlines(), naa.splitlines()
|
||||
detaljer = forskjeller(a, b)
|
||||
if len(a) != len(b):
|
||||
return Sammenligning(ENDRET, math.inf, detaljer)
|
||||
storst = 0.0
|
||||
for linje_a, linje_b in zip(a, b):
|
||||
if linje_a == linje_b:
|
||||
continue
|
||||
if TALL.sub("#", linje_a) != TALL.sub("#", linje_b):
|
||||
return Sammenligning(ENDRET, math.inf, detaljer)
|
||||
for x, y in zip(TALL.findall(linje_a), TALL.findall(linje_b)):
|
||||
ok, avvik = innenfor(x, y)
|
||||
if not ok:
|
||||
return Sammenligning(ENDRET, avvik, detaljer)
|
||||
storst = max(storst, avvik)
|
||||
return Sammenligning(TOLERANSE, storst, detaljer)
|
||||
|
||||
|
||||
def les_dat(tekst: str) -> tuple[list[str], list[list[str]]]:
|
||||
"""Kolonnenavn og rader i en datafil fra sim.py (første linje er kolonnenavnene)."""
|
||||
linjer = [linje.split() for linje in tekst.splitlines() if linje.strip()]
|
||||
if not linjer:
|
||||
return [], []
|
||||
return linjer[0], linjer[1:]
|
||||
|
||||
|
||||
def sammenlign_dat(fasit: str, naa: str) -> Sammenligning:
|
||||
"""Sammenlign en datafil med fasit; ved avvik største absolutte avvik per kolonne."""
|
||||
if fasit == naa:
|
||||
return Sammenligning(LIK)
|
||||
kol_a, rader_a = les_dat(fasit)
|
||||
kol_b, rader_b = les_dat(naa)
|
||||
if kol_a != kol_b:
|
||||
return Sammenligning(ENDRET, math.inf,
|
||||
[f"kolonnene er ulike: notatet {' '.join(kol_a)}, nå {' '.join(kol_b)}"])
|
||||
if len(rader_a) != len(rader_b) or any(len(x) != len(y) for x, y in zip(rader_a, rader_b)):
|
||||
return Sammenligning(ENDRET, math.inf,
|
||||
[f"antall rader er ulikt: notatet {len(rader_a)}, nå {len(rader_b)}"])
|
||||
per_kolonne = [0.0] * len(kol_a)
|
||||
alle_innenfor = True
|
||||
for rad_a, rad_b in zip(rader_a, rader_b):
|
||||
for j, (x, y) in enumerate(zip(rad_a, rad_b)):
|
||||
if x == y:
|
||||
continue
|
||||
ok, avvik = innenfor(x, y)
|
||||
alle_innenfor = alle_innenfor and ok
|
||||
per_kolonne[j] = max(per_kolonne[j], avvik)
|
||||
deler = [f"{navn} {vis_tall(avvik)}" for navn, avvik in zip(kol_a, per_kolonne) if avvik > 0]
|
||||
detaljer = ["største absolutte avvik per kolonne: " + (", ".join(deler) or "ingen (bare formatering)")]
|
||||
return Sammenligning(TOLERANSE if alle_innenfor else ENDRET, max(per_kolonne), detaljer)
|
||||
|
||||
|
||||
def verst(statuser: list[str]) -> str:
|
||||
"""Den dårligste statusen i en liste."""
|
||||
return max(statuser, key=RANG.__getitem__, default=LIK)
|
||||
|
||||
|
||||
# ---------------- miljø og prosesser ----------------
|
||||
|
||||
def har_numpy_scipy() -> bool:
|
||||
"""Sjekk om denne Python har numpy 2.0 eller nyere (numpy.trapezoid) og scipy."""
|
||||
try:
|
||||
numpy = importlib.import_module("numpy")
|
||||
importlib.import_module("scipy.optimize")
|
||||
except ImportError:
|
||||
return False
|
||||
return hasattr(numpy, "trapezoid")
|
||||
|
||||
|
||||
def kjor_python(args: list[str], cwd: Path) -> subprocess.CompletedProcess[str]:
|
||||
"""Kjør denne Python med args i mappa cwd og fang utskriften."""
|
||||
return subprocess.run([sys.executable, *args], cwd=str(cwd), env=MILJO, capture_output=True, text=True,
|
||||
encoding="utf-8", check=False)
|
||||
|
||||
|
||||
def feilmelding(prosess: subprocess.CompletedProcess[str]) -> list[str]:
|
||||
"""De siste linjene på stderr, til detaljene."""
|
||||
linjer = prosess.stderr.strip().splitlines()
|
||||
return [f"stoppet med exit-kode {prosess.returncode}:", *linjer[-MAKS_LINJER // 2:]]
|
||||
|
||||
|
||||
def sha256(fil: Path) -> str:
|
||||
"""sha256 av en fil."""
|
||||
return hashlib.sha256(fil.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
# ---------------- kontrollene ----------------
|
||||
|
||||
def kontroll_kjerne() -> Dom:
|
||||
"""1. Kjernen mot sha256 i KILDE.json."""
|
||||
kildefil = KJERNE / "KILDE.json"
|
||||
if not kildefil.is_file():
|
||||
return Dom(ENDRET, f"Kjernen: fant ikke {kildefil}, så kjernen kan ikke sammenlignes med notatet.")
|
||||
kilde = json.loads(kildefil.read_text(encoding="utf-8"))
|
||||
endret = []
|
||||
for navn, info in kilde["filer"].items():
|
||||
fil = KJERNE / navn
|
||||
if not fil.is_file():
|
||||
endret.append(f"{navn} mangler")
|
||||
elif sha256(fil) != info["sha256"]:
|
||||
endret.append(f"{navn} er endret")
|
||||
versjon = f"{kilde['repo']} @ {kilde['commit'][:7]}"
|
||||
if not endret:
|
||||
return Dom(LIK, f"Kjernen: uendret fra notatet ({len(kilde['filer'])} filer, {versjon}).")
|
||||
return Dom(ENDRET, f"Kjernen: endret fra notatet ({versjon}): {', '.join(endret)}.")
|
||||
|
||||
|
||||
def kontroll_utskrift(skript: str, mappe: Path) -> Dom:
|
||||
"""2 og 3. Utskriften fra diagnose.py eller forlop.py på begge eksempelfilene mot fasit."""
|
||||
statuser, detaljer, storst = [], [], 0.0
|
||||
for eksempel in EKSEMPELFILER:
|
||||
fasitfil = FASIT / f"{skript}_{eksempel}.txt"
|
||||
inndata = EKSEMPLER / f"{eksempel}.json"
|
||||
mangler = [str(f) for f in (fasitfil, inndata) if not f.is_file()]
|
||||
if mangler:
|
||||
statuser.append(ENDRET)
|
||||
detaljer.append(f"{eksempel}: fant ikke {', '.join(mangler)}")
|
||||
continue
|
||||
prosess = kjor_python([str(KJERNE / f"{skript}.py"), str(inndata)], mappe)
|
||||
if prosess.returncode != 0:
|
||||
statuser.append(ENDRET)
|
||||
detaljer += [f"{eksempel}:", *(" " + linje for linje in feilmelding(prosess))]
|
||||
continue
|
||||
resultat = sammenlign_tekst(fasitfil.read_text(encoding="utf-8"), prosess.stdout)
|
||||
statuser.append(resultat.status)
|
||||
storst = max(storst, resultat.avvik)
|
||||
if resultat.status != LIK:
|
||||
detaljer += [f"{eksempel}:", *(" " + linje for linje in resultat.detaljer)]
|
||||
status = verst(statuser)
|
||||
begge = " og ".join(EKSEMPELFILER)
|
||||
linje = {
|
||||
LIK: f"{skript}: lik notatet for {begge}.",
|
||||
TOLERANSE: f"{skript}: innenfor toleranse for {begge} (største avvik {vis_tall(storst)}).",
|
||||
ENDRET: f"{skript}: endret (se under).",
|
||||
}[status]
|
||||
return Dom(status, linje, detaljer, storst)
|
||||
|
||||
|
||||
def kontroll_full(mappe: Path) -> Dom:
|
||||
"""4. Full kjøring av sim.py i en midlertidig mappe mot fasit/data og fasit/sim_utskrift.txt."""
|
||||
print(" (kjører sim.py, om lag 1-2 minutter ...)", flush=True)
|
||||
prosess = kjor_python([str(KJERNE / "sim.py")], mappe)
|
||||
if prosess.returncode != 0:
|
||||
return Dom(ENDRET, "Full kjøring: sim.py stoppet med en feil.", feilmelding(prosess), math.inf)
|
||||
fasit_data = FASIT / "data"
|
||||
navn_fasit = sorted(f.name for f in fasit_data.glob("*.dat"))
|
||||
navn_naa = sorted(f.name for f in (mappe / "data").glob("*.dat"))
|
||||
statuser, detaljer, storst, like = [], [], 0.0, 0
|
||||
for navn in sorted(set(navn_fasit) | set(navn_naa)):
|
||||
if navn not in navn_naa or navn not in navn_fasit:
|
||||
statuser.append(ENDRET)
|
||||
detaljer.append(f"{navn}: " + ("mangler i kjøringen" if navn not in navn_naa else "finnes ikke i fasit"))
|
||||
continue
|
||||
resultat = sammenlign_dat((fasit_data / navn).read_text(encoding="utf-8"),
|
||||
(mappe / "data" / navn).read_text(encoding="utf-8"))
|
||||
statuser.append(resultat.status)
|
||||
storst = max(storst, resultat.avvik)
|
||||
if resultat.status == LIK:
|
||||
like += 1
|
||||
else:
|
||||
dom = "innenfor toleranse" if resultat.status == TOLERANSE else "endret"
|
||||
detaljer.append(f"{navn} ({dom}): {'; '.join(resultat.detaljer)}")
|
||||
utskriftfil = FASIT / "sim_utskrift.txt"
|
||||
if utskriftfil.is_file():
|
||||
utskrift = sammenlign_tekst(utskriftfil.read_text(encoding="utf-8"), prosess.stdout)
|
||||
else:
|
||||
utskrift = Sammenligning(ENDRET, math.inf, [f"fant ikke {utskriftfil}"])
|
||||
statuser.append(utskrift.status)
|
||||
storst = max(storst, utskrift.avvik)
|
||||
if utskrift.status != LIK:
|
||||
detaljer += ["utskriften fra sim.py:", *(" " + linje for linje in utskrift.detaljer)]
|
||||
status = verst(statuser)
|
||||
tekst_utskrift = {LIK: "lik", TOLERANSE: "innenfor toleranse", ENDRET: "endret"}[utskrift.status]
|
||||
linje = (f"Full kjøring: {like} av {len(navn_fasit)} datafiler like byte for byte med notatet; "
|
||||
f"utskriften {tekst_utskrift}.")
|
||||
return Dom(status, linje, detaljer, storst)
|
||||
|
||||
|
||||
def kontroll_utvidelser(mappe: Path, *, regnemiljo: bool) -> Dom:
|
||||
"""Grensetilfellet i hver utvidelse skal gjenskape kjernen eksakt (avvik 0)."""
|
||||
utvidelser = sorted(f for f in (MODELL / "utvidelser").glob("*.py") if not f.name.startswith("_"))
|
||||
if not utvidelser:
|
||||
return Dom(LIK, "Utvidelser: ingen å kontrollere.")
|
||||
if not regnemiljo:
|
||||
return Dom(IKKE_KJORT, f"Utvidelser: ikke kjørt ({len(utvidelser)} stk.), numpy og scipy mangler.")
|
||||
statuser, detaljer, storst = [], [], 0.0
|
||||
for fil in utvidelser:
|
||||
prosess = kjor_python(["-c", UTVIDELSE_KJORER, str(MODELL), str(fil)], mappe)
|
||||
try:
|
||||
tilfeller = json.loads(prosess.stdout.strip().splitlines()[-1]) if prosess.returncode == 0 else None
|
||||
except (ValueError, IndexError):
|
||||
tilfeller = None
|
||||
if tilfeller is None:
|
||||
statuser.append(ENDRET)
|
||||
detaljer += [f"{fil.stem}: grensetilfelle() kunne ikke kjøres", *(" " + linje for linje in
|
||||
feilmelding(prosess))]
|
||||
continue
|
||||
if not tilfeller:
|
||||
statuser.append(ENDRET)
|
||||
detaljer.append(f"{fil.stem}: grensetilfelle() ga ingen tilfeller; en utvidelse skal ha minst ett.")
|
||||
continue
|
||||
for beskrivelse, avvik in tilfeller:
|
||||
storst = max(storst, abs(avvik))
|
||||
if avvik != 0.0:
|
||||
statuser.append(ENDRET)
|
||||
detaljer.append(f"{fil.stem}: {beskrivelse}: avvik {vis_tall(abs(avvik))}, skal være eksakt 0")
|
||||
else:
|
||||
statuser.append(LIK)
|
||||
status = verst(statuser)
|
||||
navn = ", ".join(f.stem for f in utvidelser)
|
||||
linje = (f"Utvidelser: grensetilfellene gjenskaper kjernen eksakt ({navn})." if status == LIK
|
||||
else f"Utvidelser: grensetilfellet gjenskaper ikke kjernen eksakt ({navn}; se under).")
|
||||
return Dom(status, linje, detaljer, storst)
|
||||
|
||||
|
||||
# ---------------- rapporten ----------------
|
||||
|
||||
def niva(dommer: list[Dom], *, rask: bool, arbeidskopi: bool) -> list[str]:
|
||||
"""Linjene om nivået som er oppnådd."""
|
||||
kjort = [d for d in dommer if d.status != IKKE_KJORT]
|
||||
status = verst([d.status for d in kjort])
|
||||
deler = (["uten full kjøring, --rask"] if rask else []) + (
|
||||
["bare det som er kjørt"] if any(d.status == IKKE_KJORT for d in dommer) else [])
|
||||
hva = f" ({'; '.join(deler)})" if deler else ""
|
||||
if status == LIK:
|
||||
linjer = [f"Nivå{hva}: bit for bit som notatet."]
|
||||
elif status == TOLERANSE:
|
||||
storst = max(d.avvik for d in kjort)
|
||||
linjer = [(f"Nivå{hva}: innenfor toleranse (største avvik {vis_tall(storst)}): hvert tall avviker med "
|
||||
"høyst én enhet i siste viste siffer.")]
|
||||
else:
|
||||
endret = [d.linje.split(":")[0] for d in kjort if d.status == ENDRET]
|
||||
linjer = [f"Nivå{hva}: endret: {', '.join(endret)}."]
|
||||
if arbeidskopi:
|
||||
linjer.append("Dette er en arbeidskopi, så det er en opplysning, ikke en feil: detaljene over viser "
|
||||
"hvilke av notatets resultater som har flyttet seg, og hvor mye.")
|
||||
else:
|
||||
linjer.append("Pluginens modell skal regne som notatet, så dette er en feil.")
|
||||
if any(d.status == IKKE_KJORT for d in dommer):
|
||||
linjer.append(f"Ikke kjørt fordi numpy eller scipy mangler i {sys.executable}. "
|
||||
"«kjor.py miljo --opprett» installerer dem i en egen mappe.")
|
||||
return linjer
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
"""Kjør kontrollene og skriv dommen. Returnerer exit-koden."""
|
||||
if argv not in ([], ["--rask"]):
|
||||
print("Bruk: kjor.py kontroll [--rask]", file=sys.stderr)
|
||||
return 2
|
||||
rask = argv == ["--rask"]
|
||||
arbeidskopi = (ROT / ARBEIDSKOPI_MERKE).is_file()
|
||||
regnemiljo = har_numpy_scipy()
|
||||
print(f"Kontroll av modellen i {MODELL}" + (" (arbeidskopi)" if arbeidskopi else "") + "\n", flush=True)
|
||||
dommer: list[Dom] = []
|
||||
|
||||
def vis(nummer: str, dom: Dom) -> None:
|
||||
dommer.append(dom)
|
||||
print(f"{nummer} {dom.linje}")
|
||||
for linje in dom.detaljer:
|
||||
print(f" {linje}")
|
||||
sys.stdout.flush()
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="dynamisk-rettsstat-") as tmp:
|
||||
mappe = Path(tmp)
|
||||
vis("1.", kontroll_kjerne())
|
||||
vis("2.", kontroll_utskrift("diagnose", mappe))
|
||||
if regnemiljo:
|
||||
vis("3.", kontroll_utskrift("forlop", mappe))
|
||||
else:
|
||||
vis("3.", Dom(IKKE_KJORT, "forlop: ikke kjørt, numpy og scipy mangler."))
|
||||
if rask:
|
||||
print("4. Full kjøring: hoppet over (--rask).")
|
||||
elif regnemiljo:
|
||||
vis("4.", kontroll_full(mappe))
|
||||
else:
|
||||
vis("4.", Dom(IKKE_KJORT, "Full kjøring: ikke kjørt, numpy og scipy mangler."))
|
||||
vis("5.", kontroll_utvidelser(mappe, regnemiljo=regnemiljo))
|
||||
print()
|
||||
print("\n".join(niva(dommer, rask=rask, arbeidskopi=arbeidskopi)))
|
||||
statuser = [d.status for d in dommer]
|
||||
if ENDRET in statuser:
|
||||
return 1
|
||||
if IKKE_KJORT in statuser:
|
||||
return 3
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.dont_write_bytecode = True
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
Loading…
Add table
Add a link
Reference in a new issue