"""Wczytanie pojedynczego arkusza do znormalizowanej ramki danych. Łączy wykrywanie nagłówka (header_detect) z mapowaniem układu kolumn (layout). Zwraca ramkę o KANONICZNYCH nazwach kolumn — gotową do indeksowania, cache'owania (parquet) i ewentualnego załadowania do SQL. To jest jedyne miejsce, które "rozumie" format Excela. Reszta systemu jej nie widzi. """ from __future__ import annotations from dataclasses import dataclass import pandas as pd from app.excel.header_detect import detect_header_row from app.excel.layout import build_column_mapping @dataclass class LoadedSheet: frame: pd.DataFrame # dane z kanonicznymi kolumnami header_row: int # wykryty indeks nagłówka column_mapping: dict[str, str] # pole_kanoniczne -> oryginalna_nazwa def load_sheet(path: str, sheet: str | int = 0, header_scan_rows: int = 15) -> LoadedSheet: raw = pd.read_excel(path, sheet_name=sheet, header=None, dtype=object) header_row = detect_header_row(raw, max_scan=header_scan_rows) header_cells = [str(c) for c in raw.iloc[header_row].tolist()] mapping = build_column_mapping(header_cells) data = raw.iloc[header_row + 1 :].copy() data.columns = header_cells data = data.dropna(how="all") # przenazwij na kanoniczne pola: {oryginał -> kanoniczne} inverse = {orig: canon for canon, orig in mapping.items()} data = data.rename(columns=inverse) data = data.reset_index(drop=True) return LoadedSheet(frame=data, header_row=header_row, column_mapping=mapping)