- M01 캐시 `steady()` 범위 — 요청 한 번 안 파일 자국 한 번(77 번 × 19 ms → 1 번) · stale · forget 뒤 다시 · 범위 밖 그대로 - 두 번 셈(183-1) 2차 산근 = 1차가 본 단가(있음 · 값)가 같을 때만 1차 풀이 사본 · 다르면 다시 셈 - [저장] 단가 수요 한 번(셈 답에 넘김) · 단계 표시 = 셈과 함께 - B08 `once()` 범위 — B09 원천 읽기 때 토공 채집석 공제가 자재 집계표 답을 다시 씀(두 번 셈 → 한 번) - 시험: test_b09_save_speed 새로 · test_183 바꿔 끼운 셈 함수 = 새 memo 인자 받음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
3.3 KiB
Python
92 lines
3.3 KiB
Python
"""B09 [저장] 속도 — 같은 결과 범위 안 다시 셈 줄임 지킴.
|
|
|
|
- 산근 두 번 셈(183-1) = 1차가 본 단가(있음 · 값)가 같을 때만 1차 풀이 그대로(`_Prices.same`)
|
|
- M01 `steady()` 범위 = 파일 자국 한 번 · `stale` 뒤 다시 셈 · 범위 밖은 늘 셈
|
|
- B08 `once()` 범위 = 채집석 공제가 자재 집계표 답을 다시 씀(셈 한 번)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B08_Quantity import B08_Quantity_Router_Material as material # noqa: E402
|
|
from B09_Estimation.B09_Estimation_Sangeun import _Prices # noqa: E402
|
|
from M01_MasterData import M01_MasterData_Store_Cache as cache # noqa: E402
|
|
|
|
SHEETS = {
|
|
"labor": [{"key": "L1", "price": 100}, {"key": "L2", "price": 5}],
|
|
"compare": [{"key": "M1", "applied": 3}],
|
|
"machine": [{"key": "E1", "labor": 1, "material": 2, "expense": 3}],
|
|
}
|
|
|
|
|
|
def _seen() -> _Prices:
|
|
got = _Prices(SHEETS)
|
|
got.labor.get("L1")
|
|
assert "M9" not in got.material
|
|
got.machine.get("E1")
|
|
return got
|
|
|
|
|
|
def test_산근_같은_단가면_다시_씀() -> None:
|
|
other = {**SHEETS, "labor": [{"key": "L1", "price": 100}, {"key": "L2", "price": 999}]}
|
|
assert _seen().same(_Prices({**other, "compare": []})) # 안 본 L2 · M1 은 안 셈
|
|
|
|
|
|
def test_산근_본_단가_바뀌면_다시_셈() -> None:
|
|
assert not _seen().same(_Prices({**SHEETS, "labor": [{"key": "L1", "price": 101}]}))
|
|
added = {**SHEETS, "compare": [{"key": "M9", "applied": 1}]}
|
|
assert not _seen().same(_Prices(added)) # 없던 자재가 생김
|
|
machine = {**SHEETS, "machine": [{"key": "E1", "labor": 1, "material": 2, "expense": 4}]}
|
|
assert not _seen().same(_Prices(machine))
|
|
|
|
|
|
def test_M01_범위_안_자국_한_번(monkeypatch) -> None:
|
|
calls = []
|
|
monkeypatch.setattr(cache, "_stamps", lambda folder: calls.append(folder) or {})
|
|
folder = Path("x")
|
|
cache._now(folder)
|
|
cache._now(folder)
|
|
assert len(calls) == 2 # 범위 밖 = 늘 셈
|
|
with cache.steady():
|
|
cache._now(folder)
|
|
cache._now(folder)
|
|
assert len(calls) == 3
|
|
cache.stale([]) # 스스로 고친 자리 = 다시 셈
|
|
cache._now(folder)
|
|
assert len(calls) == 4
|
|
cache._now(folder)
|
|
assert len(calls) == 5
|
|
|
|
|
|
def test_B08_범위_안_자재_집계표_한_번(monkeypatch, tmp_path) -> None:
|
|
calls = []
|
|
rows = [{"key": material.DEDUCT_KEY, "amount": 12.5}]
|
|
|
|
async def sheets(_pid, _root, _over):
|
|
calls.append(1)
|
|
return {"sheets": {"material": {"rows": rows}}}
|
|
|
|
async def root(_pid):
|
|
return tmp_path
|
|
|
|
monkeypatch.setattr(material, "_sheets", sheets)
|
|
monkeypatch.setattr(material, "_project_root", root)
|
|
monkeypatch.setattr(material, "quantity_settings", lambda _root: {})
|
|
|
|
async def run() -> list:
|
|
out = [await material.picked_deduction("p", tmp_path)]
|
|
with material.once():
|
|
await material.material_sheets("p")
|
|
out.append(await material.picked_deduction("p", tmp_path))
|
|
out.append(await material.picked_deduction("p", tmp_path))
|
|
return out
|
|
|
|
assert asyncio.run(run()) == [12.5, 12.5, 12.5]
|
|
assert len(calls) == 3 # 범위 안 공제 = 셈 없음
|