# -*- coding: utf-8 -*- """재료_자재품목.json 다섯 값 칸이 모두 빈 줄 가운데 로직이 실제로 가리키는 줄 — 읽기 전용 분석. · 「빈 줄」 = 물가자료·유통물가·물가정보·거래가격·관급 다섯 칸이 모두 없음 · 「로직이 가리킴」 = 로직 호표 요소가 그 키를 바로 적음 · 재료 고르기 조건(구분·상세구분·규격)의 후보 줄 · 대표 줄로 콕 집음 · 품셈재료 연결(문자열 키 · 지역 조건)을 따라간 줄 · 지역 조건(모래·자갈 등)은 실제 프로젝트 자재지역을 모르므로 지역을 안 가리고 이름·단위만 맞춤 (후보를 넓게 잡아 「안 쓰임」 판정이 헛짚지 않게) · 값은 채우지 않음 · 마스터 파일을 고치지 않음 돌리기: ./venv/Scripts/python.exe resources/master_data/scripts/check_값없는줄.py """ from __future__ import annotations import json import sys from pathlib import Path HERE = Path(__file__).resolve().parent MASTER = HERE.parent sys.path.insert(0, str(HERE)) import check_master as cm # noqa: E402 import master_material as mm # noqa: E402 PRICE = ("물가자료", "유통물가", "물가정보", "거래가격", "관급") # 두 ref 표의 키 목록 — 로직이 지금도 부르는지 다시 잣대질할 때 씀 (`_관리자값_미확보.md`·`_없는_재료.md`) ADMIN_KEYS = ( "MP000253 MP000290 MP000293 MP000048 MP000094 MP000216 MP000299 MP000359 " "MP000023 MP000052 MP000055 MP000060 MP000065 MP000066 MP000070 MP000076 MP000082 " "MP000095 MP000113 MP000129 MP000134 MP000144 MP000150 MP000169 MP000172 MP000176 " "MP000177 MP000201 MP000202 MP000209 MP000211 MP000215 MP000218 MP000235 MP000239 " "MP000241 MP000242 MP000250 MP000269 MP000294 MP000310 MP000314 MP000319 MP000357 " "MP000363" ).split() NO_ITEM_KEYS = ( "MP000012 MP000038 MP000048 MP000052 MP000055 MP000056 MP000057 MP000060 " "MP000065 MP000070 MP000076 MP000077 MP000078 MP000082 MP000095 MP000096 MP000101 " "MP000113 MP000129 MP000134 MP000139 MP000144 MP000148 MP000150 MP000169 MP000172 " "MP000176 MP000177 MP000201 MP000209 MP000210 MP000211 MP000212 MP000213 MP000214 " "MP000216 MP000218 MP000220 MP000221 MP000223 MP000235 MP000239 MP000240 MP000241 " "MP000242 MP000250 MP000253 MP000254 MP000255 MP000257 MP000258 MP000259 MP000260 " "MP000261 MP000262 MP000265 MP000269 MP000271 MP000272 MP000273 MP000274 MP000275 " "MP000276 MP000280 MP000281 MP000285 MP000286 MP000287 MP000288 MP000290 MP000293 " "MP000294 MP000295 MP000296 MP000297 MP000298 MP000299 MP000301 MP000302 MP000303 " "MP000304 MP000305 MP000306 MP000308 MP000309 MP000310 MP000314 MP000315 MP000319 " "MP000325 MP000326 MP000327 MP000328 MP000330 MP000334 MP000335 MP000336 MP000337 " "MP000338 MP000340 MP000341 MP000342 MP000343 MP000344 MP000345 MP000349 MP000351 " "MP000352 MP000353 MP000359 MP000363" ).split() def all_empty(master) -> set[str]: """MT 다섯 값 칸이 모두 빈 키.""" return { key for key, row in master.index.get(mm.MARKET, {}).items() if not mm._offers(master, key) } def region_reach(master, name, unit) -> set[str]: """MP 연결이 지역 조건(모래·자갈 등)일 때 이름 뿌리·단위만으로 넓게 잡은 후보.""" want, need = mm.plain(name), (mm.plain_unit(unit) if unit else "") return { key for root, _, _, u, key in mm._market_index(master) if root.endswith(want) and (not need or u == need) } def reached(master) -> tuple[set[str], set[str]]: """(로직이 가리키는 MT 키, 로직이 지금도 문자열로 부르는 MP 키).""" mt_hit: set[str] = set() mp_hit: set[str] = set() for path in sorted(MASTER.glob("로직_*.json")): rows = json.loads(path.read_text(encoding="utf-8")).get("줄", []) for row in rows: for h in row.get("호표") or []: e, unit = h.get("요소"), h.get("단위") if isinstance(e, str) and e[:2] == mm.MARKET: mt_hit.add(e) elif isinstance(e, dict) and "구분" in e: mt_hit.update(mm.candidates(master, e, None, unit)) if e.get("대표"): mt_hit.add(str(e["대표"])) elif isinstance(e, str) and e[:2] == mm.LINKED: mp_hit.add(e) link = master.index.get(mm.LINKED, {}).get(e, {}).get("연결") if isinstance(link, str) and link[:2] == mm.MARKET: mt_hit.add(link) elif isinstance(link, dict) and "계약종별" not in link: mrow = master.index[mm.LINKED][e] mt_hit.update(region_reach(master, link.get("이름"), mrow.get("단위"))) return mt_hit, mp_hit def main() -> int: master = cm.master() empty = all_empty(master) mt_hit, mp_hit = reached(master) gap = sorted(empty & mt_hit) print(f"MT 줄 {len(master.index.get(mm.MARKET, {}))}") print(f"다섯 칸 모두 빈 줄 {len(empty)} · 그 가운데 로직이 가리키는 줄 {len(gap)}") for key in gap: row = master.get(key) print(f" {key} {row.get('이름')} ({row.get('구분')}·{row.get('상세구분')})") print(f"\n로직이 지금도 MP 키를 문자열로 부르는 곳 {len(mp_hit)}") for title, keys in ( ("_관리자값_미확보.md 45종", ADMIN_KEYS), ("_없는_재료.md 111줄", NO_ITEM_KEYS), ): unused = [k for k in keys if k not in mp_hit] print(f"{title} 가운데 로직이 이제 안 씀 {len(unused)} — {unused}") return 0 if __name__ == "__main__": sys.stdout.reconfigure(encoding="utf-8") sys.exit(main())