Files
Aislo/old_code/resources/tester/test_form_const.py
T
eomsangdonandClaude Opus 5 8472fc9f40 refactor(B08,B09): 폴더째 old_code 로 옮기고 빈 화면 둘만 남김 (PLAN 7-3)
B08_Quantity 86 · B09_Estimation 111 파일을 old_code/ 로 옮김(지우지 않음).
화면은 메뉴·주소·단계 막대만 남은 빈 틀 둘 — main.py 라우터 13 개는 끊음.
B07 이 빌려 쓰던 비탈 길이·면적은 필요한 함수만 B07_DesignDetail_Engine_SlopeGeometry
로 옮겨 적음(면적 적분·노면 면적·측점 묶음은 안 옮김) · 시험 하나를 새로 둠.
B07 구조물도 조립(Cad_StandardSheet)은 2026-09-13 에 이미 도면 목록에서 빠져
부르는 곳이 없어 old_code 로 같이 보냄 — 구조물 그림은 되살리지 않음.
B06 구조물 몫 조회는 빈 값으로 두어 화면이 그대로 서게 함.
B08·B09 를 부르던 시험 25 개도 old_code/resources/tester 로 옮김.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
2026-09-22 12:27:45 +09:00

161 lines
7.3 KiB
Python

"""건설 표 모양 판정·밑수 읽기 — 2026-09-18 브레인 일감(랩탑 메인).
못박는 것
- ⚠ **산림은 건설 층에 닿지 않음** — 건설 규칙은 산림 잣대가 못 가른 표에서만 돌고, 산림 미판정은 0.
- 건설 꼴 여섯(기계 손료표 · 율·계수 · 값 없는 설명표 · 건설 직종 · 단위 칸 · 공식 기호)을 가름.
- **못 가리면 미판정** — 지어내지 않음.
- 밑수 읽기: 건설 꼴 `(용접개소당)`·`(세면기 개당)`·`(m당 : 관길이기준)`·`(일당)` 를 읽되
⚠ `(1ha당, 100본당)` 처럼 **둘이면 안 고름** · `공㎥당` 은 `㎥` 로 안 깎임 · 「회」는 밑수가 아님.
- ⚠ **작업조 표에는 「일」 밑수를 안 붙임**(c3da333e — 붙이면 유로폼 호표가 사라짐).
금액 불변은 `test_work_item_key_gate.py` 원가계산서 시험(직접공사비 5,983,724)이 잼.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_FormsConst import ( # noqa: E402
judged_const_form,
)
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Table import ( # noqa: E402
basis_from_source,
crew_table,
detect_form,
new_report,
table_entry,
)
FOREST = ROOT / "resources/data_cost_input_value/pum_forest_2026.json"
MASTER = ROOT / "resources/data_work_item_master"
def table(headers: list[str], rows: list[list[str]]) -> dict:
return {"table_id": "T0001", "section": "시험", "line": 3, "headers": headers, "rows": rows}
# ── 산림을 흔들지 않음 ────────────────────────────────────────────────────
def test_산림_표는_건설_층에_닿지_않음() -> None:
"""산림 표는 산림 잣대에서 이미 갈림 — 건설 규칙이 산림 값을 바꿀 수 없음(마스터 산출로 잼)."""
master = json.loads((MASTER / "work_item_master_2026-01-01.json").read_text(encoding="utf-8"))
reached = [
t["pum_table_id"]
for w in master["work_items"]
for t in w.get("tables", [])
if str(t.get("form_basis", "")).startswith("건설 꼴")
]
assert reached == [], f"산림 표가 건설 층까지 내려감: {reached[:5]}"
def test_산림_마스터는_형태_미판정이_없음() -> None:
master = json.loads((MASTER / "work_item_master_2026-01-01.json").read_text(encoding="utf-8"))
assert master["stats"]["form_undetermined"] == 0
# ── 건설 꼴 가름 ─────────────────────────────────────────────────────────
def test_기계_손료표는_계수() -> None:
got = judged_const_form(
table(
["분류 번호", "규격 (ton)", "내용 시간", "상각 비율", "시 간 당(10-7)"],
[["0101-0007", "7", "12,000", "0.9", "1,811"]],
)
)
assert got and got[0] == "coefficient"
@pytest.mark.parametrize(
"headers, rows",
[
(
["사용기간별 구 분", "3개월 (%)", "2개년초과 평균손율 (%)"],
[["철 물", "30", "85"]],
), # 손율
(["지형종류", "시가지"], [["계수", "0.58"]]), # 보정계수
(["설치간격", "0.6m이하"], [["요 율", "17%"]]), # 요율
],
)
def test_율_계수표는_계수(headers: list[str], rows: list[list[str]]) -> None:
got = judged_const_form(table(headers, rows))
assert got and got[0] == "coefficient"
def test_값이_없는_설명표는_참조() -> None:
got = judged_const_form(
table(["노 임 구 분", "산 정 식"], [["노임합계", "P+PO"], ["기본노임", "P"]])
)
assert got == ("reference", "값(숫자) 칸이 없음 — 설명·서식 표")
def test_건설_직종이_있으면_소요량() -> None:
got = judged_const_form(
table(["구 분", "특급 기술자", "고급 기술자"], [["작업계획", "0.5", "1.1"]])
)
assert got and got[0] == "requirement"
def test_비고의_산출식은_계수로_안_뒤집음() -> None:
"""인력품 표의 비고에 산출식이 있어도 **품 표**다(9-5-4 수치지도)."""
got = judged_const_form(
table(
["구 분", "고급 기술자", "비 고"],
[["자동독취", "0.016인", "4매×20분/60분/8시간=0.166일"]],
)
)
assert got and got[0] == "requirement"
def test_단위_칸과_값이_한_줄이면_소요량() -> None:
got = judged_const_form(table(["구 분", "단 위", "브라켓형"], [["비 계 공", "인", "1.40"]]))
assert got and got[0] == "requirement"
def test_줄_이름이_공식_기호뿐이면_계수() -> None:
got = judged_const_form(table(["구 분", "R.C.D", "올케이싱"], [["β", "1.14", "1.08"]]))
assert got and got[0] == "coefficient"
def test_못_가리면_미판정으로_남김() -> None:
"""지역·월별 숫자만 있는 표 — 무엇의 값인지 원문으로 못 가름."""
assert judged_const_form(table(["지역별", "1월", "2월"], [["춘천", "7", "5"]])) is None
assert detect_form(table(["지역별", "1월"], [["춘천", "7"]]), None)[0] == "undetermined"
# ── 밑수 읽기 ────────────────────────────────────────────────────────────
@pytest.mark.parametrize(
"line, want",
[
("1-2-1 용접접합('93년 보완)(용접개소당)", (1.0, "개소")),
("7-1-5 카운터형 세면기 설치(분리형)('26년 보완)(세면기 개당)", (1.0, "개")),
("- 1. 이중보온관 부설(m당 : 관길이기준)", (1.0, "m")),
("1-3-10 플륨관 해체('22년 보완)(일당)", (1.0, "일")),
("6-8-1 주철제 게이트 제수밸브 부설 및 접합('23년 보완)(기당)", (1.0, "기")),
("1-3-1 데크플레이트 가스절단('18년 보완)(절단길이 10m당)", (10.0, "m")),
("### 12-19. 강관비계 (단위: 공㎥당)", (1.0, "공㎥")),
("### 6-2-1. 둘레베기 (1ha당, 100본당)", (None, None)), # 밑수가 둘 — 안 고름
("### 10-4. 중기운반 (단위: 회당)", (None, None)), # 「회」는 밑수 단위가 아님
],
)
def test_건설_꼴_밑수_읽기(line: str, want: tuple) -> None:
assert basis_from_source([line, "", "| 머리 |"], 3) == want
def test_작업조_표에는_일_밑수를_안_붙임() -> None:
"""원문이 `(일당)` 이라도 작업조 표면 밑수를 비움 — 밑수는 시공량 열."""
crew = table(
["구 분", "단 위", "수 량", "시 공 량 (㎡)"],
[["형틀목공 보통인부", "인 인", "4 1", "25"]],
)
assert crew_table(crew)
lines = ["### 12-38-3 설치 및 해체 (일당)", "", "| 머리 |"]
entry = table_entry(crew, "12-38-3", "12-38-3", "12", lines, None, new_report())
assert (entry["basis_quantity"], entry["basis_unit"]) == (None, None)
plain = table(["구 분", "단 위", "수 량"], [["보통인부", "인", "1.4"]])
entry = table_entry(plain, "2-1", "2-1", "2", lines, None, new_report())
assert (entry["basis_quantity"], entry["basis_unit"]) == (1.0, "일")