feat(781-1 · 781-2): 출처 책 · 부문 · 옛 책 가림 · 「근거 조항 우리 기초에 없음」 표지(요구 628 · 629 · 630)
- 책 낱말 표(ReadEst.book_of) — 임도 · 사방 = 옛 책 「(옛)」 · 공통 · 토목 · 건축 · 기계설비 · 유지관리 = 「건설품셈 <부문>」 · 그 밖 건설품셈(부문 모름) 그대로 - 출처 풀이(Basis.settle · Excel.read_book 끝 한 곳 · 두 형식) — 건설품셈(부문 모름) 번호 → 블록 이름(안 맞으면 글 두 묶음)이 원문 제목 · 같은 번호 로직 이름과 뜻 낱말을 나누는 부문 하나 = 그 부문 · 둘 이상 = 모름 · 없음 = (옛) · 임도 옛 번호 → 지식DB 대응표 확정 한 대응(가 · 나 항 = 현행 윗마디 · 일대다 안 옮김) - 조항 견줌(Basis.clause) 한 줄 — 책 또는 구분 같음 · (옛) = 없음 - 기초 없음 표지(Basis.no_basis) — 출처 조항(윗 · 아랫마디 포함) 로직 0 = 「근거 조항 우리 기초에 없음 — 건설품셈 공통 1-2-7 운반」 · 옛 번호 = 「옛 번호 — 대응 미확인」 · 맞춤셈 꼬리표 · 맞음 아닌 후보 글 「참고 후보 — 근거 조항 아님」 · 단가산출 근거 꼬리표 1위 대신 표지(1위 맞음이면 1위) - 시험: 새 test_628 · test_621 단계 해시 다시 굳힘(달라진 칸 = 출처뿐 · S1 수 · 그래프 그대로) · test_m02_hopyo_basis · finger · stmate · excel 출처 기대값 새 책 꼴로(낡은 기대 「임도 = 산림품셈」 · 「건설품셈」 부문 없음) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,11 @@
|
||||
|
||||
읽기(`read` · `sources` · `trade_names` · `SHEET` · `GLINES` · `GCHARS`) = EST 어댑터
|
||||
`M02_Hopyo_ReadEst`(776-2 · 이름은 그대로 다시 냄).
|
||||
견줌(`candidates`) = 같은 책 조항 같음 1.0 · 윗마디 0.9(엑셀 6-2 ⊃ 우리 6-2-2) ·
|
||||
출처 풀이(`settle` · 781-1) = 건설품셈(부문 모름) 번호 → 뜻 낱말로 부문 ·
|
||||
임도품셈(옛) → 대응표 현행 산림 번호 ·
|
||||
기초 없음 표지(`no_basis` · 781-2) = 출처 조항에 우리 로직 0 · 옛 번호.
|
||||
견줌(`candidates`) = 같은 책(부문을 알면 같은 구분) 조항 같음 1.0 ·
|
||||
윗마디 0.9(엑셀 6-2 ⊃ 우리 6-2-2) ·
|
||||
앞 마디 같음 0.5(조항이 안 맞으면 후보 아님 · `clause`) · 조항 오타 「13-114」 = 「13-11-4」 ·
|
||||
건설 공통 · 토목 덤 0.1 · 직종 겹침(보통인부 뺌) 0.5 · 단위 0.15 · 직종도 뜻 낱말도 안 겹치면 버림 ·
|
||||
같은 점수는 글자 두 개 묶음(괄호 글 포함)이 가름 · 이름 · 낱말(괄호 글 포함 · 인력 · 기계 뺌)이
|
||||
@@ -15,11 +19,13 @@ M01 · 원본 로직은 읽기만.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import re
|
||||
from functools import lru_cache
|
||||
from typing import Any
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
from M01_MasterData import M01_MasterData_Store_Make as make
|
||||
from M02_MasterTemplete import M02_Hopyo_Match as hopyo_match # 서로 부름 — 부를 때만 씀
|
||||
from M02_MasterTemplete import M02_Labor_Inputs as labor_inputs
|
||||
from M02_MasterTemplete.M02_Hopyo_ReadEst import ( # noqa: F401 — 읽기는 EST 어댑터(776-2) · 옛 이름 그대로
|
||||
@@ -81,8 +87,9 @@ def _head(number: str) -> str:
|
||||
|
||||
def clause(theirs: list[list[str]], our: dict[str, Any]) -> tuple[float, list[str], str]:
|
||||
"""엑셀 인용 조항 `[[책, 번호]]` ↔ 우리 로직(`ours()` 한 줄) → (점수, 맞은 우리 조항 글,
|
||||
꼬리표) — 같은 책만 · 같음 1 · 윗마디 0.9(엑셀 6-2 ⊃ 우리 6-2-2) · 앞 마디 0.5."""
|
||||
nums = [n for book, n in theirs if book == our["책"]]
|
||||
꼬리표) — 같은 책(부문을 알면 같은 구분 · 「(옛)」 = 없음) · 같음 1 ·
|
||||
윗마디 0.9(엑셀 6-2 ⊃ 우리 6-2-2) · 앞 마디 0.5."""
|
||||
nums = [n for book, n in theirs if book in (our["책"], our["구분"])]
|
||||
same = sorted(n for n in nums if n in our["조항"])
|
||||
if same:
|
||||
return 1.0, [f"{our['구분']} {n}" for n in same], "조항 같음"
|
||||
@@ -96,6 +103,148 @@ def clause(theirs: list[list[str]], our: dict[str, Any]) -> tuple[float, list[st
|
||||
return 0.0, [], ""
|
||||
|
||||
|
||||
# ── 출처 풀이(781-1 · 781-2) — 건설 부문 · 임도 옛 번호 대응 · 기초 없음 ───────────
|
||||
OLD = "(옛)"
|
||||
_ROAD = "임도품셈" + OLD
|
||||
_ROAD_MAP = make.BODY.parent / "경쟁사 프로그램/STmate 분석/30_원자료/임도품셈_판_대응표.csv"
|
||||
_OLD_NO = re.compile(r"^(\d+(?:-\d+)+)(\s+[가-하])?$")
|
||||
_STOP_GRAMS = frozenset("설치 해체 작업 인력 기계 장비 보완 신설 공사".split())
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def road_map() -> dict[str, str]:
|
||||
"""임도품셈(옛) 번호 → 현행 산림 번호 — 지식DB 대응표 「확정」 한 대응만(일대다 · 미확인 뺌) ·
|
||||
옛 번호가 가 · 나 항이면 현행 윗마디(9-13-7 → 9-13 · 그 항만 대응하므로)."""
|
||||
with open(_ROAD_MAP, encoding="utf-8-sig", newline="") as f:
|
||||
rows = list(csv.DictReader(f))
|
||||
out = {}
|
||||
for row in rows:
|
||||
old, new = _OLD_NO.match(row["과거_절"].strip()), row["현행_절"].strip()
|
||||
if row["판정"] != "확정" or not old or not _OLD_NO.fullmatch(new) or " " in new:
|
||||
continue
|
||||
out[old.group(1)] = new.rsplit("-", 1)[0] if old.group(2) and new.count("-") > 1 else new
|
||||
return out
|
||||
|
||||
|
||||
def _grams(text: Any) -> set[str]:
|
||||
"""뜻 낱말 — 낱말 안 한글 두 글자 묶음(괄호 글 포함 · 굴삭 = 굴착)."""
|
||||
words = re.findall(r"[가-힣]+", str(text or "").replace("굴삭", "굴착"))
|
||||
return {w[i : i + 2] for w in words for i in range(len(w) - 1)} - _STOP_GRAMS
|
||||
|
||||
|
||||
@lru_cache(maxsize=2)
|
||||
def _sections(book: str) -> dict[tuple[str, str], str]:
|
||||
"""{(부문, 절 번호): 제목(괄호 글 · 「:」 뒤 뺌)} — 원문 본문."""
|
||||
return {
|
||||
(s["division"], s["section"]): re.sub(r"\(.*?\)", "", s["title"]).split(":")[0].strip()
|
||||
for s in make._all_sections(book)
|
||||
}
|
||||
|
||||
|
||||
@lru_cache(maxsize=2)
|
||||
def _named(whole_id: int) -> dict[tuple[str, str], list[str]]:
|
||||
"""{(구분, 원문번호): [로직 이름]} — M01 로직."""
|
||||
out: dict[tuple[str, str], list[str]] = {}
|
||||
for data in m01.loaded()[0].values():
|
||||
if data.get("그룹") == "로직":
|
||||
for row in data.get("줄") or []:
|
||||
key = (str(row.get("구분") or ""), str(row.get("원문번호") or "").split(" ")[0])
|
||||
out.setdefault(key, []).append(str(row.get("이름") or ""))
|
||||
return out
|
||||
|
||||
|
||||
def _part(number: str, name: Any, text: Any = "") -> str:
|
||||
"""건설품셈(부문 모름) 번호 → 원문에 그 번호가 있는 부문 중 블록 이름(안 맞으면 블록 글 ·
|
||||
두 묶음)이 원문 제목 · 같은 번호 로직 이름과 뜻 낱말을 나누는 부문이 하나 = 그 부문 ·
|
||||
둘 이상 = 모름 · 없음 = 「(옛)」(번호 뜻 안 맞음)."""
|
||||
if not _grams(name):
|
||||
return "건설품셈"
|
||||
named = _named(id(m01.loaded()[1]))
|
||||
texts = {
|
||||
part: [title, *named.get((f"건설품셈 {part}", no), [])]
|
||||
for (part, no), title in _sections("건설품셈").items()
|
||||
if no == number
|
||||
}
|
||||
hits = []
|
||||
for mine, least in ((_grams(name), 1), (_grams(text), 2)): # 글은 두 묶음 이상
|
||||
hits = [p for p, ts in texts.items() if any(len(mine & _grams(t)) >= least for t in ts)]
|
||||
if hits:
|
||||
break
|
||||
if len(hits) == 1:
|
||||
return f"건설품셈 {hits[0]}"
|
||||
return "건설품셈" if hits else "건설품셈" + OLD
|
||||
|
||||
|
||||
def resolve(theirs: list[list[str]], name: Any, text: Any = "") -> list[list[str]]:
|
||||
"""블록 출처 → 부문 풀이 · 임도 옛 번호 대응(`road_map`) 뒤 출처."""
|
||||
out: list[list[str]] = []
|
||||
for book, number in theirs:
|
||||
one = [book, number]
|
||||
if book == _ROAD and number in road_map():
|
||||
one = ["산림품셈", road_map()[number]]
|
||||
elif book == "건설품셈":
|
||||
one = [_part(number, name, text), number]
|
||||
if one not in out:
|
||||
out.append(one)
|
||||
return out
|
||||
|
||||
|
||||
def settle(book: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Book 단산 블록 출처를 제자리에서 풀이(줄 `근거.출처` 가 같은 리스트를 가리킴)."""
|
||||
for block in book.get("단산") or []:
|
||||
if block.get("출처"):
|
||||
text = " ".join(str(t) for t in block.get("글") or [])
|
||||
block["출처"][:] = resolve(block["출처"], block.get("이름"), text)
|
||||
return book
|
||||
|
||||
|
||||
def has_logic(kind: str, number: str) -> bool:
|
||||
"""그 구분 · 조항(윗마디 · 아랫마디 포함)에 M01 로직이 있나."""
|
||||
return _has(id(m01.loaded()[1]), kind, number)
|
||||
|
||||
|
||||
@lru_cache(maxsize=512)
|
||||
def _has(whole_id: int, kind: str, number: str) -> bool:
|
||||
named = _named(whole_id)
|
||||
parts = number.split("-")
|
||||
ups = {"-".join(parts[:i]) for i in range(2, len(parts) + 1)}
|
||||
return any(k == kind and (no in ups or no.startswith(number + "-")) for k, no in named)
|
||||
|
||||
|
||||
def no_basis(theirs: list | None) -> dict[str, str] | None:
|
||||
"""출처 조항이 모두 우리 기초 밖이면 표지 `{판정, 글, 이름}` — 기초 없음(로직 0) › 옛 번호
|
||||
(「(옛)」 · 지금 원문에 없는 번호) · 로직 있는 조항 · 건설품셈(부문 모름)이 하나라도
|
||||
있으면 None."""
|
||||
none, old = [], []
|
||||
for book, number in theirs or []:
|
||||
base, _, part = book.partition(" ")
|
||||
if book == "건설품셈":
|
||||
return None
|
||||
if book.endswith(OLD) or base not in make.BOOKS:
|
||||
old.append((book.removesuffix(OLD), number))
|
||||
elif has_logic(book, number):
|
||||
return None
|
||||
elif (title := _sections(base).get((part, number))) is None:
|
||||
old.append((book, number))
|
||||
else:
|
||||
none.append((book, number, title))
|
||||
if none:
|
||||
book, number, title = none[0]
|
||||
where = f"{book.replace('품셈', '')} {number} {title}"
|
||||
return {
|
||||
"판정": "기초 없음",
|
||||
"글": f"근거 조항 우리 기초에 없음 — {book} {number} {title}",
|
||||
"이름": f"기초 없음 — {where}",
|
||||
}
|
||||
if old:
|
||||
return {
|
||||
"판정": "옛 번호",
|
||||
"글": f"옛 번호 — 대응 미확인 — {old[0][0]} {old[0][1]}",
|
||||
"이름": "옛 번호 — 근거 못 씀",
|
||||
}
|
||||
return None
|
||||
|
||||
|
||||
def _text(line: dict[str, Any]) -> str:
|
||||
text = f"{line.get('이름') or ''} {line.get('규격') or ''}"
|
||||
for old, new in _TYPOS:
|
||||
|
||||
@@ -30,6 +30,7 @@ import re
|
||||
from decimal import ROUND_FLOOR, Decimal, InvalidOperation
|
||||
from typing import Any
|
||||
|
||||
from M02_MasterTemplete import M02_Hopyo_Basis as source_basis # 출처 풀이(781-1)
|
||||
from M02_MasterTemplete import M02_Hopyo_ReadEst as hopyo_basis # EST 단가산출 어댑터(776-2)
|
||||
from M02_MasterTemplete import M02_Hopyo_Stmate as hopyo_stmate
|
||||
from M02_MasterTemplete import M02_Hopyo_UnitLine as unit_line
|
||||
@@ -302,7 +303,7 @@ def read_book(name: str, data: bytes) -> dict[str, Any]:
|
||||
sheets, xls = _open(name, data, LISTS)
|
||||
_OPENED = (data, sheets, xls) # 격자(`Grid.read`)가 이어 씀 — 한 번 열기
|
||||
if hopyo_stmate.is_stmate(sheets):
|
||||
return unit_line.settle(hopyo_stmate.read(sheets))
|
||||
return unit_line.settle(source_basis.settle(hopyo_stmate.read(sheets)))
|
||||
rows = sheets.get(SHEET)
|
||||
if rows is None:
|
||||
raise ExcelError(NO_SHEET)
|
||||
@@ -374,7 +375,9 @@ def read_book(name: str, data: bytes) -> dict[str, Any]:
|
||||
"단산": basis,
|
||||
"검산": {"어긋남": wrong, "총괄표": len(totals)},
|
||||
}
|
||||
return unit_line.settle(book) # 단위 줄 하위 · 재현 · 덮음 · 일위대가 줄 투영(778-3)
|
||||
return unit_line.settle(
|
||||
source_basis.settle(book)
|
||||
) # 출처 풀이(781-1) · 단위 줄 하위 · 재현 · 덮음 · 일위대가 줄 투영(778-3)
|
||||
|
||||
|
||||
def _json(value: Any) -> Any:
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
형식(EST 글)을 아는 곳은 여기까지.
|
||||
|
||||
블록 = B열(머리 「산출근거」) 머리 줄 「N.이름[단위]」(앞 빈칸 없음)부터 다음 머리 앞까지 ·
|
||||
출처 = 「…품셈」(오타 「품줌」) 뒤 20 글자 안 절 번호 — 앞 글에 산림 · 임도 = 산림품셈 ·
|
||||
그 밖 = 건설품셈 ·
|
||||
출처 = 「…품셈」(오타 「품줌」) 뒤 20 글자 안 절 번호 — 책 = 앞 낱말(`book_of` · 781-1: 산림 ·
|
||||
임도(옛) · 사방(옛) · 건설 부문 · 그 밖 건설품셈(부문 모름)) ·
|
||||
부문 풀이 · 옛 번호 대응 = `M02_Hopyo_Basis.settle` ·
|
||||
직종 = 「이름 : 수」 줄의 빈칸 뺀 이름이 우리 인력(LB) 이름 · 옛이름일 때만(지금 이름으로) ·
|
||||
글 = 머리 뺀 몸 줄 `GLINES` 줄 · 줄마다 `GCHARS` 자 안 · 산출근거 열이 빈 줄은 그 오른쪽 ~ 돈 머리
|
||||
(맨 오른쪽 묶음) 앞 칸을 빈칸으로 이어 붙임(거창 꼴 · 돈 머리 없으면 `WIDE` 열) ·
|
||||
@@ -36,6 +37,13 @@ GLINES, GCHARS, WIDE = 200, 300, 140
|
||||
_HEAD = re.compile(r"^(\d+)\.\s*(.*?)\s*\[([^\[\]]*)\]\s*$")
|
||||
_BOOK = re.compile(r"품[셈줌]")
|
||||
_TRADE = re.compile(r"^[\s*·\-]*([가-힣][가-힣\s]*?)\s*:\s*[\d,]")
|
||||
_BOOK_WORDS = { # 책 낱말(781-1) — 옛 책 = 「(옛)」 · 건설 부문 낱말 = 「건설품셈 <부문>」
|
||||
"산림": "산림품셈",
|
||||
"임도": "임도품셈(옛)",
|
||||
"사방": "사방품셈(옛)",
|
||||
**{p: f"건설품셈 {p}" for p in ("공통", "토목", "건축", "기계설비", "유지관리")},
|
||||
}
|
||||
_BOOK_WORD = re.compile(r"(" + "|".join(_BOOK_WORDS) + r")\s*(?:부문|사업|공사)?\s*(?:표준)?\s*$")
|
||||
_TYPO_CLAUSE = re.compile(r"^(\d+)-(\d)(\d)(\d)$") # 「13-114」 = 13-11-4
|
||||
_MONEY = {"합계": "계", "노무비": "노무비", "재료비": "재료비", "경비": "경비"}
|
||||
# 항목 풀이 — 지문(`Finger`)과 같은 규칙
|
||||
@@ -108,15 +116,26 @@ def trade(name: Any) -> str | None:
|
||||
return names.get(flat) or names.get(re.sub(r"\(.*?\)", "", flat))
|
||||
|
||||
|
||||
def book_of(before: str) -> str:
|
||||
"""「…품셈」 앞 글 → 책(781-1) — 바로 앞 낱말 먼저 · 없으면 앞 12 자에 산림 · 임도 ·
|
||||
그 밖 = 건설품셈(부문 모름)."""
|
||||
hit = _BOOK_WORD.search(before)
|
||||
if hit:
|
||||
return _BOOK_WORDS[hit.group(1)]
|
||||
if "산림" in before:
|
||||
return "산림품셈"
|
||||
return _BOOK_WORDS["임도"] if "임도" in before else "건설품셈"
|
||||
|
||||
|
||||
def sources(text: str) -> list[list[str]]:
|
||||
"""글 → [[책, 절 번호]] — 「건설공사표준품셈 3-2-1」 · 「산림사업표준품셈(9-14)」."""
|
||||
"""글 → [[책, 절 번호]] — 「건설공사표준품셈 3-2-1」 · 「산림사업표준품셈(9-14)」 ·
|
||||
책 = `book_of`."""
|
||||
out = []
|
||||
for hit in _BOOK.finditer(text):
|
||||
num = labor_inputs._NUMBER.search(text, hit.end())
|
||||
if not num or num.start() - hit.end() > 20:
|
||||
continue
|
||||
before = text[max(0, hit.start() - 12) : hit.start()]
|
||||
book = "산림품셈" if "산림" in before or "임도" in before else "건설품셈"
|
||||
book = book_of(text[max(0, hit.start() - 12) : hit.start()])
|
||||
typo = _TYPO_CLAUSE.match(num.group())
|
||||
number = "{}-{}{}-{}".format(*typo.groups()) if typo else num.group()
|
||||
if [book, number] not in out:
|
||||
|
||||
@@ -23,6 +23,7 @@ from typing import Any
|
||||
|
||||
from common_util.common_util_time import utc_now_text
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
from M02_MasterTemplete import M02_Hopyo_Basis as hopyo_basis
|
||||
from M02_MasterTemplete import M02_Hopyo_Fit as fit
|
||||
from M02_MasterTemplete import M02_Hopyo_Ledger as ledger
|
||||
from M02_MasterTemplete import M02_Hopyo_SkPatch as skpatch
|
||||
@@ -169,11 +170,15 @@ class Maker:
|
||||
return self._units
|
||||
|
||||
def basis(self, no: int) -> dict[str, Any] | None:
|
||||
"""근거 꼬리표 = 맞춤셈 1위 기초(참고)."""
|
||||
"""근거 꼬리표 = 맞춤셈 1위 기초(참고) · 출처 조항이 우리 기초 밖이고 1위가 맞음 아니면
|
||||
1위 대신 표지(781-2 · 「기초 없음 — 건설 공통 1-2-7 운반」 · 「옛 번호 — 근거 못 씀」)."""
|
||||
if no not in self.first: # 일위대가 밖 = 맞춤셈 없음
|
||||
return None
|
||||
entry = self.cache.get(fit.unit_key(self.first[no])) or {}
|
||||
top = (entry.get("차례") or [None])[0]
|
||||
outside = hopyo_basis.no_basis(self.blocks[no].get("출처"))
|
||||
if outside and (entry.get("판정") or {}).get("상태") != "맞음":
|
||||
return {"로직": None, "이름": outside["이름"], "판정": outside["판정"]}
|
||||
if not top:
|
||||
return None
|
||||
name = (self.whole.logic(top) or {}).get("이름")
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
같음 1위 고정(딱 맞음이 이김) → 섞인 줄 몫 먼저 · 조합(`Combine.solve` · 근거 안 닿은 덧 = 후보 끝)
|
||||
→ 위 다섯 옵션 거꾸로(`Option`) →
|
||||
위 다섯 가운데 딱 맞음(옵션까지)이 있는데 1위가 아니면 그것이 1위(조합 없는 줄) →
|
||||
판정 맞음 · 다른 점 · 후보 + 후보 다섯(로직마다 옵션 판정 꼬리표).
|
||||
판정 맞음 · 다른 점 · 후보 + 후보 다섯(로직마다 옵션 판정 꼬리표) ·
|
||||
출처 조항이 우리 기초 밖(781-2 · `Basis.no_basis`) = `기초없음` 표지 · 판정 꼬리표 ·
|
||||
맞음 아닌 후보 글 「참고 후보」.
|
||||
글 · 꼬리표는 숫자 사실만(엑셀 · 우리 품) — 「옛 판」 같은 까닭은 짓지 않음.
|
||||
"""
|
||||
|
||||
@@ -22,6 +24,7 @@ from M02_MasterTemplete import M02_Hopyo_Option as option
|
||||
|
||||
|
||||
_num = money_fmt.fmt # 꼬리표 수 — 공용 수량 꼴(1만 넘어도 지수 꼴 아님)
|
||||
OUTSIDE = "참고 후보 — 근거 조항 아님"
|
||||
|
||||
|
||||
def excel_qty(efp: dict[str, Any]) -> dict[str, Any]:
|
||||
@@ -150,6 +153,11 @@ def block(block_: dict | None, line: dict[str, Any], got: dict[str, Any]) -> dic
|
||||
entry["조합"] = combo or None
|
||||
entry["판정"] = judge(efp, top, opts, theirs, got)
|
||||
entry["후보"] = candidates(efp, top, opts, theirs, got, scores, border.get("근거") or {})
|
||||
if outside := hopyo_basis.no_basis(theirs): # 781-2 — 근거 조항이 우리 기초 밖
|
||||
entry["기초없음"] = outside
|
||||
entry["판정"]["꼬리표"].append(outside["글"])
|
||||
for c in entry["후보"]:
|
||||
c["글"] = c["글"] if c["판정"] == "맞음" else OUTSIDE
|
||||
names = {x["로직"]: x for x in got["로직"]}
|
||||
for k in (k for k in spare if k not in top[: fit.TOP_OPT] and k in names): # 근거 안 닿은 덧
|
||||
one = {key: names[k][key] for key in ("로직", "이름", "단위")}
|
||||
|
||||
Reference in New Issue
Block a user