Files
Aislo/resources/tester/test_642_2_bind_solve.py
eomsangdonandClaude Opus 5.5 d516d09fd9 feat(785-2): Bind B2 · B3 · B4 785-1 꼴 맞춤 · Solve 풂 절 parts · 지킴 시험 test_642_2
- Bind: B2 선택값 줄 = 낱말 같음 고름(「사용횟수」 ≠ 「사용」) · B3 상수 이름 · 덧(90˚) · 단위 맞춤(sec = 초 · km → m) · 경사도 → 경사각도 · B4 식 분자 · 분모 {수|기호} + 대입
- Solve.parts: Formula.works 절 + Clause 후보 {키, 절} → 풂 절(절 표 없는 후보뿐이면 블록 통째)
- 새 test_642_2_bind_solve: 예시 1 · 2 · 3 + 단산46 · 39 입력값 · 출처 꼬리표 · 입력 필요 · 엇갈림 · 지어 넣은 값 0 · 품 같음 · defaults 규칙

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:23:07 +09:00

195 lines
7.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""642-2(PLAN 785-2) 옵션값 읽기 · 검산 · 판정 — 북부청 임도 예시 1 · 2 · 3 + 단산46 · 39 기대표
(설계 642-A 2-10 · 5-3) · 출처 꼬리표 · 지어 넣은 값 0 · 입력 필요 · 품 같음 · master_auto.defaults.
읽기만(엑셀 · M01) · storage 안 씀."""
from decimal import Decimal
from pathlib import Path
import pytest
from M02_MasterTemplete import M02_Hopyo_Bind as hb
from M02_MasterTemplete import M02_Hopyo_Excel as hx
from M02_MasterTemplete import M02_Hopyo_Solve as hs
NORTH = (
Path(__file__).resolve().parents[1]
/ "knowledge/original/실무문서/2026_실무일위대가 모음"
/ "2026년_북부지방산림청_임도사업_설계내역서(공통단가).xls"
)
PATHS = {"B1", "B2", "B3", "B4", "B5", "B6"}
# 후보 = 785-1 Clause 몫(조항 색인) — 여기선 설계 2-10 후보 열 그대로
CANDS = {
10: ["GC001140", "GC001141", "GC001142"],
24: ["GC000211"],
46: ["GC000198"],
47: [{"키": "GC000206", "절": "1"}, {"키": "GC000207", "절": "2"}],
39: ["GF000224", "GF000225"],
}
@pytest.fixture(scope="module")
def master():
return hb.m01.cm.master()
@pytest.fixture(scope="module")
def book():
return hx.read_book(NORTH.name, NORTH.read_bytes())
@pytest.fixture(scope="module")
def solved(master, book):
blocks = {b["번"]: b for b in book["단산"]}
out = {}
for no, cands in CANDS.items():
hopyo = next(
h for h in book["호표"] if any((x.get("참조") or {}).get("번") == no for x in h["줄"])
)
line = next(x for x in hopyo["줄"] if (x.get("참조") or {}).get("번") == no)
same = [x for x in hopyo["줄"] if x is not line]
blk = blocks[no]
out[no] = hs.block(master, blk, hs.parts(blk, cands), {"줄": line, "같은줄": same})
return out
def _cand(solved, no, key, sec=0):
return next(c for c in solved[no]["절"][sec]["후보"] if c["키"] == key)
def _where(cand):
return {k: v["길"] for k, v in cand["바인딩"]["출처"].items()}
def test_예시1_단산10_소운반(solved):
got = solved[10]
assert got["판정"] == "기초로 풂" and got["고를수"] == 0
assert got["절"][0]["고름"] == "GC001140"
c = _cand(solved, 10, "GC001140")
b = c["바인딩"]
assert b["입력값"] == {
"운반무게": 575,
"회당운반량": 25,
"운반거리": 6,
"경사각도": 35,
"운반회수": 42,
}
assert _where(c) == {
"운반무게": "B4",
"회당운반량": "B4",
"운반거리": "B3",
"경사각도": "B3",
"운반회수": "B3",
}
assert b["입력필요"] == [] and b["엇갈림"] == {}
assert set(b["안씀"]) == {"재료종별", "재료형상", "재료갈래", "운반로", "실작업시간"}
(row,) = c["줄"]
assert row["판정"] == "품 같음"
assert Decimal(str(row["우리"]["품"])).quantize(Decimal("0.000001")) == Decimal("0.547619")
assert round(c["금액"]["계"], 1) == 94227.7
def test_예시2_단산47_절_둘(solved):
got = solved[47]
one, two = got["절"]
assert (one["고름"], two["고름"]) == ("GC000206", "GC000207")
a = _cand(solved, 47, "GC000206", 0)["바인딩"]
assert a["입력값"] == {"Type": "Type-Ⅰ"} and a["출처"]["Type"]["길"] == "B1"
c = _cand(solved, 47, "GC000207", 1)
b = c["바인딩"]
assert b["입력값"] == {"Type": "Type-Ⅰ", "호": "Ⅰ-1", "소량감률": 50}
assert _where(c) == {"Type": "B1", "호": "B5", "소량감률": "B5"}
assert [x["값"] for x in b["엇갈림"]["구분"]] == ["토목", "건축"]
assert b["기본"]["구분"] == "토목"
assert [r["판정"] for r in c["줄"]] == ["품 같음"] * 4
assert got["판정"] == "고를 것" and got["고를수"] == 1 # 구분 하나만 사용자
def test_예시3_단산24_합판거푸집(solved, master, book):
c = _cand(solved, 24, "GC000211")
b = c["바인딩"]
assert b["입력값"] == {
"사용횟수": "4회",
"유형": "보통",
"지붕슬래브": "아님",
"폼타이": "아님",
}
assert _where(c) == {"사용횟수": "B1", "유형": "B2", "지붕슬래브": "B2", "폼타이": "B2"}
assert b["입력필요"] == ["높이감률", "구멍땜"]
assert b["기본"]["높이감률"] is None and b["기본"]["구멍땜"] is None # 규칙에 맞는 칸 없음
assert set(b["안씀"]) == {"폼타이규격", "측압"} and b["비움"] == ["자재지역"]
assert solved[24]["판정"] == "고를 것" and solved[24]["고를수"] == 2
# 사용자가 0 넣음 → 노무 줄 품 같음 · 노무비 38,291 = 엑셀
given = {**b["입력값"], "높이감률": 0, "구멍땜": 0}
items = [x for x in next(b for b in book["단산"] if b["번"] == 24)["항목"] if not x.get("밖")]
rows = hs.pair(hb.quantities(master, "GC000211", given), items)
assert {r["판정"] for r in rows if r["엑셀"]} == {"품 같음"}
fill = {n: b["기본"][n] for n in b["안씀"]} | {"자재지역": None}
money = hb.mf.run(master, "GC000211", {**fill, **given})
assert round(money["노무비"]) == 38291
def test_단산46_레미콘타설(solved):
got = solved[46]
c = _cand(solved, 46, "GC000198")
b = c["바인딩"]
assert b["입력값"] == {"타설방법": "장비사용타설", "구조물": "철근구조물", "소량감률": 50}
assert _where(c) == {"타설방법": "B1", "구조물": "B1", "소량감률": "B5"}
assert b["입력필요"] == ["굴착기"] and b["비움"] == ["지역"] # 굴착기 규격 = B3 · 사용자
mach = next(r for r in c["줄"] if r["엑셀"] and r["엑셀"]["묶음"] == "X")
assert mach["판정"] == "품 같음" and mach["표지"] == "기계 갈래 엇갈림"
assert [d["이름"] for d in got["덧"]] == ["레미콘"] # 별도계상 = 덧 줄
def test_단산39_찰붙임(solved):
sec = solved[39]["절"][0]
assert sec["고름"] == "GF000225" and solved[39]["판정"] == "기초로 풂"
c = _cand(solved, 39, "GF000225")
assert c["바인딩"]["입력값"] == {
"뒷길이": 35,
"굵은골재최대치수": 25,
"강도": 21,
"슬럼프": "120",
"채움콘크리트량": 0.12,
"보정작업": "해당 없음",
}
assert _where(c)["뒷길이"] == "B1" and _where(c)["채움콘크리트량"] == "B6"
assert _cand(solved, 39, "GF000224")["판정"] == "품 다름"
def test_지어_넣은_값_없음(solved):
for got in solved.values():
for sec in got["절"]:
for c in sec["후보"]:
b = c["바인딩"]
assert set(b["입력값"]) == set(b["출처"]) # 출처 없는 값 0
assert {v["길"] for v in b["출처"].values()} <= PATHS
@pytest.mark.parametrize(
"excel, ours, want",
[
(0.67, 0.6667, True),
(1.18, 1.1765, True),
(3.53, 3.5294, True),
(0.1111111111, 0.11111, True),
(0.67, 0.69, False),
(0.547619, 0.5476190476, True),
(None, 1, False),
],
)
def test_품_같음(excel, ours, want):
assert hs.same(excel, ours) is want
def test_defaults_규칙(master):
ma = hb.ma
jige = ma.defaults(master, master.logic("GC001140"))
assert jige["실작업시간"] == 0 and jige["운반무게"] == 0 # 가드
assert jige["경사각도"] == 0 and jige["운반거리"] is None # 고르기 첫째 · 못 정함
pour = ma.defaults(master, master.logic("GC000198"))
assert pour["소량감률"] == 0 and pour["타설방법"] == "인력운반타설" # 0 을 품은 범위
form = ma.defaults(master, master.logic("GC000211"))
assert form["높이감률"] is None and form["구멍땜"] is None
assert 1 not in [v for v in jige.values() if not isinstance(v, str)] # 지어 넣는 1 없음