gendesign/backend/tests/test_network_obremenenie.py
Light1YT 3f245026ee
All checks were successful
CI / changes (push) Successful in 8s
CI / frontend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Successful in 2m12s
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 9m0s
CI / openapi-codegen-check (pull_request) Successful in 1m50s
CI / backend-tests (pull_request) Successful in 8m49s
feat(site-finder): выделить сетевые обременения из ЗОУИТ (#1070, Refs #103)
cad_zouit содержит ~1930 сетевых охранных зон (тепло 548/электро 69/газ 23/связь 9/
инж.коммуникации 1281), но analyze отдавал их общими ЗОУИТ-overlaps без сетевого среза.
Pure-function classify_network_zone (type_zone→NetworkKind), сверен с prod distinct.
Overlap-строки cad_zouit несут is_network_zone/network_kind/network_kind_label; gate_verdict
даёт выделенный blocker ZOUIT_NETWORK_OBREMENENIE с видом сети (back-compat: классификация
на месте если флага нет; блокирующее поведение МКД сохранено). ЗСО санохраны источника
исключена из water (не сеть). 18 тестов.

#1070-предложение «сетевые обременения как analyze-слой» — реализовано через текущий cad_zouit.
ТУ-данные ООО Брик = needs-human (нет публичного API). engineering_networks loader = honest
blocked (источник публично пуст — QGIS-темплейт Минстроя 0 строк).

Closes #1070
2026-06-14 19:17:33 +05:00

141 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Tests for network-obremenenie классификатор (#1070) — pure function, no DB.
type_zone-строки взяты из реальных distinct-значений cad_zouit (PROD, 2026-06-14).
"""
from app.services.site_finder.gate_verdict import compute_gate_verdict
from app.services.site_finder.network_obremenenie import (
classify_network_zone,
is_network_obremenenie,
network_kind_label,
)
# ── classify_network_zone: реальные type_zone из cad_zouit ────────────────────
def test_thermal_zone():
assert classify_network_zone("Охранная зона тепловых сетей") == "thermal"
def test_electricity_zone():
tz = (
"Охранная зона объектов электроэнергетики (объектов электросетевого хозяйства "
"и объектов по производству электрической энергии)"
)
assert classify_network_zone(tz) == "electricity"
def test_pipeline_zone_gas_first():
# «трубопроводов (газопроводов, нефтепроводов …)» — газ ловится раньше pipeline.
tz = (
"Охранная зона трубопроводов (газопроводов, нефтепроводов "
"и нефтепродуктопроводов, аммиакопроводов)"
)
assert classify_network_zone(tz) == "gas"
def test_communication_zone():
assert classify_network_zone("Охранная зона линий и сооружений связи") == "communication"
def test_general_engineering_zone():
assert classify_network_zone("Охранная зона инженерных коммуникаций") == "general"
# ── негативные: НЕ сетевые ЗОУИТ ──────────────────────────────────────────────
def test_servitude_not_network():
assert classify_network_zone("Зона публичного сервитута") is None
def test_szz_not_network():
assert classify_network_zone("Санитарно-защитная зона") is None
def test_natural_zouit_not_network():
assert classify_network_zone("Зоны с особыми условиями использования территории") is None
def test_none_and_empty():
assert classify_network_zone(None) is None
assert classify_network_zone("") is None
def test_general_keyword_without_protection_marker_is_skipped():
# «инженерные коммуникации» без «охранная зона» → не ловим (избегаем ложных).
assert classify_network_zone("Размещение инженерных коммуникаций") is None
# ── helpers ───────────────────────────────────────────────────────────────────
def test_is_network_obremenenie():
assert is_network_obremenenie("Охранная зона тепловых сетей") is True
assert is_network_obremenenie("Зона публичного сервитута") is False
def test_network_kind_label():
assert network_kind_label("thermal") == "теплоснабжение"
assert network_kind_label("general") == "инженерные коммуникации"
assert network_kind_label(None) is None
# ── gate_verdict: сетевое обременение → выделенный blocker ─────────────────────
def _dump_available() -> dict:
return {"available": True, "stale": False}
def test_gate_verdict_thermal_network_blocker():
"""Теплосеть (#1070 ООО Брик) → ZOUIT_NETWORK_OBREMENENIE blocker."""
overlaps = [
{
"source": "cad_zouit",
"type_zone": "Охранная зона тепловых сетей",
"name": "ТС-123",
"is_network_zone": True,
"network_kind": "thermal",
"network_kind_label": "теплоснабжение",
}
]
verdict = compute_gate_verdict(None, overlaps, None, _dump_available())
codes = [b["code"] for b in verdict["blockers"]]
assert "ZOUIT_NETWORK_OBREMENENIE" in codes
assert verdict["can_build_mkd"] is False
detail = next(
b["detail"] for b in verdict["blockers"] if b["code"] == "ZOUIT_NETWORK_OBREMENENIE"
)
assert "теплоснабжение" in detail
def test_gate_verdict_servitude_not_network_blocker():
"""Сервитут (не сеть) → НЕ ZOUIT_NETWORK_OBREMENENIE."""
overlaps = [
{
"source": "cad_zouit",
"type_zone": "Зона публичного сервитута",
"name": "",
"is_network_zone": False,
"network_kind": None,
"network_kind_label": None,
}
]
verdict = compute_gate_verdict(None, overlaps, None, _dump_available())
codes = [b["code"] for b in verdict["blockers"]]
assert "ZOUIT_NETWORK_OBREMENENIE" not in codes
def test_gate_verdict_network_classified_when_flag_absent():
"""Back-compat: overlap без флага → gate_verdict классифицирует сам."""
overlaps = [
{
"source": "cad_zouit",
"type_zone": "Охранная зона объектов электроэнергетики",
"name": "ВЛ-10кВ",
}
]
verdict = compute_gate_verdict(None, overlaps, None, _dump_available())
codes = [b["code"] for b in verdict["blockers"]]
assert "ZOUIT_NETWORK_OBREMENENIE" in codes