Weichenknoten zwischen Kreiseln, Track-Mouseover, Parameter in cfg/parameter.ini

TRO-Typen an Kreisel-Beruehrpunkten (lib/kreisel_junctions.py, derive_tros
Schritt 3c): jeder Kreisel als Stadion-Form mit Laufrichtung; jeder
gleichlaufende Beruehrpunkt ist eine Weiche (exportierte ILS Weiche oder
abgeleitet W<a>_<b>), Beruehrpunkte derselben Umlenkung bilden einen
Knoten. Ein Separator steuert ihn, wenn er in Laufrichtung unmittelbar
davor liegt (keine andere Weiche dazwischen). Typ = Separatoren x Weichen.
export.csv: 1Sep1Swi (9/1, 9/8, 8/7), 2Sep1Swi (7/2), 2Sep2Swi (2/3/4),
3Sep2Swi (4/5/6). Neuer Katalogtyp 3Sep2Swi (nicht aus SCL belegt).
Gegenlaeufige Beruehrpunkte (Mubea, Dematic) bleiben bei der alten Regel;
Mubea/HundM05/Dematic unveraendert, Showroom 0018+0019 jetzt 2Sep1Swi.

material_flow --track: Mouseover je Knoten mit Zugehoerigkeit zu
Kreisel/VF/GF (Zuordnung, TrackIds-Kette, Lage laut Geometrie), Weiche mit
beiden Kreiseln, Be-/Entladung mit ihrem Kreisel; Widersprueche mit "!".

Zahlenwerte (Toleranzen, Schwellen, Massstaebe, Groessen) aus allen
lib-Modulen nach cfg/parameter.ini (lib/parameter.py, Abschnitt je Modul,
Ueberschreiben je Anlage ueber %SKEL_CFG%/parameter.ini). Ausgaben aller
Anlagen bytegleich.

tro_flow.py: Docstrings mit Parametern/Rueckgabe, fehlende Typangaben.

Geprueft: 90 Tests gruen; tro_flow/material_flow/scl_skeleton auf 5 CSVs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-10-14 17:20:30 +02:00
co-authored by Claude Opus 5.5
parent 0c69faf3db
commit 550bdeb464
17 changed files with 1634 additions and 125 deletions
+69
View File
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
"""Tests fuer lib/parameter.py und cfg/parameter.ini."""
from __future__ import annotations
import configparser
import re
from pathlib import Path
import pytest
import parameter
from parameter import ParameterError, get_float, get_int
ROOT = Path(__file__).resolve().parent.parent
BASE = ROOT / "cfg" / parameter.PARAMETER_FILE
@pytest.fixture
def frisch(monkeypatch: pytest.MonkeyPatch):
"""Parameter-Cache leeren, damit SKEL_CFG im Test wirkt - und danach wieder."""
parameter._parser.cache_clear()
yield monkeypatch
parameter._parser.cache_clear()
def _base() -> configparser.ConfigParser:
parser = configparser.ConfigParser(inline_comment_prefixes=(";", "#"))
parser.read(BASE, encoding="utf-8")
return parser
def test_base_values_are_read(frisch: pytest.MonkeyPatch) -> None:
frisch.delenv("SKEL_CFG", raising=False)
assert get_float("kreisel_junctions", "contact_tolerance") == 50.0
assert get_int("tro_flow", "min_store_lanes") == 2
def test_skel_cfg_overrides_single_value(frisch: pytest.MonkeyPatch, tmp_path: Path) -> None:
(tmp_path / parameter.PARAMETER_FILE).write_text(
"[kreisel_junctions]\ncontact_tolerance = 75 ; Anlage X\n", encoding="utf-8")
frisch.setenv("SKEL_CFG", str(tmp_path))
assert get_float("kreisel_junctions", "contact_tolerance") == 75.0
# nicht ueberschriebene Werte kommen weiter aus der Grunddatei
assert get_float("kreisel_junctions", "separator_tolerance") == 100.0
def test_missing_key_is_an_error(frisch: pytest.MonkeyPatch) -> None:
frisch.delenv("SKEL_CFG", raising=False)
with pytest.raises(ParameterError, match=r"\[tro_flow\] gibt_es_nicht fehlt"):
get_float("tro_flow", "gibt_es_nicht")
def test_non_number_is_an_error(frisch: pytest.MonkeyPatch, tmp_path: Path) -> None:
(tmp_path / parameter.PARAMETER_FILE).write_text(
"[tro_flow]\nmin_store_lanes = zwei\n", encoding="utf-8")
frisch.setenv("SKEL_CFG", str(tmp_path))
with pytest.raises(ParameterError, match="keine ganze Zahl"):
get_int("tro_flow", "min_store_lanes")
def test_every_key_is_used_by_its_module() -> None:
"""Jeder Schluessel der Grunddatei wird in lib/<Abschnitt>.py gelesen -
keine verwaisten Werte, die nichts mehr steuern."""
parser = _base()
for section in parser.sections():
source = (ROOT / "lib" / f"{section}.py").read_text(encoding="utf-8")
for key in parser.options(section):
assert re.search(rf'"{key}"', source), f"[{section}] {key} wird nicht gelesen"