docs(infra): add .md metadata for write_xlsx_sheets function
The function code and its registry metadata were created together but the .md was left untracked by the auto-commit. Add it so the indexed function has its companion metadata versioned. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
---
|
||||
name: write_xlsx_sheets
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def write_xlsx_sheets(out_path: str, sheets: dict, header_bold: bool = True, autofit: bool = True, freeze_header: bool = True) -> str"
|
||||
description: "Escribe un archivo Excel (.xlsx) multi-hoja desde datos en memoria con openpyxl. Crea (o sobrescribe) un libro completo a partir de un dict {nombre_hoja: datos}, una hoja por key en orden de insercion. Cada hoja acepta list[list] (primera fila = headers) o {\"headers\": [...], \"rows\": [[...]]}. Cabecera en negrita opcional, auto-ancho de columnas aproximado (cap 60), congelado de cabecera (freeze_panes A2), y manejo de celdas None/numeros/strings/bool. Crea los directorios padre si faltan. Devuelve la ruta absoluta del archivo escrito."
|
||||
tags: [xlsx, excel, spreadsheet, openpyxl, office, onlyoffice, io, infra]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [openpyxl]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "python/functions/infra/write_xlsx_sheets.py"
|
||||
params:
|
||||
- name: out_path
|
||||
desc: "Ruta del archivo .xlsx a escribir. Se crean los directorios padre si faltan. Si el archivo ya existe se SOBRESCRIBE por completo (no preserva hojas previas). Vacio lanza ValueError."
|
||||
- name: sheets
|
||||
desc: "Dict {nombre_hoja: datos}, una hoja por key en orden de insercion. Cada valor admite dos formas: (1) list[list] donde la primera fila son los headers y el resto filas de datos; (2) dict {\"headers\": [...], \"rows\": [[...], ...]} separando cabeceras de filas. Dict vacio lanza ValueError. El nombre de hoja se trunca a 31 chars (limite de Excel)."
|
||||
- name: header_bold
|
||||
desc: "Si True (default) la primera fila (cabecera) de cada hoja se escribe en negrita. Solo aplica cuando la hoja tiene headers."
|
||||
- name: autofit
|
||||
desc: "Si True (default) ajusta el ancho de cada columna a la longitud maxima del contenido de esa columna (incluida la cabecera), con un cap de 60 caracteres y +2 de holgura. Es aproximado (cuenta caracteres, no pixeles reales de la fuente)."
|
||||
- name: freeze_header
|
||||
desc: "Si True (default) congela la fila de cabecera con freeze_panes='A2' en cada hoja que tenga cabecera, dejandola fija al hacer scroll."
|
||||
output: "str — la ruta ABSOLUTA del archivo .xlsx escrito (os.path.abspath de out_path)."
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from infra.write_xlsx_sheets import write_xlsx_sheets
|
||||
|
||||
path = write_xlsx_sheets(
|
||||
"/tmp/reporte_ventas.xlsx",
|
||||
{
|
||||
# Forma list[list]: primera fila = headers
|
||||
"Ventas": [
|
||||
["Producto", "Unidades", "Precio", "Activo"],
|
||||
["Teclado", 12, 29.99, True],
|
||||
["Raton", 30, 14.5, False],
|
||||
["Monitor", None, 199.0, True], # None -> celda vacia
|
||||
],
|
||||
# Forma explicita: headers + rows
|
||||
"Resumen": {
|
||||
"headers": ["Metrica", "Valor"],
|
||||
"rows": [
|
||||
["Total productos", 3],
|
||||
["Ingreso estimado", 6359.99],
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
print(path) # /tmp/reporte_ventas.xlsx
|
||||
|
||||
# Leer de vuelta para confirmar
|
||||
from openpyxl import load_workbook
|
||||
wb = load_workbook(path)
|
||||
print(wb.sheetnames) # ['Ventas', 'Resumen'] (orden preservado)
|
||||
print(wb["Ventas"]["B2"].value) # 12 (int conservado)
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Usala cuando tengas datos en memoria (resultado de un scraping, una query, un
|
||||
report) y quieras volcarlos a un archivo Excel limpio de una sola pasada, con
|
||||
una o varias hojas. Es la pieza de escritura para exportar datasets a `.xlsx`
|
||||
sin formulas ni preservacion de estado previo: tu generas el dict
|
||||
`{hoja: filas}` y la funcion produce el libro entero. Si necesitas actualizar
|
||||
UNA hoja de un libro que ya existe sin destruir las demas (preservando trabajo
|
||||
manual, formulas, key matching), usa `upsert_xlsx_sheet_py_infra` en su lugar.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Impura — escribe en disco.** Devuelve la ruta absoluta del archivo escrito.
|
||||
- **SOBRESCRIBE el archivo si ya existe.** No hace merge ni backup: el libro
|
||||
anterior se reemplaza por completo. Para escritura no destructiva sobre un
|
||||
libro existente, usa `upsert_xlsx_sheet`.
|
||||
- **Requiere openpyxl** (ya instalado en `python/.venv`, version 3.1.5). Si no
|
||||
esta disponible lanza `ImportError` con la instruccion de instalacion
|
||||
(`cd python && uv add openpyxl`).
|
||||
- **Nombre de hoja truncado a 31 caracteres** (limite de Excel). openpyxl
|
||||
tambien prohibe ciertos caracteres en el nombre (`\ / ? * [ ] :`); pasarlos
|
||||
puede lanzar.
|
||||
- **autofit es aproximado**: mide longitud de caracteres del contenido, no el
|
||||
ancho real en pixeles de la fuente. Cap a 60 chars para columnas con texto
|
||||
largo.
|
||||
- **Tipos de celda**: None, int, float, str y bool se escriben nativos
|
||||
(preservan su tipo en Excel). Cualquier otro tipo (date, Decimal, objetos) se
|
||||
serializa a `str` — convierte tu mismo antes si quieres tipos nativos de Excel.
|
||||
- **sheets vacio o out_path vacio** lanzan `ValueError`.
|
||||
- **Encoding**: openpyxl maneja Unicode (UTF-8) de forma transparente en los
|
||||
valores de celda; no hay que codificar nada a mano.
|
||||
Reference in New Issue
Block a user