import json import os import time from .audit import audit_tool_call import subprocess from typing import List, Any import pandas as pd from openpyxl import load_workbook, Workbook from openpyxl.utils import range_boundaries from openpyxl.worksheet.table import Table, TableStyleInfo def open_workbook(path: str): _t = time.time() wb = load_workbook(path) wb.close() out = {"path": path, "sheets": wb.sheetnames} audit_tool_call("tool_spreadsheet.open_workbook", {"path": path}, {"ok": True}, True, int((time.time()-_t)*1000)) return out def read_range(path: str, sheet: str, a1_range: str): wb = load_workbook(path, data_only=True) ws = wb[sheet] min_col, min_row, max_col, max_row = range_boundaries(a1_range) data = [] for row in ws.iter_rows(min_row=min_row, max_row=max_row, min_col=min_col, max_col=max_col, values_only=True): data.append(list(row)) wb.close() return {"sheet": sheet, "range": a1_range, "values": data} def write_range(path: str, sheet: str, start_cell: str, values: List[List[Any]], style: dict | None = None): wb = load_workbook(path) ws = wb[sheet] start_col = ws[start_cell].column start_row = ws[start_cell].row for r_idx, row in enumerate(values): for c_idx, val in enumerate(row): ws.cell(row=start_row + r_idx, column=start_col + c_idx, value=val) wb.save(path) wb.close() return {"status": "ok"} def add_sheet(path: str, name: str): wb = load_workbook(path) if name in wb.sheetnames: wb.close() return {"status": "exists"} wb.create_sheet(title=name) wb.save(path) wb.close() return {"status": "ok"} def create_workbook(path: str, template_spec_json: dict): wb = Workbook() wb.remove(wb.active) for sheet_spec in template_spec_json.get("sheets", []): ws = wb.create_sheet(title=sheet_spec.get("name", "Sheet")) data = sheet_spec.get("data", []) for row in data: ws.append(row) wb.save(path) wb.close() return {"status": "ok", "path": path} def apply_table(path: str, sheet: str, a1_range: str, table_name: str): wb = load_workbook(path) ws = wb[sheet] table = Table(displayName=table_name, ref=a1_range) style = TableStyleInfo(name="TableStyleMedium9", showRowStripes=True) table.tableStyleInfo = style ws.add_table(table) wb.save(path) wb.close() return {"status": "ok"} def validate(path: str): try: load_workbook(path).close() return [] except Exception as e: return [str(e)] def save_as(path: str, out_path: str): wb = load_workbook(path) wb.save(out_path) wb.close() return {"status": "ok", "out_path": out_path} def convert_to_pdf(path: str, out_pdf_path: str): cmd = ["soffice", "--headless", "--convert-to", "pdf", "--outdir", os.path.dirname(out_pdf_path), path] try: subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return {"status": "ok", "out_pdf_path": out_pdf_path} except Exception as e: return {"status": "error", "error": str(e)}