feat(M01): 흐름 로직 줄 = 옛 식 칸(입력 · 중간 · 호표 · 결과 · 덧줄) 지움 · 읽는 곳은 흐름의 설계 때 정할 것 · 출력에서(사용자 결정)
- master_formula.inputs_of · FLOW_INPUTS · OLD_FIELDS · mf.run 이 흐름 줄이면 스스로 서버 갈래를 깖(스크립트 · 시험도) - check_master 틀 검사 · 시험입력 · 로직(…) 입력 검사 · master_auto 자동값 · 프로젝트 빈 입력 · 연결 · 다시 적용 값이 흐름 입력으로 - 프로젝트 단가 묶음(collect)이 흐름의 요소 · 표 · 다른 로직 · 기계 시간당 경비 로직을 모음 - 옛 엔진 갈래 결과 = 옛 꼴(돈 출력 줄 · 값들 · 알림) · 조합 · 프로젝트에서 안 준 입력은 빈 입력 알림(예시값 아님) - /text 흐름 로직 = 출력 상자 줄 · GET /logic 은 보기용으로 설계 때 정할 것을 입력 꼴로 얹음(파일은 그대로) - 찾을 값이 빈 조건 찾기는 그 값만 비움(옛 셈처럼) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
This commit is contained in:
@@ -167,8 +167,10 @@ def _value(v: Any, words: set | frozenset = frozenset()) -> Any:
|
||||
return store._dec(v)
|
||||
|
||||
|
||||
def run(flow: dict, key: str, inputs: dict) -> dict:
|
||||
"""흐름 셈 — 입력 = 「설계 때 정할 것」 이름 → 값."""
|
||||
def run(flow: dict, key: str, inputs: dict, strict: bool = False) -> dict:
|
||||
"""흐름 셈 — 입력 = 「설계 때 정할 것」 이름 → 값 · strict(조합 · 프로젝트) = 안 준 입력은
|
||||
예시값
|
||||
대신 빈 값 + 알림 「빈 입력」(옛 엔진처럼 그 값을 쓰는 곳만 비움)."""
|
||||
active = _ACTIVE.get()
|
||||
if key and key in active: # 옛 셈을 건너 다시 돌아온 흐름(흐름 → 옛 로직 → 흐름)
|
||||
raise store.cm.mf.FormulaError(f"로직이 서로를 부름 — {' → '.join([*active, key])}")
|
||||
@@ -183,7 +185,12 @@ def run(flow: dict, key: str, inputs: dict) -> dict:
|
||||
given = {k: _value(v, words) for k, v in (inputs or {}).items()}
|
||||
flow = {**flow, "key": key}
|
||||
values = dc._design_values(flow, given)
|
||||
return dc.run(flow, values, load, flow.get("userElements") or [], [key])
|
||||
blank = [d for d in dc.design_inputs(flow) if strict and given.get(d["port"]) is None]
|
||||
for d in blank:
|
||||
values.setdefault(d["box"], {})[d["port"]] = None
|
||||
got = dc.run(flow, values, load, flow.get("userElements") or [], [key])
|
||||
got["notes"] = [*(f"입력 「{d['port']}」 빈 입력" for d in blank), *got.get("notes", [])]
|
||||
return got
|
||||
finally:
|
||||
_ACTIVE.reset(token)
|
||||
|
||||
@@ -195,20 +202,65 @@ def _engine(master, ref: str, row: dict, given: dict) -> dict:
|
||||
"""
|
||||
token = dv.SOURCE.set(master)
|
||||
try:
|
||||
got = run(row[FLOW], ref, given)
|
||||
got = run(row[FLOW], ref, given, strict=True)
|
||||
finally:
|
||||
dv.SOURCE.reset(token)
|
||||
if got["errors"]:
|
||||
raise store.cm.mf.FormulaError(f"「{ref}」 흐름 셈 — {' · '.join(got['errors'])}")
|
||||
cost = got["cost"]
|
||||
kinds = {(b.get("output") or {}).get("cost") for b in row[FLOW].get("boxes") or []
|
||||
if b.get("kind") == "output"} # fmt: skip
|
||||
if kinds and kinds <= {"값"} and len(cost["값들"]) == 1: # 돈 아닌 로직 = 결과 하나
|
||||
return {"결과": next(iter(cost["값들"].values())), "중간": {}}
|
||||
return {"줄": [], **{k: cost[k] for k in dc.COSTS}, "계": cost["계"], "중간": {}}
|
||||
cost, notes = got["cost"], got.get("notes") or []
|
||||
outs = [b for b in row[FLOW].get("boxes") or [] if b.get("kind") == "output"]
|
||||
extra = {"중간": {}, "값들": cost["값들"], **({"알림": notes} if notes else {})}
|
||||
if outs and all((b.get("output") or {}).get("cost") in (None, "값") for b in outs):
|
||||
first = got["outputs"].get(outs[0]["id"]) # 돈 아닌 로직 = 첫 출력이 결과 · 나머지는 값들
|
||||
return {"결과": first, **extra}
|
||||
lines = [] # 옛 「줄」 꼴 — 돈 출력 상자마다 한 줄(수량 1 · 단가 = 금액)
|
||||
for b in outs:
|
||||
kind, value = (b.get("output") or {}).get("cost"), got["outputs"].get(b["id"])
|
||||
if kind in dc.COSTS:
|
||||
unit = (b.get("output") or {}).get("unit") or ""
|
||||
lines.append({"이름": b.get("name") or "", "단위": unit,
|
||||
"수량": Decimal(1), "단가": value, "금액": value, "비목": {kind: value},
|
||||
**({} if value is not None else {"까닭": "값 없음"})}) # fmt: skip
|
||||
sums = {k: cost[k] for k in dc.COSTS}
|
||||
return {"줄": lines, **sums, "계": cost["계"], **extra}
|
||||
|
||||
|
||||
def _inputs(row: dict) -> list[dict]:
|
||||
"""흐름 로직 입력 = 「설계 때 정할 것」 → 옛 입력 꼴(이름 · 단위 · 고르기 · 범위 · 예시)."""
|
||||
out = []
|
||||
for d in dc.design_inputs(row[FLOW]):
|
||||
v = d.get("variable") or {}
|
||||
one = {"이름": d["port"], "단위": None if d.get("unit") in (None, "-") else d["unit"]}
|
||||
one |= {"고르기": v["choices"]} if v.get("choices") else {}
|
||||
one |= {"범위": v["range"]} if v.get("range") else {}
|
||||
out.append(one | {"예시": v.get("example")})
|
||||
return out
|
||||
|
||||
|
||||
store.cm.mf.FLOW_RUN = _engine # 옛 엔진을 부르는 곳이 모두 흐름 로직을 흐름 셈으로(한 곳 갈래)
|
||||
store.cm.mf.FLOW_INPUTS = (
|
||||
_inputs # 입력을 읽는 곳(시험입력 · 자동값 · 프로젝트 입력 · 연결)도 흐름에서
|
||||
)
|
||||
|
||||
|
||||
def text(key: str, inputs: dict, row: dict | None = None) -> dict | None:
|
||||
"""읽는 식 줄(`/text` 꼴) — 흐름 로직이면 출력 상자를 비목 묶음 줄로 · 아니면 None(옛 글)."""
|
||||
got = calc(key, inputs, row)
|
||||
if got is None or not got.get("flow") or "outputs" not in got:
|
||||
return got
|
||||
groups: dict[str, list] = {}
|
||||
for o in got["outputs"]:
|
||||
value = o["value"]
|
||||
shown = f"{value:,}" if isinstance(value, (int, Decimal)) else str(value)
|
||||
line = {"이름": o["name"], "글": shown, "이름글": o["name"], "금액": value, "조각": []}
|
||||
groups.setdefault(o["cost"] or "값", []).append(line)
|
||||
out = [{"비목": k, "줄": v} for k, v in groups.items()]
|
||||
return {
|
||||
"ok": got["ok"],
|
||||
"flow": True,
|
||||
"groups": out,
|
||||
**({"reason": got["reason"]} if "reason" in got else {}),
|
||||
}
|
||||
|
||||
|
||||
def auto(key: str) -> dict | None:
|
||||
@@ -294,9 +346,10 @@ def _redo(row: dict, key: str) -> list[str]:
|
||||
|
||||
|
||||
def _bare(row: dict) -> dict:
|
||||
"""새 흐름 로직 — 옛 식 칸은 빈 것으로(파일 틀 검사) · 출처 없으면 「자체」."""
|
||||
old = {"입력": [], "중간": [], "호표": [], "끝수": None}
|
||||
return {**old, **row, "출처": row.get("출처") or "자체"}
|
||||
"""흐름 로직 줄 — 옛 식 칸(입력 · 중간 · 호표 · 결과 · 덧줄)은 지움(흐름이 정본)
|
||||
· 끝수 · 시험입력 · 메타 칸은 둠 · 출처 없으면 「자체」."""
|
||||
kept = {k: v for k, v in row.items() if k not in store.cm.mf.OLD_FIELDS}
|
||||
return {"끝수": None, **kept, "출처": row.get("출처") or "자체"}
|
||||
|
||||
|
||||
def save(batch: list[dict]) -> dict:
|
||||
@@ -313,6 +366,7 @@ def save(batch: list[dict]) -> dict:
|
||||
raise store.StoreError(400, f"새 흐름 로직은 「{make.OWN}」 에만 더함")
|
||||
row = make._clean(_bare(row), str(row.get("소유") or make.OWNERS[0]))
|
||||
ch.update(op="add", key=None)
|
||||
row = _bare(row) if not new else row
|
||||
ch["row"] = row
|
||||
name = row.get("이름") or ch.get("key") or "새 로직"
|
||||
warns += [f"「{name}」 {w}" for w in _redo(row, str(ch.get("key") or ""))]
|
||||
|
||||
Reference in New Issue
Block a user