ToolStore Agent
feat: toolsets with @tool decorator, in-process execution, no auto-install
c37b3fd
Raw
History Blame Contribute Delete
6.9 kB
"""
xlsx‑toolkit β€” Read, write, and convert Excel spreadsheets.
================================================================
Provides four functions for working with .xlsx files without needing
to write throw‑away scripts for every spreadsheet task.
"""
import io
import json
import sys
from pathlib import Path
try:
from toolstore.toolset import tool
except ImportError:
def tool(fn):
return fn # no‑op when toolstore package not installed
# ── xlsx_read ──────────────────────────────────────────────────────────
@tool
def xlsx_read(*, filepath: str, sheet: str = "",
max_rows: int = 0) -> dict:
"""Read an Excel sheet and return rows as a JSON array.
Args:
filepath: Absolute or relative path to the .xlsx file.
sheet: Sheet name (default: first sheet).
max_rows: Limit rows read (0 = all).
Returns:
dict with keys:
sheet β€” name of the sheet that was read
columns β€” list of column headers
rows β€” list of dicts, one per data row
count β€” number of data rows returned
"""
try:
from openpyxl import load_workbook
except ImportError:
return {"error": "openpyxl not installed β€” run: pip install openpyxl"}
p = Path(filepath).expanduser().resolve()
if not p.exists():
return {"error": f"File not found: {p}"}
try:
wb = load_workbook(p, read_only=True, data_only=True)
except Exception as exc:
return {"error": f"Cannot open workbook: {exc}"}
ws = wb[sheet] if sheet else wb.active
if ws is None:
return {"error": f"Sheet '{sheet or '(default)'}' not found"}
rows_iter = ws.iter_rows(values_only=True)
try:
headers = [str(h) if h is not None else f"col_{i}"
for i, h in enumerate(next(rows_iter))]
except StopIteration:
return {"sheet": ws.title, "columns": [], "rows": [], "count": 0}
rows = []
for row in rows_iter:
row_dict = {headers[i]: (None if v is None else v)
for i, v in enumerate(row) if i < len(headers)}
for h in headers[len(row):]:
row_dict[h] = None
rows.append(row_dict)
if max_rows and len(rows) >= max_rows:
break
wb.close()
return {"sheet": ws.title, "columns": headers, "rows": rows, "count": len(rows)}
# ── xlsx_sheets ────────────────────────────────────────────────────────
@tool
def xlsx_sheets(*, filepath: str) -> dict:
"""List all sheet names in an Excel file with row/column counts.
Args:
filepath: Path to the .xlsx file.
Returns:
dict with keys:
filename β€” base name of the file
sheets β€” list of {name, rows, cols}
"""
try:
from openpyxl import load_workbook
except ImportError:
return {"error": "openpyxl not installed β€” run: pip install openpyxl"}
p = Path(filepath).expanduser().resolve()
if not p.exists():
return {"error": f"File not found: {p}"}
try:
wb = load_workbook(p, read_only=True, data_only=True)
except Exception as exc:
return {"error": f"Cannot open workbook: {exc}"}
sheets = []
for name in wb.sheetnames:
ws = wb[name]
sheets.append({"name": name, "rows": ws.max_row or 0, "cols": ws.max_column or 0})
wb.close()
return {"filename": p.name, "sheets": sheets}
# ── xlsx_to_csv ────────────────────────────────────────────────────────
@tool
def xlsx_to_csv(*, filepath: str, sheet: str = "",
delimiter: str = ",") -> dict:
"""Convert an Excel sheet to CSV text.
Args:
filepath: Path to the .xlsx file.
sheet: Sheet name (default: first sheet).
delimiter: Field delimiter (default comma).
Returns:
dict with key "csv" containing the full CSV string.
"""
result = xlsx_read(filepath=filepath, sheet=sheet)
if "error" in result:
return result
columns = result["columns"]
lines = [delimiter.join(f'"{c}"' if delimiter in str(c) else str(c)
for c in columns)]
for row in result["rows"]:
lines.append(delimiter.join(
f'"{v}"' if v is not None and delimiter in str(v) else (str(v) if v is not None else "")
for v in (row.get(c, "") for c in columns)
))
return {"csv": "\n".join(lines), "sheet": result["sheet"],
"rows": result["count"], "columns": columns}
# ── xlsx_create ────────────────────────────────────────────────────────
@tool
def xlsx_create(*, filepath: str, sheet: str = "Sheet1",
columns: list, rows: list) -> dict:
"""Create a new .xlsx file from provided data.
Args:
filepath: Where to write the new .xlsx file.
sheet: Sheet name.
columns: List of column header strings.
rows: List of dicts, each keyed by column name.
Returns:
dict with "written" (absolute path) or "error".
"""
try:
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
except ImportError:
return {"error": "openpyxl not installed β€” run: pip install openpyxl"}
p = Path(filepath).expanduser().resolve()
p.parent.mkdir(parents=True, exist_ok=True)
wb = Workbook()
ws = wb.active
ws.title = sheet
hdr_font = Font(bold=True, color="FFFFFF", size=11)
hdr_fill = PatternFill(start_color="4F46E5", end_color="4F46E5", fill_type="solid")
hdr_align = Alignment(horizontal="center", vertical="center")
for col_idx, col_name in enumerate(columns, 1):
cell = ws.cell(row=1, column=col_idx, value=col_name)
cell.font = hdr_font
cell.fill = hdr_fill
cell.alignment = hdr_align
for r, row_data in enumerate(rows, 2):
for c, col_name in enumerate(columns, 1):
value = row_data.get(col_name) if isinstance(row_data, dict) else row_data[c-1] if isinstance(row_data, list) else None
ws.cell(row=r, column=c, value=value)
for col in ws.columns:
max_len = max((len(str(cell.value or "")) for cell in col), default=8)
ws.column_dimensions[col[0].column_letter].width = min(max_len + 2, 60)
wb.save(p)
return {"written": str(p), "sheet": sheet,
"columns": len(columns), "rows": len(rows)}