knowledge(M01): 값 없는 자재품목 줄 가운데 로직이 실제로 쓰는 것만 가림
- `scripts/check_값없는줄.py` 신설 — 로직 1,354 줄을 훑어 호표 직접 지정·고르기 조건 후보· 대표 줄·품셈재료 연결(문자열 키·지역 조건)까지 실제 참조를 셈, 값은 안 채움 - 재료_자재품목.json 다섯 칸(물가자료·유통물가·물가정보·거래가격·관급) 모두 빈 줄 345 가운데 로직이 실제로 가리키는 진짜 구멍은 31 줄 — `ref/_분석_값없는줄.md` 신설 - `ref/_관리자값_미확보.md` 재검증 — 45종 가운데 6종은 고르기 조건으로 바뀌었거나 로직이 재료 자체를 뺀 것이라 로직이 안 씀으로 옮김, 남은 39종·로직 49개는 그대로 관리자 몫 - `ref/_없는_재료.md` 재검증 — 111줄 모두 지금도 로직이 부름, 뺄 줄 없음 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# -*- 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())
|
||||
Reference in New Issue
Block a user