Files
Aislo/common_util/common_util_calc_sites.py
T

124 lines
5.0 KiB
Python

"""계산 자리 판(PLAN 504-2 · 요구 309-2) — 시스템 관리자 「계산 자리」 창이 읽고 쓰는 판 하나.
판 = `resources/master_template/calc_sites.json` `{version, sites: {묶음: "both" | "server"}}`.
both = 조작 중 브라우저 셈 + [저장] 서버 정본(지금 등록부 자리) · server = 조작 중에도 서버 길
(G1 · D3 = 504-2 · ③ 토량 · ④ 이월 · ⑧ 고정 브라우저(시험용 · fixed 는 정본 칸 표시) = 511-A 창구).
판이 없거나 깨지면 기본값(전부 both = 등록부 그대로). [저장] · [확정] 서버 정본 길은 판을 안 읽음.
묶음 12 줄 = 등록부(`design_calc_registry*.ts`) # 전부 · 같은지 시험 `test_309_2_calc_sites.py`.
"""
from __future__ import annotations
import json
import os
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[1]
PATH = ROOT / "resources" / "master_template" / "calc_sites.json"
VALUES = ("both", "server")
# 묶음 · 등록부 # · 바꿀 수 있음 · 잠금 줄의 고정 자리(both · server · browser) · 까닭 열쇠
GROUPS: tuple[dict[str, Any], ...] = (
{"key": "ground_sample", "nos": ["G1"], "switchable": True, "fixed": None, "why": None},
{"key": "corridor_mesh", "nos": ["D3"], "switchable": True, "fixed": None, "why": None},
{
"key": "quantity",
"nos": ["E1", "F7", "F8", "C4"],
"switchable": True,
"fixed": None,
"why": "quantity",
},
{"key": "carry", "nos": ["R9", "F10"], "switchable": True, "fixed": None, "why": "carry"},
# 묶음 단계(511-B · 단계째 서버 Node `stage.*`) — 짝 모으기 B-3 ~ B-5 끝난 줄부터 엶
# 노선(511-B B-5 · 노선 저장 폴리라인 = Node `route.polyline` · 조작 중 「서버」 = 같은 id)
{"key": "route", "nos": ["R1", "R3"], "switchable": True, "fixed": None, "why": None},
{
"key": "follow",
"nos": ["P5", "P6", "F1", "F2"],
"switchable": False,
"fixed": "both",
"why": "pair_B5",
},
# 측점(511-B B-2 · 서버 측점 생성 = Node `stations.sections` · 조작 중 「서버」 = `stations.list`)
{
"key": "stations",
"nos": ["R5", "R6", "R7", "F3"],
"switchable": True,
"fixed": None,
"why": None,
},
{
"key": "profile",
"nos": ["P1", "P2", "P3", "P4", "P8"],
"switchable": False,
"fixed": "both",
"why": "pair_B3",
},
{
"key": "cross",
"nos": ["G2", "G4", "C1", "C2", "C3", "C5", "C6", "F4", "F5", "F6"],
"switchable": False,
"fixed": "both",
"why": "pair_B4",
},
# 폼 기본값 도구(B04 · B08 파이썬 · 고를 것 없음)
{"key": "form_default", "nos": ["F9"], "switchable": False, "fixed": "both", "why": None},
{
"key": "fixed_server",
"nos": ["E2", "G3", "D1", "D2", "N1"],
"switchable": False,
"fixed": "server",
"why": "server",
},
{
"key": "fixed_browser",
"nos": ["R2", "R4", "R8", "P7", "C7", "D4"],
"switchable": True,
"fixed": "browser",
"why": "browser",
},
)
# 판 줄 차례 = 묶음 차례(파일 늘 같은 꼴)
ORDER = tuple(g["key"] for g in GROUPS if g["switchable"])
SWITCHABLE = frozenset(ORDER)
LOCKED = frozenset(g["key"] for g in GROUPS if not g["switchable"])
def read_sites() -> dict[str, Any]:
"""판 — 없음 · 깨짐 · 모르는 값 = 그 줄 기본값(both)."""
try:
raw = json.loads(PATH.read_text(encoding="utf-8"))
except (OSError, ValueError):
raw = {}
stored = raw.get("sites") if isinstance(raw, dict) else None
stored = stored if isinstance(stored, dict) else {}
sites = {k: stored.get(k) if stored.get(k) in VALUES else "both" for k in ORDER}
version = raw.get("version") if isinstance(raw, dict) else None
return {"version": version if isinstance(version, int) else 0, "sites": sites}
def check_changes(changes: dict[str, str]) -> None:
"""잠금 줄 · 모르는 줄 · 모르는 값 = ValueError(창구가 400)."""
for key, value in changes.items():
if key in LOCKED:
raise ValueError(f"잠긴 줄 — {key}")
if key not in SWITCHABLE:
raise ValueError(f"모르는 줄 — {key}")
if value not in VALUES:
raise ValueError(f"모르는 값 — {key}={value}")
def write_sites(changes: dict[str, str]) -> tuple[dict[str, Any], list[str]]:
"""검사 → 바뀐 줄만 얹어 판 번호 +1 · 통째 바꿔 씀(반쯤 쓴 판 없음). 돌려줌 = 새 판 · 바뀐 줄."""
check_changes(changes)
current = read_sites()
changed = sorted(k for k, v in changes.items() if current["sites"][k] != v)
if not changed:
return current, []
board = {"version": current["version"] + 1, "sites": {**current["sites"], **changes}}
temp = PATH.with_suffix(".json.tmp")
temp.write_text(json.dumps(board, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
os.replace(temp, PATH)
return board, changed