Files
Aislo/M01_MasterData/M01_MasterData_Equation.py
T
eomsangdonandClaude Opus 5.5 43784a4c09 wip(801-1): 수식 그 자리 고침 · 한 마디 줄 · 로직 부름 기호 · 반올림 · 안 탄 갈래 숨김 — 요구 664 로 멈춤(메인 안 합침)
- 서버: 한 마디 줄(표 찾기 · 요소 · 로직 부름 하나) = 줄 기호 · 「적용 · 값 · 기준」 칸 글 대신 조건 값 기호 · 로직 부름 기호(master_equation_sign) · 값 식 숫자 단위 · 있는 계산 변수 연결 바꿈 = 그 줄 식 · 식 속 원자 키보드 글(입력글)
- 화면: 박스 없는 조판 · 반올림 감싸개 · 안 탄 만약 숨김(감싸개 글로 구조 지킴) · 보이는 식 그 자리 고침(contenteditable · 원자 data-tok) · 값 숫자 그 자리 고침(valueEdit)
- 시험 test_801_1 7 통과 · 넓은 왕복 199 로직 중 13 걸림(식 300 자 상한 · 요소 EQ/MO 글 · 표 칸 Q 기호 맞물림) · test_796_2 옛 createFormulaCell 기대 안 고침(멈춤)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 17:50:36 +09:00

118 lines
4.8 KiB
Python

"""M01 수식 탭 서버 몫(PLAN 796-1 · 요구 655 · 657) — 수식 나무 읽기 · 고침 미리 셈 · 저장.
모델 = `scripts/master_equation.py`(나무 · 변수 표) · `master_equation_edit.py`(고침 · 검사) ·
키보드 글 번역 · 상한 = M02 단가산출 식 칸과 한 벌(`M02_Sangeun_Formula` 불러 씀 · 고치지 않음) ·
셈 = 엔진 한 벌(③ 서버 단독 · 브라우저 값 받아 적지 않음) · 저장 = 기존 M01 `/save`(개정확인) ·
M02 사본(795-1)은 `export_row` · `edit_row` 를 사본 줄로 부름 · 시험 `test_796_1_formula_model.py`.
"""
from __future__ import annotations
from typing import Any
from M01_MasterData import M01_MasterData_Store as store
from M01_MasterData import M01_MasterData_Store_Make as make
_ERR = (store.cm.mf.FormulaError, ArithmeticError, KeyError, TypeError, ValueError)
import master_equation as meq # noqa: E402 — `store` 가 scripts 를 길에 둔 뒤
import master_equation_link as link # noqa: E402
import master_equation_edit as me # noqa: E402
def _fx() -> Any:
from M02_MasterTemplete import M02_Sangeun_Formula as fx # M02 가 M01 을 부름 — 늦게
return fx
def words(text: str, row: dict) -> tuple[str, list[str]]:
"""층 번역 — 상한(길이 · 괄호) · `[노임 …]` · `[별칭]` → 엔진 식."""
fx = _fx()
if bad := fx.limits(text):
return text, bad
return fx.to_engine(text, row)
def _given(inputs: dict | None) -> dict:
return {k: store._dec(v) for k, v in (inputs or {}).items()}
def _typed(eq: dict, row: dict) -> dict:
"""줄마다 `입력글` = 키보드 한 줄 식(이름 꼴 · 변수 글) — 식 칸 처음 글."""
fx = _fx()
for line in eq.get("줄") or []:
if line.get("식"):
line["입력글"] = me.keyboard_of(fx.to_name(str(line["식"]), row), row)
_atoms(line.get("이름식"), lambda raw: me.keyboard_of(fx.to_name(raw, row), row))
return eq
def _atoms(tree, word) -> None:
"""식 속 표 찾기 · 요소 · 로직 부름 마디 `입력글` = 키보드 글(801 그 자리 고침 · 블록 속 나무 빼고)."""
if isinstance(tree, dict):
if tree.get("식") and (tree.get("꼴") == "블록" or tree.get("갈래") in ("찾기", "요소")):
tree["입력글"] = word(str(tree["식"]))
for k, v in tree.items():
if k != "나무":
_atoms(v, word)
elif isinstance(tree, list):
for v in tree:
_atoms(v, word)
def export_row(whole, row: dict, inputs: dict | None = None) -> dict:
"""로직 줄(정본 · 사본) → 수식 — 마스터에 그 줄을 얹어 셈."""
eq = meq.export(me.swap(whole, row), str(row.get("키")), _given(inputs))
return _typed(eq, row)
def edit_row(whole, row: dict, edits: list) -> tuple[dict, list[str]]:
"""고침 → (새 줄, 까닭) — 까닭 있으면 저장 안 됨(M01 · M02 사본 같은 함수)."""
new, why, _ = me.apply(whole, row, edits, words)
return new, why
def read(key: str, inputs: dict | None = None) -> dict:
whole = store.loaded()[1]
try:
return {"ok": True, "수식": export_row(whole, whole.logic(key), inputs)}
except _ERR as e:
return {"ok": False, "reason": str(e) or type(e).__name__}
def preview(key: str, edits: list, inputs: dict | None = None) -> dict:
"""고침 미리 셈(저장 없음) — {되나, 까닭, 줄, 수식, 전, 후}."""
whole = store.loaded()[1]
row = whole.logic(key)
new, why = edit_row(whole, row, edits)
if why:
return {"되나": False, "까닭": why}
try:
before = meq.export(whole, key, _given(inputs))["합계"]
eq = export_row(whole, new, inputs)
except _ERR as e:
return {"되나": False, "까닭": [f"셈 막힘 — {e}"]}
return {"되나": True, "까닭": [], "줄": new, "수식": eq, "전": before, "후": eq["합계"]}
def links(ask: dict) -> dict:
"""새 기호 연결 후보(800-3) — {갈래: 표 | 요소 | 로직, 검색, 분류?} → {후보, 더있음} · 읽기만."""
return link.candidates(store.loaded()[1], ask)
def save(
key: str, edits: list, inputs: dict | None = None, version: str = "", confirmed: bool = False
) -> dict:
"""고침 저장 — 검사 통과 · 기존 M01 `/save`(정본 = 개정확인 · 판 다르면 409)."""
got = store.logic(key)
if version and version != got["version"]:
raise store.StoreError(409, {"stale": [got["file"]]})
new, why = edit_row(store.loaded()[1], got["logic"], edits)
if why:
raise store.StoreError(400, {"까닭": why})
change = {"op": "edit", "key": key, "row": new}
part = {"file": got["file"], "version": got["version"], "changes": [change]}
out = make.save([part], confirmed)
return {**out, **read(key, inputs)}