refactor(776-2): 엑셀 한 번 열기(격자 = 읽은 책) · 줄 갈래 한 규칙 · EST 블록 금액 · 항목 · 옛 판 HP 409 「다시 올림」
- Excel — read_book 이 연 책(xls = formatting_info · 목록 시트까지)을 Grid.read 가 이어 씀(opened) · 거창 여는 횟수 2 → 1 · 여덟 파일 올림 시간 17.8 → 7.8 초 - Excel.kind_of = 두 형식 · 붙여넣기 한 규칙(STmate 코드 머리 · EST 칸 · 끝에 노임 올림) · Stmate._kind 걷음 - Excel — EST 블록에 금액 · 항목(ReadEst) 실음 · Basis 대신 ReadEst 직접 - Grid — 읽은 책 그대로 · xlsx 열 폭은 보기 시트 머리 <cols> 만(sheetData 에서 멈춤) · 여덟 파일 격자 결과 전과 같음 - Store.read 다른 판 = 409 「다시 올림」 · Forget.finish 는 옛 판도 끝냄(old=True) - S1 · S2 해시 그대로 · test_718_1 옛 판 열기 409 · 끝내기 시험 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,13 +24,14 @@ import zipfile
|
||||
from typing import Any
|
||||
|
||||
from openpyxl.utils import get_column_letter
|
||||
from openpyxl.xml.functions import fromstring
|
||||
from openpyxl.xml.functions import fromstring, iterparse
|
||||
|
||||
from M02_MasterTemplete import M02_Hopyo_Basis as hopyo_basis
|
||||
from M02_MasterTemplete import M02_Hopyo_Excel as hopyo_excel
|
||||
from M02_MasterTemplete import M02_Hopyo_ReadEst as hopyo_basis # EST 단가산출 시트 이름
|
||||
from M02_MasterTemplete import M02_Hopyo_Stmate as hopyo_stmate
|
||||
|
||||
LIST_E, LIST_S, HOPYO_S = "단가산출총괄표", hopyo_stmate.LISTS[0], "일위대가목록표"
|
||||
LIST_E, HOPYO_S = hopyo_excel.LISTS
|
||||
LIST_S = hopyo_stmate.LISTS[0]
|
||||
SHEETS = (
|
||||
hopyo_excel.SHEET,
|
||||
LIST_E,
|
||||
@@ -185,10 +186,8 @@ def _xls_sheet(book: Any, sh: Any, styles: _Styles, sid: str) -> dict[str, Any]:
|
||||
return out
|
||||
|
||||
|
||||
def _xls(data: bytes) -> dict[str, Any]:
|
||||
import xlrd
|
||||
|
||||
book = xlrd.open_workbook(file_contents=data, formatting_info=True, logfile=io.StringIO())
|
||||
def _xls(book: Any) -> dict[str, Any]:
|
||||
"""xlrd 책(`formatting_info` · 읽기가 연 것) → 격자."""
|
||||
styles = _Styles()
|
||||
found = {sh.name.strip(): sh for sh in book.sheets()}
|
||||
sheets = [
|
||||
@@ -203,8 +202,11 @@ def _xls(data: bytes) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _xlsx_widths(data: bytes) -> dict[str, dict[str, dict[str, Any]]]:
|
||||
"""시트 이름 → 열 글자 → `{폭, 숨김}` — 시트 XML `<cols>` 를 읽음(read_only 는 폭을 안 줌)."""
|
||||
def _xlsx_widths(
|
||||
data: bytes, names: tuple[str, ...] | None = None
|
||||
) -> dict[str, dict[str, dict[str, Any]]]:
|
||||
"""시트 이름 → 열 글자 → `{폭, 숨김}` — 시트 XML 머리 `<cols>` 만 읽음(`<sheetData>` 에서 멈춤 ·
|
||||
read_only 는 폭을 안 줌) · `names` = 이 시트만."""
|
||||
out: dict[str, dict[str, dict[str, Any]]] = {}
|
||||
try:
|
||||
with zipfile.ZipFile(io.BytesIO(data)) as zf:
|
||||
@@ -216,11 +218,15 @@ def _xlsx_widths(data: bytes) -> dict[str, dict[str, dict[str, Any]]]:
|
||||
for sheet in fromstring(zf.read("xl/workbook.xml")).iter():
|
||||
if tag(sheet) != "sheet":
|
||||
continue
|
||||
if names is not None and sheet.get("name", "").strip() not in names:
|
||||
continue
|
||||
rid = next((v for k, v in sheet.attrib.items() if k.endswith("}id")), None)
|
||||
path = (rels.get(rid) or "").lstrip("/")
|
||||
path = path if path.startswith("xl/") else f"xl/{path}"
|
||||
cols: dict[str, dict[str, Any]] = {}
|
||||
for col in fromstring(zf.read(path)).iter():
|
||||
for _, col in iterparse(zf.open(path), events=("start",)):
|
||||
if tag(col) == "sheetData":
|
||||
break
|
||||
if tag(col) != "col":
|
||||
continue
|
||||
first, last = int(col.get("min", 0)), min(int(col.get("max", 0)), 200)
|
||||
@@ -240,7 +246,7 @@ def _xlsx(
|
||||
) -> dict[str, Any]:
|
||||
# ponytail: xlsx 는 값 · 열 폭만(병합 · 서식은 openpyxl 비 read_only 로 무거움) — 필요하면 그때
|
||||
found = found or hopyo_excel._sheets(name, data, EXTRA)
|
||||
widths = _xlsx_widths(data)
|
||||
widths = _xlsx_widths(data, SHEETS)
|
||||
sheets = []
|
||||
for at, title in enumerate((n for n in SHEETS if n in found), 1):
|
||||
rows = found[title]
|
||||
@@ -319,9 +325,8 @@ def _lists(rows: dict[str, Any], parsed: dict[str, Any]) -> dict[str, list[dict[
|
||||
def read(name: str, data: bytes, parsed: dict[str, Any]) -> dict[str, Any]:
|
||||
"""엑셀 → `{책: Workbook, 호표, 단산, 보기, 원본, 목록, 줄}` — `parsed` =
|
||||
`M02_Hopyo_Excel.read_book` 결과(행 범위)."""
|
||||
xlsx = data[:4] == b"PK\x03\x04" or name.lower().endswith(".xlsx")
|
||||
rows = hopyo_excel._sheets(name, data, EXTRA) # ponytail: xls 는 서식 없이 한 번 더 읽음
|
||||
book = _xlsx(name, data, rows) if xlsx else _xls(data)
|
||||
rows, xls = hopyo_excel.opened(name, data, EXTRA) # 읽기가 연 책 그대로(한 번 열기 · 776-2)
|
||||
book = _xlsx(name, data, rows) if xls is None else _xls(xls)
|
||||
keep = ("번", "이름", "행")
|
||||
ids = {s["이름"]: s["id"] for s in book["시트"]}
|
||||
on = {role: next((n for n in names if n in ids), None) for role, names in ROLES.items()}
|
||||
|
||||
Reference in New Issue
Block a user