Files
fn_registry/python/functions/infra/upsert_xlsx_sheet.md
T
2026-06-15 01:33:35 +02:00

6.2 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
upsert_xlsx_sheet function py infra 1.0.0 impure def upsert_xlsx_sheet(xlsx_path: str, sheet_name: str, records: list[dict], columns: list[str], key_col: str = "", preserve_cols: list[str] | None = None, formulas: dict | None = None, backup: bool = True, freeze: str = "A2", autofilter: bool = True) -> dict Actualiza de forma NO DESTRUCTIVA una hoja concreta de un archivo .xlsx con openpyxl. Reescribe SOLO la hoja indicada (sheet_name) y conserva intactas las demas hojas del libro. Antes de limpiar la hoja gestionada lee, por una columna clave (key_col), los valores de las columnas de trabajo manual (preserve_cols) y los reescribe ganando sobre los datos nuevos. Cabecera estilizada (negrita, relleno, texto blanco, borde, centrado), freeze_panes, autofilter, auto-ancho de columnas, formulas por columna con placeholders {row} y {NombreColumna}, y backup .bak opcional. Devuelve un resumen con filas escritas, hojas conservadas y celdas manuales preservadas.
xlsx
openpyxl
spreadsheet
office
onlyoffice
infra
false error_go_core
openpyxl
name desc
xlsx_path Ruta del archivo .xlsx. Si existe se abre con openpyxl (y se respaldan las demas hojas); si no existe se crea un libro nuevo eliminando la hoja por defecto vacia.
name desc
sheet_name Nombre de la hoja a (re)escribir. Es la UNICA hoja que la funcion toca; el resto del libro queda intacto. Si la hoja no existe, se crea.
name desc
records Lista de dicts; cada dict es una fila y sus claves son nombres de columna. Se escribe una fila por record en el orden definido por columns.
name desc
columns Orden canonico de columnas (nombres de cabecera). Define que columnas se escriben y en que orden. Una clave de un record que no este en columns se ignora.
name desc
key_col Nombre de la columna clave usada para emparejar filas existentes con records al preservar trabajo manual. Vacio (default) desactiva la preservacion. El match normaliza el valor (lowercase + espacios colapsados).
name desc
preserve_cols Lista de columnas cuyos valores manuales existentes en el libro se conservan: si una celda ya tenia valor para esa clave, ese valor gana sobre el de records. None o lista vacia desactiva la preservacion.
name desc
formulas Dict opcional {columna: "plantilla"} o {columna: {"f": plantilla, "fmt": formato_numerico}}. La plantilla admite {row} (numero de fila actual) y {NombreColumna} (letra de la columna con ese nombre). Estas columnas se escriben como formula en cada fila y NO se rellenan desde records.
name desc
backup Si True y el archivo existe, copia a xlsx_path + '.bak' antes de escribir. El .bak es rotativo: cada llamada lo sobrescribe. Default True.
name desc
freeze Celda para freeze_panes (inmoviliza filas/columnas por encima/izquierda). Default 'A2' (congela la cabecera).
name desc
autofilter Si True activa auto_filter sobre el rango A1 hasta la ultima columna y fila de datos. Default True.
Dict con: sheet (nombre de la hoja escrita), rows_written (numero de filas de datos), other_sheets_preserved (lista con los nombres de las demas hojas conservadas), manual_cells_preserved (cuantas celdas de trabajo manual se conservaron) y backup_path (ruta del .bak creado, o cadena vacia si no hubo backup). true
test_no_destructivo_y_preserva_trabajo_manual
test_crea_libro_nuevo_si_no_existe
python/functions/infra/upsert_xlsx_sheet_test.py python/functions/infra/upsert_xlsx_sheet.py

Ejemplo

import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from infra.upsert_xlsx_sheet import upsert_xlsx_sheet

result = upsert_xlsx_sheet(
    xlsx_path="/home/enmanuel/afiliados/programas_afiliados.xlsx",
    sheet_name="Datos",
    records=[
        {"Programa": "Awin", "Clicks": 1200, "Ingreso": 340},
        {"Programa": "CJ",   "Clicks": 800,  "Ingreso": 210},
    ],
    columns=["Programa", "Clicks", "Ingreso", "EPC"],
    key_col="Programa",
    preserve_cols=["Ingreso"],            # el ingreso anotado a mano gana sobre el dato nuevo
    formulas={
        "EPC": {"f": '=IFERROR({Ingreso}{row}/{Clicks}{row},"")', "fmt": "0.00"},
    },
)
print(result)
# {'sheet': 'Datos', 'rows_written': 2, 'other_sheets_preserved': ['Personal'],
#  'manual_cells_preserved': 1, 'backup_path': '/home/enmanuel/afiliados/programas_afiliados.xlsx.bak'}

La columna EPC se escribe como formula =IFERROR(C2/B2,"") (las letras se resuelven a partir de la posicion de Ingreso y Clicks en columns), y la hoja "Personal" del usuario no se toca.

Cuando usarla

Usala cuando necesites regenerar UNA hoja de un .xlsx que el usuario tambien edita a mano, sin destruir su trabajo: refrescar datos de research/scraping manteniendo columnas anotadas manualmente, o publicar un dataset en una hoja concreta de un libro que contiene otras hojas personales. Es la pieza de escritura para flujos donde un editor (OnlyOffice/Excel) y un proceso automatico comparten el mismo archivo.

Gotchas

  • Impura — escribe en disco. Pisa SOLO la hoja sheet_name; las demas hojas del libro se conservan tal cual (esa es la garantia central de la funcion).
  • Requiere openpyxl (ya instalado en python/.venv).
  • El .bak es rotativo: cada llamada con backup=True sobrescribe xlsx_path + ".bak". No es un historial; es la copia de la version anterior.
  • Lee del disco. Si el archivo esta abierto en OnlyOffice/Excel, GUARDA en el editor ANTES de llamar a la funcion: ella lee la version en disco y, al recargar el editor despues, perderias los cambios no guardados.
  • Las columnas se localizan por nombre en la cabecera (fila 1). Si renombras una columna entre ejecuciones, el match de preserve_cols/key_col con la version anterior se rompe para esa columna (se trata como columna nueva).
  • key_col vacio o preserve_cols vacio desactivan la preservacion: la hoja se reescribe por completo desde records.
  • Las columnas declaradas en formulas se escriben siempre como formula y NO se rellenan desde records ni se preservan.