majorsilence-reporting
Genera informes RDL en PDF, Excel, CSV y más desde Python — vía subproceso, un binario AOT, o FFI ctypes en proceso. Sin dependencias en tiempo de ejecución más allá de la biblioteca estándar.
Instalación
Instala desde PyPI (se requiere Python 3.10+):
# PyPI pip install majorsilence-reporting # O de forma editable desde el código fuente pip install -e .
Sin dependencias en tiempo de ejecución — usa solo la biblioteca estándar de Python (subprocess, ctypes, tempfile).
Modos de integración
Hay tres clases disponibles según cómo despliegues el motor de informes:
| Clase | Mecanismo | Requisito |
|---|---|---|
| Report | Lanza dotnet RdlCmd.dll como proceso hijo. | Runtime de .NET instalado en el servidor. |
| ReportAot | Lanza un binario RdlCmd autocontenido compilado con AOT. | Binario AOT desplegado junto a la aplicación. No se necesita runtime de .NET. |
| report_native.Report | Carga librdlnative.so en el proceso mediante ctypes. | Biblioteca nativa + archivos .so asociados desplegados. Llama a load_library() una vez al iniciar. |
Report — subproceso (dotnet)
from majorsilence_reporting import Report rpt = Report( report_path = '/path/to/report.rdl', rdl_cmd_path = '/path/to/RdlCmd.dll', ) rpt.set_connection_string('Data Source=/path/to/data.db') rpt.set_parameter('StartDate', '2026-01-01') # Guardar en un archivo rpt.export('pdf', '/tmp/output.pdf') # O bien obtener los bytes en memoria (por ejemplo para una respuesta de Flask) data = rpt.export_to_memory('pdf') return Response(data, mimetype='application/pdf')
ReportAot — binario AOT
Misma API que Report, pero apunta a un binario autocontenido en lugar de a una DLL. No se necesita runtime de .NET en el servidor.
from majorsilence_reporting import ReportAot rpt = ReportAot( report_path = '/path/to/report.rdl', rdl_cmd_path = '/path/to/RdlCmd', # binario autocontenido, sin extensión .dll ) rpt.set_connection_string('Data Source=/path/to/data.db') data = rpt.export_to_memory('xlsx') # ReportAot también admite xlsx_table, tifb y mht data = rpt.export_to_memory('xlsx_table')
report_native — FFI en proceso
El modo nativo carga librdlnative.so directamente en el proceso de Python mediante ctypes. No se genera ningún proceso hijo, lo que lo convierte en la opción de menor latencia. También admite renderizado en memoria real — los bytes del informe se devuelven directamente desde el búfer nativo sin escribir un archivo temporal.
from majorsilence_reporting.report_native import load_library, Report # Llamar una vez al iniciar el proceso. Carga librdlnative.so y todas las bibliotecas asociadas. lib = load_library('/path/to/librdlnative.so') rpt = Report(lib, report_path='/path/to/report.rdl') rpt.set_connection_string('Data Source=/path/to/data.db') # Devuelve los bytes directamente desde el búfer nativo — no se escribe ningún archivo temporal data = rpt.export_to_memory('pdf') # Pasar a Django / FastAPI / Flask como respuesta binaria return Response(data, media_type='application/pdf')
load_library() define RDLNATIVE_LIB_DIR y precarga todas las bibliotecas .so / .dylib asociadas con RTLD_GLOBAL para que el resolutor P/Invoke de .NET las encuentre correctamente. Llámala una vez por proceso antes de crear cualquier instancia de Report.
API principal
Las tres clases comparten la misma interfaz:
| Método | Descripción |
|---|---|
| set_connection_string(cs) | Establece la cadena de conexión a la base de datos usada por el informe. Llamar antes de export. |
| set_parameter(name, value) | Define un parámetro de informe con nombre. Ambos argumentos son cadenas. Se puede llamar tantas veces como sea necesario. |
| export(format, path) | Renderiza el informe y escribe la salida en path en disco. |
| export_to_memory(format) | Renderiza y devuelve la salida como bytes (formatos binarios) o str (formatos de texto). En report_native.Report siempre devuelve bytes. |
Conjuntos de datos en memoria
report_native.Report permite suministrar datos completamente en memoria mediante add_data() — sin necesidad de conexión a una base de datos. Pasa un nombre de conjunto de datos y una lista de diccionarios donde cada valor es una cadena.
from majorsilence_reporting.report_native import load_library, Report lib = load_library('/path/to/librdlnative.so') rpt = Report(lib, report_path='/path/to/report.rdl') rpt.add_data('SalesData', [ {'Product': 'PDF Library Pro', 'Revenue': '1200.00', 'Units': '3'}, {'Product': 'Report Designer', 'Revenue': '250.00', 'Units': '1'}, {'Product': 'Support (12 mo.)', 'Revenue': '500.00', 'Units': '1'}, ]) data = rpt.export_to_memory('pdf')
add_data() activa automáticamente SkipDatabaseSchemaValidation. El nombre del conjunto de datos debe coincidir con un conjunto de datos definido en el archivo .rdl. Todos los valores de campo deben ser cadenas — convierte números y fechas antes de pasarlos.
Formatos de exportación
| Cadena de formato | Salida | Disponible en |
|---|---|---|
pdf | Todos los modos | |
csv | Texto CSV | Todos los modos |
xlsx | Libro de Excel | Todos los modos |
xml | Datos XML | Todos los modos |
rtf | Rich Text Format | Todos los modos |
tif | Imagen TIFF (color) | Todos los modos |
html | HTML | Todos los modos |
xlsx_table | Excel (estilo tabla) | Solo ReportAot + nativo |
tifb | Imagen TIFF (blanco y negro) | Solo ReportAot + nativo |
mht | Archivo web MHTML | Solo ReportAot + nativo |
pdf. Todos los métodos son síncronos — envuélvelos en asyncio.get_event_loop().run_in_executor(None, ...) si necesitas llamarlos desde código asíncrono sin bloquear.