# -*- coding: utf-8 -*- """511-B B-5 노선 저장 체인 시간 · 값 — 검증 프로젝트의 지금 노드 · 편집표 그대로 저장(수동 실행). 같은 노선이라 값은 그대로(새 노선 행 번호만 바뀜) · 초기값 안 건드림(`as_initial` 끔). 갈래 = 파이썬 짝(Node 폴리라인 · 좌표 맞춤 끔) / Node 를 번갈아 N 번 · 저장 뒤 정본 파일 해시 (노선 csv · 노드 · 곡선표 · 구조물 · 관 · 추가 측점 · 종단 · 횡단)가 처음과 같은지. 쓰는 법: `./venv/Scripts/python.exe resources/tester/run_511_b5_route_save_timing.py [N]` """ import asyncio import hashlib import json import logging import statistics import sys import time from pathlib import Path from uuid import UUID ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) from config.config_db import close_db_pool, init_db_pool # noqa: E402 CANON = ( "B05_Profile/route/planned_route.csv", "B05_Profile/route/planned_route_nodes.csv", "B05_Profile/route/planned_route_curves.json", "B05_Profile/route/route_main.geojson", "B05_Profile/route/structures.json", "B05_Profile/route/plus_stations.json", "B04_PreProcess/drainage/edits/pipe_points.json", ) def _hashes(root: Path) -> dict[str, str]: files = [root / name for name in CANON] files += sorted((root / "B06_Section").rglob("*.json")) return { str(path.relative_to(root)): hashlib.sha256(path.read_bytes()).hexdigest()[:16] for path in files if path.is_file() } async def _save(project_id: UUID, python: bool) -> float: from B05_Profile import B05_Profile_Route_Polyline_Write as writer from B05_Profile import B05_Profile_Router_Replan as replan from B05_Profile.B05_Profile_Route_Save import RouteSaveRequest from common_util import common_util_route_follow as follow plan = await replan.read_route_plan(project_id) edits = plan["node_edits"] body = RouteSaveRequest( vertices=[ {"x": n["x"], "y": n["y"], "curve": e["curve"], "radius_m": e["radius_m"]} for n, e in zip(plan["nodes"], edits, strict=True) ], station_snap=bool(plan.get("station_snap")), station_snap_step=plan.get("station_snap_step"), ) real = (writer.node_polyline, follow.fill_structure_coordinates) if python: writer.node_polyline = lambda *a: None follow.fill_structure_coordinates = follow._fill_structure_coordinates_py try: started = time.perf_counter() result = await replan.replan_route(project_id, body) seconds = time.perf_counter() - started finally: writer.node_polyline, follow.fill_structure_coordinates = real status = getattr(result, "status_code", 200) assert status == 200, getattr(result, "body", result) return seconds async def main(project_id: UUID, rounds: int) -> None: from B05_Profile import B05_Profile_Router_Replan as replan logging.basicConfig(level=logging.WARNING, format="%(message)s") await init_db_pool() try: root, _ = await replan._project_paths(project_id) first = _hashes(root) times: dict[str, list[float]] = {"python": [], "node": []} for _ in range(rounds): for kind in ("python", "node"): times[kind].append(await _save(project_id, kind == "python")) after = _hashes(root) changed = sorted( k for k in first.keys() | after.keys() if first.get(k) != after.get(k) ) print(f"{kind}: {times[kind][-1]:.2f} s · 바뀐 정본 {len(changed)} {changed[:5]}") print( json.dumps( { k: { "median_s": round(statistics.median(v), 2), "runs": [round(x, 2) for x in v], } for k, v in times.items() }, ensure_ascii=False, ) ) finally: from common_util.common_util_calc_runner import _SERVED _SERVED.stop() await close_db_pool() if __name__ == "__main__": asyncio.run(main(UUID(sys.argv[1]), int(sys.argv[2]) if len(sys.argv) > 2 else 3))