Files
dxfmakros/tests/test_export_sivas_as_es.py
T
y.wang 4ce2a02205 feat: Sivas-Merkmale 4427-4432 (AS-/ES-Element) im Export befuellen
Die Streckenbloecke GF_N und VF_N tragen Winkel und Seite ihres AS-/ES-
Elements bereits als Attribute des gemeinsamen Schemas (WINKEL_AS/SEITE_AS/
WINKEL_ES/SEITE_ES, *strecke-attr-front* in ssg_core.lsp). Diese Information
landet jetzt auch im details-JSON des Sivas-Exports.

Zuordnung (Sivas-Hierarchie: 4431/4432 schalten Winkel und Seite frei):
  4431/4432  AS-/ES-Element vorhanden   Ja/Nein
  4427/4429  Winkel                     "30 °"/"90 °"
  4428/4430  Seite                      links/rechts

Die Zuordnung steht vollstaendig in cfg/sivas.cfg - mit denselben sechs
Zeilen in [gefaellestrecke] und [variofoerderer], jeweils direkt hinter 2950,
was auch die Reihenfolge im details-JSON bestimmt.

Ob ein Element vorhanden ist, entscheidet ausschliesslich WINKEL_AS/WINKEL_ES:
das Schema laesst den Winkel leer, wenn keines gewaehlt wurde, waehrend
SEITE_AS/SEITE_ES mit "rechts" immer einen Vorgabewert tragen. Ohne Element
bleiben Winkel UND Seite leer, damit in Sivas keine Seite unter einem
"Nein"-Knoten haengt.

Weitere Punkte:
- sivas_mapping: neuer Dekorator @braucht_attribs. Ein so markierter
  Transform wird als fn(wert, attribs) statt fn(wert) aufgerufen und sieht
  damit die uebrigen Attribute des Blocks - noetig, weil die Seite vom
  Winkel abhaengt. Ohne diese Klammer muessten bedingte Merkmale wieder als
  Python-Code aus der Config herauswandern.
- Die Winkel-Schreibweise der Sivas-Auswahlliste ("30 °" mit Leerzeichen vor
  dem Gradzeichen) steht als Tabelle [as_es_winkel_anzeige] in sivas.cfg,
  Bauart wie [geruest_typ_anzeige] - weicht Sivas davon ab, ist das die
  einzige Stelle zum Nachziehen.
- gefaellestrecke_signature beruecksichtigt AS/ES: zwei sonst baugleiche
  Gefaellestrecken mit AS links bzw. rechts bleiben getrennte Zeilen, sonst
  zeigte die gemeinsame Zeile nur die Seite des ersten Blocks.
- Altbestand ohne diese Attribute meldet "Nein" statt abzubrechen.
- Merkmalsstamm_in_Sivas.xlsx auf den aktuellen Sivas-Stand gebracht
  (enthaelt neben 4427-4432 auch 4002, 7010-7013 und Klartext-Korrekturen;
  4339/4383 heissen jetzt eindeutig "... Gefaellestrecke"/"... Variofoerderer").
- 12 neue Tests in tests/test_export_sivas_as_es.py, ohne BricsCAD lauffaehig.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-21 12:55:01 +02:00

182 lines
7.9 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
test_export_sivas_as_es.py - Sivas-Merkmale 4427-4432 (AS-/ES-Element) fuer
Gefaellestrecke (GF_N) und Streckengruppe (VF_N).
Pruefpunkte: Vorhandensein haengt am Winkel (nicht an der Seite, die immer
einen Vorgabewert traegt), der Winkel wird in die Sivas-Schreibweise der
Auswahlliste uebersetzt, ohne Element bleiben Winkel UND Seite leer, die
Zuordnung steht vollstaendig in cfg/sivas.cfg, und die GF-Gruppierung trennt
Bloecke mit unterschiedlichem AS-/ES-Element.
Laeuft komplett ohne BricsCAD (reine Python-Logik).
"""
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
import export_sivas # noqa: E402
import sivas_mapping # noqa: E402
# Sivas-Schreibweise der Winkel-Auswahlliste (cfg/sivas.cfg
# [as_es_winkel_anzeige]) - die Tests vergleichen gegen die Config, damit ein
# Nachziehen der Schreibweise dort nicht die halbe Testdatei bricht.
W30 = export_sivas.as_es_winkel("30")
W90 = export_sivas.as_es_winkel("90")
def _strecke(nr, typ="Gefaellestrecke", **attr):
"""GF_N-/VF_N-Block mit dem gemeinsamen Strecken-Attributschema."""
attribs = {"ID": f"000{nr}", "Bezeichnung": f"GF_{nr}", "ARTINR": "6220",
"MONTAGEHOEHE_m": "2.000", "HOEHE_VON_mm": "2000",
"HOEHE_BIS_mm": "1000", "TYP": typ,
"L_GF_m": "3.000", "GF_WINKEL": "3",
"SEITE_AS": "links", "WINKEL_AS": "90",
"SEITE_ES": "links", "WINKEL_ES": "90"}
attribs.update(attr)
return {"block_name": f"GF_{nr}", "x": 0.0, "y": 0.0, "z": 2000.0,
"rotation": 0.0, "attribs": attribs}
def test_as_es_vorhanden_mit_winkel_und_seite():
details = export_sivas.build_gefaellestrecke_details(_strecke(1))
assert details["4431"] == "Ja"
assert details["4427"] == W90
assert details["4428"] == "links"
assert details["4432"] == "Ja"
assert details["4429"] == W90
assert details["4430"] == "links"
def test_zuordnung_steht_in_der_config():
"""Die sechs Merkmale muessen in BEIDEN Strecken-Abschnitten von
sivas.cfg stehen (GF_N und VF_N lesen dieselben Attribute)."""
for abschnitt in ("gefaellestrecke", "variofoerderer"):
mapping = sivas_mapping.load_section_mapping(abschnitt)
for merkmal, attribut, transform in (
("4431", "WINKEL_AS", "as_es_vorhanden"),
("4427", "WINKEL_AS", "as_es_winkel"),
("4428", "SEITE_AS", "as_seite"),
("4432", "WINKEL_ES", "as_es_vorhanden"),
("4429", "WINKEL_ES", "as_es_winkel"),
("4430", "SEITE_ES", "es_seite")):
assert merkmal in mapping, f"{merkmal} fehlt in [{abschnitt}]"
ist_attribut, _alt, _default, ist_transform = mapping[merkmal]
assert ist_attribut == attribut, f"[{abschnitt}] {merkmal}"
assert ist_transform == transform, f"[{abschnitt}] {merkmal}"
assert ist_transform in export_sivas.TRANSFORMS
def test_winkel_in_sivas_schreibweise():
"""4427/4429 tragen den Optionswert der Auswahlliste, nicht die nackte
Attributzahl (Vorgabe aus cfg/sivas.cfg [as_es_winkel_anzeige])."""
details = export_sivas.build_gefaellestrecke_details(
_strecke(1, WINKEL_AS="30", WINKEL_ES="90.0"))
assert details["4427"] == W30
assert details["4429"] == W90
# Unbekannter Winkel faellt auf die ganzzahlige Rohzahl zurueck
assert export_sivas.as_es_winkel("60.0") in (W30, W90, "60")
def test_ohne_winkel_kein_element_und_keine_seite():
"""Leerer WINKEL_AS = kein AS-Element; die Seite darf dann NICHT
durchgereicht werden (SEITE_AS traegt mit "rechts" immer einen
Schema-Vorgabewert)."""
details = export_sivas.build_gefaellestrecke_details(
_strecke(1, WINKEL_AS="", SEITE_AS="rechts"))
assert details["4431"] == "Nein"
assert details["4427"] == ""
assert details["4428"] == ""
# ES bleibt davon unberuehrt
assert details["4432"] == "Ja"
assert details["4430"] == "links"
def test_seite_rechts():
details = export_sivas.build_gefaellestrecke_details(
_strecke(1, SEITE_AS="rechts", SEITE_ES="rechts"))
assert details["4428"] == "rechts"
assert details["4430"] == "rechts"
def test_variofoerderer_hat_dieselben_merkmale():
block = _strecke(1, typ="Streckengruppe", L_VF_m="2.000", VF_WINKEL="0",
ANTRIEBFAHRTRICHTUNG="Auf", MOTORSEITE="rechts",
WINKEL_AS="30", SEITE_AS="rechts")
details = export_sivas.build_variofoerderer_details(block)
assert details["4431"] == "Ja"
assert details["4427"] == W30
assert details["4428"] == "rechts"
assert details["4429"] == W90
def test_gruppierung_trennt_nach_as_seite():
"""Sonst baugleiche Gefaellestrecken mit AS links bzw. rechts duerfen
nicht in einer Sivas-Zeile landen (die Zeile wuerde nur eine der beiden
Seiten zeigen)."""
links = export_sivas.gefaellestrecke_signature(_strecke(1, SEITE_AS="links"))
rechts = export_sivas.gefaellestrecke_signature(_strecke(2, SEITE_AS="rechts"))
assert links != rechts
assert links == export_sivas.gefaellestrecke_signature(_strecke(3, SEITE_AS="links"))
def test_gruppierung_trennt_nach_as_winkel():
assert (export_sivas.gefaellestrecke_signature(_strecke(1, WINKEL_AS="30"))
!= export_sivas.gefaellestrecke_signature(_strecke(2, WINKEL_AS="90")))
def test_gruppierung_ohne_element_ignoriert_die_seite():
"""Ohne AS-Element ist die Seite bedeutungslos und steht auch nicht in der
Zeile - sie darf die Gruppierung dann nicht aufspalten."""
assert (export_sivas.gefaellestrecke_signature(
_strecke(1, WINKEL_AS="", SEITE_AS="links"))
== export_sivas.gefaellestrecke_signature(
_strecke(2, WINKEL_AS="", SEITE_AS="rechts")))
def test_reihenfolge_im_details_json():
"""Die sechs Merkmale stehen im details-JSON direkt HINTER 2950
(Anlagenhoehe) - so vorgegeben, und so steht es in beiden Abschnitten von
sivas.cfg. Die Reihenfolge der JSON-Keys folgt der Zeilenreihenfolge der
Config (configparser und dict erhalten beide die Einfuegereihenfolge)."""
erwartet = ["2950", "4431", "4427", "4428", "4432", "4429", "4430"]
gf = list(export_sivas.build_gefaellestrecke_details(_strecke(1)))
vf = list(export_sivas.build_variofoerderer_details(
_strecke(2, typ="Streckengruppe", L_VF_m="2.000")))
assert gf[:len(erwartet)] == erwartet
assert vf[:len(erwartet)] == erwartet
def test_altbestand_ohne_die_attribute():
"""Bloecke aus Zeichnungen, die vor der Einfuehrung von WINKEL_AS gebaut
wurden, haben die Attribute gar nicht - dann greift der leere Default und
es wird "Nein" gemeldet (statt KeyError). Das ist die einzig moegliche
Aussage: Sivas kennt nur Ja/Nein, kein "unbekannt"."""
block = _strecke(1)
for tag in ("WINKEL_AS", "SEITE_AS", "WINKEL_ES", "SEITE_ES"):
del block["attribs"][tag]
details = export_sivas.build_gefaellestrecke_details(block)
assert details["4431"] == "Nein"
assert details["4432"] == "Nein"
assert details["4427"] == details["4428"] == ""
assert details["4429"] == details["4430"] == ""
def test_transform_mit_attribs_kontext():
"""Der @braucht_attribs-Transform muss das komplette Attribut-Dict sehen -
sonst koennte die Seite ihre Abhaengigkeit vom Winkel nicht pruefen."""
assert getattr(export_sivas.as_seite, "braucht_attribs", False)
assert getattr(export_sivas.es_seite, "braucht_attribs", False)
assert not getattr(export_sivas.ja_nein, "braucht_attribs", False)
mapping = {"4428": ("SEITE_AS", None, "", "as_seite")}
attribs = {"SEITE_AS": "links", "WINKEL_AS": "90"}
assert sivas_mapping.anwenden(mapping, attribs, export_sivas.TRANSFORMS) \
== {"4428": "links"}
attribs_ohne = {"SEITE_AS": "links", "WINKEL_AS": ""}
assert sivas_mapping.anwenden(mapping, attribs_ohne, export_sivas.TRANSFORMS) \
== {"4428": ""}