diff --git a/README.md b/README.md index e6f0480..2489600 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Live through COM on Windows, or headless through ezdxf anywhere — one typed co -> **v1.5 release snapshot:** 247 tools · 8 resources · 5 prompt templates · 4981 collected tests. +> **v1.5 release snapshot:** 247 tools · 8 resources · 5 prompt templates · 4982 collected tests. > 247 is the **registered** count; a default install advertises 242 over `tools/list`, > because `ENABLE_3D` is unset. `system_about` is the runtime authority. diff --git a/engineering/understand/labels.py b/engineering/understand/labels.py index 3704a87..06f4289 100644 --- a/engineering/understand/labels.py +++ b/engineering/understand/labels.py @@ -135,6 +135,15 @@ _WIRING_PHRASES = ( ) #: Turkish puts the panel first: ``CP1 panosuna`` ("to the CP1 panel"). _WIRING_PHRASES_AFTER = ("panosuna", "panosundan") +#: The bare Russian preposition к / ко ("to") with the panel as the next word, +#: optionally after "щиту" / "шкафу" / "панели" (switchboard / cabinet / panel): +#: a Russian P&ID closes a load's text with ``к CP1``. Only a whole word counts, +#: so the к of кВт is no preposition. +_RU_TO_PANEL = re.compile( + r"(?:^|\s)ко?\s+" + r"(?:(?:щиту|шкафу|панели)\s+)?", + re.IGNORECASE, +) def plain(text: str | None) -> str: @@ -295,7 +304,9 @@ def wiring_target(text: str | None) -> str | None: ``"Wiring to CP1"`` -> ``"CP-1"``; ``"подключение к шкафу CP-1"`` -> ``"CP-1"``; ``"CP 2 panosuna"`` -> ``"CP-2"`` (Turkish names the panel - first). None when the text has no wiring phrase or no panel beside it. + first); ``"... кВт\\nк CP1"`` -> ``"CP-1"`` (the bare Russian "to", the + panel as the next word). None when the text has no wiring phrase or no + panel beside it. """ body = plain(text) lowered = body.lower() @@ -311,4 +322,8 @@ def wiring_target(text: str | None) -> str | None: matches = list(_PANEL_RE.finditer(fold_lookalikes(body[:at]))) if matches: return f"{matches[-1].group(1)}-{matches[-1].group(2)}" + for to in _RU_TO_PANEL.finditer(body): + panel = _PANEL_RE.match(fold_lookalikes(body[to.end() :])) + if panel is not None: + return f"{panel.group(1)}-{panel.group(2)}" return None diff --git a/tests/test_understand_labels.py b/tests/test_understand_labels.py index 1faeed8..dc1eeca 100644 --- a/tests/test_understand_labels.py +++ b/tests/test_understand_labels.py @@ -212,6 +212,16 @@ def test_wiring_callouts_in_four_languages(): assert wiring_target("CP 2 panosuna") == "CP-2" +def test_the_russian_to_before_a_panel_is_a_wiring_callout(): + # A Russian P&ID closes a load's text with the panel it is wired to: 'к CP1' + # ('to CP1'), or 'к щиту CP-2' ('to switchboard CP-2'). The unit кВт holds + # the same letter and is no preposition. + assert wiring_target("к CP1") == "CP-1" + assert wiring_target("P = 2,2 кВт\nк CP1") == "CP-1" + assert wiring_target("к щиту CP-2") == "CP-2" + assert wiring_target("P = 2,2 кВт") is None + + def test_a_callout_without_a_wiring_phrase_names_no_panel(): assert wiring_target("CP1") is None assert wiring_target("Wiring to") is None