122 lines
4.8 KiB
Python
122 lines
4.8 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-2 ~ B-5 끝난 줄부터 엶
|
|
{"key": "route", "nos": ["R1", "R3"], "switchable": False, "fixed": "both", "why": "pair_B5"},
|
|
{
|
|
"key": "follow",
|
|
"nos": ["P5", "P6", "F1", "F2"],
|
|
"switchable": False,
|
|
"fixed": "both",
|
|
"why": "pair_B5",
|
|
},
|
|
{
|
|
"key": "stations",
|
|
"nos": ["R5", "R6", "R7", "F3"],
|
|
"switchable": False,
|
|
"fixed": "both",
|
|
"why": "pair_B2",
|
|
},
|
|
{
|
|
"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
|