Files
Aislo/resources/tester/test_642_1_clause_formula.py
eomsangdonandClaude Opus 5.5 c5067aa2b6 feat(809-1a): 일위대가 불러오기 = 경쟁사 로직 인정 · 요소만 연결 · [수정] 모달 = 일위대가 컨테이너 부품 · 기초 판정 걷음
- [수정] 모달 = Labor_Table(읽기 · 덧칸 표지 · 엑셀 금액) · 줄 = 로직(단가산출 · 일위대가) / 요소(연결됨 · 후보 · 못 이음) · 단가산출 줄 = 가져온 식 SK 수식 탭 모달(Labor_SkEdit) · 서버 hopyo-view(M02_Hopyo_View)
- 엑셀 보기 목록 · 칠 = 줄 표지(View.listing) · 단가산출 탭 = 블록 목록 + [가져온 식으로 열기] · [내 단가산출로]
- 걷음(요구 703): 판정 체계 785(Judge · Solve · Bind · San_Basis 다섯 · Make.Move · Row 1차 판정 · 화면 Check · CheckRows · Rows · Block · JudgeApi · Picks · Judge.css) · [우리 기초로 바꾸기](to-base) · 근거 기초 제안 · Clause 기초 판정
- 시험 지움: 642_2(Bind · Solve) · 642_3(Row 1차 판정) · 642_5(옮기기 Move) · 642_6(판정 화면) · 786_2(옛 [수정] 모달) · 793_3a(근거 → 기초 제안) — 모두 걷은 기초 판정 길 몫
- 시험 고침: 642_1 · 794_2a2 · 794_2b(근거 제안 부분만 뺌) · 793_2 · 793_3b(기초 바꾸기 기대 → 없음) · 627 · 779_2 · 785_4 · 807_1 · m02_hopyo_excel · grid · stmate(judge 길 → view 길)
- 새 시험 test_809_1_import_labor(기초 길 0 · 표지 1,350 줄 · 가져온 식 SK · 모달 = Labor_Table · 금액 = 엑셀)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 19:17:58 +09:00

120 lines
4.3 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.
"""785-1(642-1) 지킴 — 블록 글 → 절 나무 · 상수 · 대입식 · 절 몫(`M02_Hopyo_Formula`) · 북부청 견본 엑셀.
조항 색인 → 기초 후보(`Clause.basis` · `index`) 시험은 809-1 에서 지움(경쟁사 로직 인정 · 요구 703).
읽기만 · 서버 없음.
"""
from __future__ import annotations
import sys
import warnings
from functools import lru_cache
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from M02_MasterTemplete import M02_Hopyo_Excel as hx # noqa: E402
from M02_MasterTemplete import M02_Hopyo_Formula as fm # noqa: E402
warnings.filterwarnings("ignore", category=UserWarning, module="openpyxl")
XLS = (
ROOT
/ "resources/knowledge/original/실무문서/2026_실무일위대가 모음"
/ "2026년_북부지방산림청_임도사업_설계내역서(공통단가).xls"
)
@lru_cache(maxsize=1)
def blocks() -> dict[int, dict]:
if not XLS.exists():
pytest.skip("견본 엑셀 없음")
book = hx.read_book(XLS.name, XLS.read_bytes())
return {b["번"]: b for b in book["단산"]}
# ── 절 나무 ───────────────────────────────────────────────────────────
def _works(no: int) -> list[str]:
nodes = blocks()[no]["절"]
ids = {id(w) for w in fm.works(nodes)}
return [p for p, one in _paths(nodes) if id(one) in ids]
def _paths(nodes: list[dict], up: str = "") -> list[tuple[str, dict]]:
out = []
for one in nodes:
path = f"{up}.{one['번']}" if up else one["번"]
out += [(path, one), *_paths(one["아래"], path)]
return out
def test_절_나무():
assert _works(47) == ["1", "2"]
assert _works(6) == ["1.가", "1.나", "1.다", "3"]
assert [n["번"] for n in blocks()[6]["절"]] == ["1", "3", "4"] # 「2.」 빠짐 그대로
assert _works(24) == [] # 재료비 · 인건비 · 합계뿐 = 블록 통째
b = blocks()[47]
assert len(b["글행"]) == len(b["글"])
one = fm.find(b["절"], "1")
assert one["소계"] == {"노무비": 217540.1, "재료비": 19578.6, "경비": None, "계": 237118.7}
lo, hi = b["행"]
assert all(lo < r <= hi for r in one["행"])
# ── 상수 · 대입식 · 몫 ─────────────────────────────────────────────────
def _consts(no: int, path: str) -> dict[str, dict]:
return {c["기호"]: c for c in fm.find(blocks()[no]["절"], path)["상수"]}
def test_상수():
c = _consts(10, "1")
assert (c["L"]["값"], c["L"]["단위"]) == (6, "m")
assert (c["경사도"]["값"], c["경사도"]["단위"]) == (35, "°")
assert (c["n"]["값"], c["n"]["이름"]) == (42, "운반회수")
c = _consts(6, "1.나")
assert {k: c[k]["값"] for k in ("q", "K", "f", "E", "Cm")} == {
"q": 0.6,
"K": 0.55,
"f": 1,
"E": 0.35,
"Cm": 18,
}
assert (c["q"]["단위"], c["Cm"]["단위"], c["Cm"]["덧"]) == ("㎥", "sec", "90˚")
assert isinstance(c["q"]["행"], int)
def test_대입식():
p = next(f for f in fm.find(blocks()[10]["절"], "1")["식"] if f["기호"] == "P")
assert p["꼴"] == "곱" and p["값"] == 0.547619
assert [(f["수"], f["단위"]) for f in p["분자"]] == [
(1, "㎡"),
(575, "㎏/㎡"),
(1, "회"),
(1, "일"),
]
assert p["분모"] == [{"수": 25, "단위": "㎏"}, {"기호": "n", "단위": ""}]
assert p["대입"] == {"n": 42}
def test_절_몫():
nodes = blocks()[6]["절"]
share = fm.find(nodes, "1.나")["몫"]
assert share["글"] == "× 575 / 1750 × 90%"
assert share["값"] == pytest.approx(575 / 1750 * 0.9, abs=1e-6)
assert fm.find(nodes, "1.가")["몫"]["값"] == 0.1
assert fm.find(nodes, "3")["몫"]["값"] == pytest.approx(575 / 1750, abs=1e-6)
assert fm.find(blocks()[47]["절"], "1")["몫"] is None
def test_인자_괄호():
got_ = fm.factors("Cm × n / (60 × Es)")
assert [(w, f.get("기호") or f.get("수")) for w, f in got_] == [
("곱", "Cm"),
("곱", "n"),
("나눔", 60),
("나눔", "Es"),
]
assert fm.factors("t1 + t2") is None and fm.factors("1 2") is None