Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
fadc215
Adding
turulomio May 20, 2026
856e6ef
Trying
turulomio May 20, 2026
8998d22
Trying
turulomio May 20, 2026
1200255
Improving columnsWidth
turulomio May 21, 2026
e4231cc
Adding more modes
turulomio May 21, 2026
224879d
Complete
turulomio May 21, 2026
f837de6
Adding validations
turulomio May 21, 2026
dd2770d
Trying
turulomio May 21, 2026
4c986cc
Trying refactorizing
turulomio May 21, 2026
534b47c
Trying refactorizing
turulomio May 21, 2026
8cd81a4
Fixing bugs
turulomio May 21, 2026
14fabca
FROM_SHEET_CELLS work
turulomio May 21, 2026
88cd0c1
All test work
turulomio May 21, 2026
15fdee6
Added fast lor sheet
turulomio May 21, 2026
cb58634
Improving ods method
turulomio May 23, 2026
af0a4e1
Works
turulomio May 23, 2026
36309ae
Works
turulomio May 23, 2026
c382f48
Works
turulomio May 23, 2026
41e7df4
Improving
turulomio May 23, 2026
4654481
Refactorizado totalccolumns
turulomio May 23, 2026
dc860b1
Propuesta de mensaje de commit
turulomio May 23, 2026
2d626dc
Mejorada hoja de stylos
turulomio May 23, 2026
94bbbdc
Refactorizado y mejorado codigo
turulomio May 23, 2026
a816fd8
I dont know
turulomio May 23, 2026
83170ec
Improved doc
turulomio May 23, 2026
6477f06
Corregido Sheet
turulomio May 23, 2026
e0587d8
Añadido resto de helpers
turulomio May 23, 2026
e8407a9
Added helpers
turulomio May 23, 2026
e5b1bfe
Fixed errors
turulomio May 24, 2026
57eef06
Reordering tests
turulomio May 24, 2026
28aa3c7
Add test for unogenerator_cleaner
turulomio May 24, 2026
22eee13
Added tests form monitor y translation
turulomio May 24, 2026
bfe600f
Removed showing logic
turulomio May 24, 2026
7099ee1
Fixing action errors
turulomio May 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Install LibreOffice and uno dependencies
run: |
sudo apt-get update
sudo apt-get install -y libreoffice python3-uno imagemagick # Removed explicit python3.10 and python3.10-venv
sudo apt-get install -y libreoffice python3-uno imagemagick gettext # Removed explicit python3.10 and python3.10-venv
- name: Install python environment
run: |
python -m venv .venv --system-site-packages # Use 'python' and remove 'sudo'
Expand Down
180 changes: 180 additions & 0 deletions HELPERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# UnoGenerator Helpers Specification

Detailed reference of all helper functions in `unogenerator.helpers`.

## Table of Contents
1. [Totals Generation (Basic)](#1-totals-generation-basic)
2. [Totals Generation (Titled)](#2-totals-generation-titled)
3. [Advanced Totals (Cross-Calculations)](#3-advanced-totals-cross-calculations)
4. [Data Block Helpers](#4-data-block-helpers)
5. [Complete Sheet Helpers](#5-complete-sheet-helpers)
6. [Utility Helpers](#6-utility-helpers)

---

## 1. Totals Generation (Basic)

### `row_totals`
Generates a horizontal row of formulas.
- `doc` (ODS): The ODS document object.
- `coord` (Coord or str): Starting coordinate.
- `list_of_totals` (list): List of formula keys (e.g. `["#SUM", "#AVG"]`).
- `color` (int, default=ColorsNamed.GrayLight): Background color.
- `styles` (list or str, default=None): Cell style(s).
- `row_from` (str, default="2"): Start row for calculation range.
- `row_to` (str, default=None): End row for calculation range.

### `column_totals`
Generates a vertical column of formulas.
- `doc` (ODS): The ODS document object.
- `coord` (Coord or str): Starting coordinate.
- `list_of_totals` (list): List of formula keys.
- `color` (int, default=ColorsNamed.GrayLight): Background color.
- `styles` (list or str, default=None): Cell style(s).
- `column_from` (str, default="B"): Start column for calculation range.
- `column_to` (str, default=None): End column for calculation range.

---

## 2. Totals Generation (Titled)

### `row_title_values_total`
Creates a row with a title, a sequence of values, and their sum.
- `doc` (ODS): The ODS document object.
- `coord` (Coord or str): Starting coordinate.
- `title` (str): Title for the row.
- `values` (list): List of numerical values.
- `style_title` (str, default="Bold"): Style for the title.
- `color_title` (int, default=ColorsNamed.Orange): Title color.
- `style_values` (str, default=None): Style for the values.
- `color_values` (int, default=ColorsNamed.White): Values color.
- `style_total` (str, default=None): Style for the total.
- `color_total` (int, default=ColorsNamed.GrayLight): Total color.

### `column_title_values_total`
Creates a column with a title, a sequence of values, and their sum.
- `doc` (ODS): The ODS document object.
- `coord` (Coord or str): Starting coordinate.
- `title` (str): Title for the column.
- `values` (list): List of numerical values.
- `style_title` (str, default="Bold"): Style for the title.
- `color_title` (int, default=ColorsNamed.Orange): Title color.
- `style_values` (str, default=None): Style for the values.
- `color_values` (int, default=ColorsNamed.White): Values color.
- `style_total` (str, default=None): Style for the total.
- `color_total` (int, default=ColorsNamed.GrayLight): Total color.

---

## 3. Advanced Totals (Cross-Calculations)

### `cross_totals_from_range`
Generates optimized vertical and horizontal totals for a data range.
- `doc` (ODS): The ODS document object.
- `range_of_data` (Range or str): The data range to calculate from.
- `key` (str, default="#SUM"): Formula alias, function name, or template (e.g. `"=SUM({}*1.21)"`).
- `column_of_totals` (bool, default=True): If True, adds column at the right.
- `row_of_totals` (bool, default=True): If True, adds row at the bottom.
- `vertical_total_title_style` (str, default="BoldCenter"): Style for right label.
- `horizontal_total_title_style` (str, default="BoldCenter"): Style for bottom label.
- `showing` (bool, default=False): Legacy. If True, adds extra "Sum of totals" block.
- `label_column` (str, default="Total"): Text for the vertical total label.
- `label_row` (str, default="Total"): Text for the horizontal total label.
- `skip_columns` (int, default=0): Number of columns to skip for bottom row totals.

---

## 4. Data Block Helpers

### `block_from_lod`
Inserts data from a List of Ordered Dictionaries.
- `doc` (ODS): The ODS document object.
- `coord_start` (Coord or str): Starting coordinate.
- `lod_` (list): The list of dictionaries.
- `keys` (list, default=None): Specific keys to write.
- `columns_header` (int, default=0): Number of columns to color as headers.
- `color_row_header` (int, default=ColorsNamed.Orange): Color for the keys row.
- `color_column_header` (int, default=ColorsNamed.Green): Color for the header columns.
- `color` (int, default=ColorsNamed.White): Background for data cells.
- `styles` (list or str, default=None): Styles for data cells.
- `column_of_totals` (bool, default=False): Generate totals on the right.
- `row_of_totals` (bool, default=False): Generate totals at the bottom.
- `key` (str, default="#SUM"): Formula key (see `cross_totals_from_range`).
- `title` (str, default=None): Merged title for the block.
- `word_wrap` (bool, default=True): Enable text wrapping.

### `block_from_lol`
Inserts data from a List of Lists.
- `doc` (ODS): The ODS document object.
- `coord_start` (Coord or str): Starting coordinate.
- `lor` (list): The list of lists.
- `headers` (list, default=None): Column header names.
- `colors` (list or int, default=ColorsNamed.White): Column colors.
- `styles` (list or str, default=None): Column styles.
- `column_of_totals` (bool, default=False): Generate totals on the right.
- `row_of_totals` (bool, default=False): Generate totals at the bottom.
- `key` (str, default="#SUM"): Formula key.
- `title` (str, default=None): Merged title for the block.
- `word_wrap` (bool, default=True): Enable text wrapping.

### `block_from_lod_with_headers`
LOD writer with hierarchical sub-headers.
- `doc` (ODS): The ODS document object.
- `lod_` (list): List of dictionaries.
- `coord` (Coord or str): Starting coordinate.
- `subtitles` (list, default=[]): Groups of columns. List of `[title, first_key]`.
- `titulo` (str, default=None): Main title.
- `column_of_totals` (bool, default=False): Generate totals on the right.
- `row_of_totals` (bool, default=False): Generate totals at the bottom.
- `freezeandselect` (Coord or str, default=None): Auto-freeze coordinate.
- `key` (str, default="#SUM"): Formula key.
- `word_wrap` (bool, default=True): Enable text wrapping.

---

## 5. Complete Sheet Helpers

### `sheet_from_lod`
Creates a new sheet and populates it from an LOD.
- `doc` (ODS): The ODS document object.
- `sheetname` (str): Name of the new sheet.
- `lod_` (list): List of dictionaries.
- `column_of_totals` (bool, default=False): Right totals.
- `row_of_totals` (bool, default=False): Bottom totals.
- `freezeandselect` (str, default=None): Coordination to freeze.
- `title` (str, default=None): Main title.
- `word_wrap` (bool, default=True): Text wrap.
- `styles` (list or str, default=None): Data styles.
- `**kwargs_columnswidth`: Extra params for column width calculation.

### `sheet_from_lol`
Creates a new sheet and populates it from an LOL.
- `doc` (ODS): The ODS document object.
- `sheetname` (str): Name of the new sheet.
- `lor` (list): List of lists.
- `headers` (list): Header names.
- `column_of_totals` (bool, default=False): Right totals.
- `row_of_totals` (bool, default=False): Bottom totals.
- `freezeandselect` (str, default=None): Coordination to freeze.
- `titulo` (str, default=None): Main title.
- `word_wrap` (bool, default=True): Text wrap.
- `**kwargs_columnswidth`: Extra params for column width calculation.

### `sheet_split_with_big_lol`
Creates multiple sheets for massive datasets.
- `doc` (ODS): The ODS document object.
- `sheet_name` (str): Base name for sheets.
- `lor` (list): Massive list of lists.
- `headers` (list): Header names.
- `headers_colors` (int, default=ColorsNamed.Orange): Header background.
- `coord_to_freeze` (Coord or str, default="A2"): Freeze coordinate.
- `max_rows` (int, default=1048575): Max rows per sheet.
- `word_wrap` (bool, default=True): Text wrap.

---

## 6. Utility Helpers

### `sheet_stylenames`
Generates a reference sheet with available document styles.
- `doc` (ODS): The ODS document object.
2 changes: 1 addition & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Only Linux is supported

You need LibreOffice installed in your system. Imagemagick is recommended for some image operations.
You need LibreOffice installed in your system. **Imagemagick** is recommended for some image operations and **psutil** is recommended for robust process management.

In some distros you need to install Python LibreOffice bindings too (python3-uno)

Expand Down
74 changes: 45 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,71 +7,87 @@

## Description

Python module to generate Libreoffice documents (ODT and ODS) programatically.
**UnoGenerator** is a powerful Python module designed to generate LibreOffice documents (ODT and ODS) programmatically with high performance and professional aesthetics.

Morever, you can export them to (.xlsx, .docx, .pdf) easyly.
Key features include:
- **Professional Defaults**: Automatic text wrapping (`word_wrap=True`) and vertical centering for professional-looking reports out of the box.
- **High Performance**: Optimized for large datasets. Inserting 10,000 rows with default formatting takes less than 0.3 seconds.
- **Rich Exports**: Easy export to `.xlsx`, `.docx`, and `.pdf`.
- **Advanced Helpers**: Flexible totals generation, automatic column width calculation, and complex data block handling.
- **Multilingual Support**: Built-in support for translations and localized document generation.

It uses Libreoffice uno module, so you need Libreoffice to be installed in your system.
It uses the LibreOffice UNO module, requiring a LibreOffice installation on your system.

## Installation

Only Linux is supported. I'm going to write unogenerator [installation methods](INSTALL.md) for some main Linux Distributions
Only Linux is supported. See the [installation guide](INSTALL.md) for detailed instructions on main Linux distributions.

## Architecture

UnoGenerator follows a clean, template-based architecture:
- **ODS/ODT**: Generic base classes for document manipulation.
- **ODS_Standard / ODT_Standard**: Optimized subclasses that use the built-in professional templates, providing specific styles (like "Normal", "BoldCenter") and optimized row heights.

## ODT 'Hello World' example

This is a Hello World example. You get the example in odt, docx and pdf formats:
Create a professional ODT document with just a few lines:

```python
from unogenerator import ODT_Standard

with ODT_Standard() as doc:
doc.addParagraph("Hello World", "Heading 1")
doc.addParagraph("Easy, isn't it","Standard")
doc.save("hello_world.odt")
doc.export_docx("hello_world.docx")
doc.export_pdf("hello_world.pdf")
doc.addParagraph("Hello World", "Heading 1")
doc.addParagraph("Easy, isn't it", "Standard")
doc.save("hello_world.odt")
doc.export_docx("hello_world.docx")
doc.export_pdf("hello_world.pdf")
```

## ODS 'Hello World' example

This is a Hello World example. You'll get example files in ods, xlsx and pdf formats:
Generate a styled spreadsheet with automatic wrapping and alignment:

```python
from unogenerator import ODS_Standard

with ODS_Standard() as doc:
doc.addCellMergedWithStyle("A1:E1", "Hello world", style="BoldCenter")
doc.save("hello_world.ods")
doc.export_xlsx("hello_world.xlsx")
doc.export_pdf("hello_world.pdf")
# word_wrap and vertical alignment are enabled by default
doc.addCellMergedWithStyle("A1:E1", "Sales Report 2026", style="BoldCenter")
doc.addRowWithStyle("A2", ["Product", "Quantity", "Price", "Total"])
doc.save("sales_report.ods")
doc.export_xlsx("sales_report.xlsx")
```

## Unogenerator scripts
## Advanced Features: Totals and Formulas

Python unogenerator package has the following scripts:
UnoGenerator provides advanced helpers to generate calculations quickly:

### unogenerator_monitor
```python
from unogenerator import helpers

Monitors your libreoffice server instances
# Generates both row and column totals with a custom formula template
helpers.cross_totals_from_range(doc, "B2:D10", key="=SUM({}*1.21)")
```

### unogenerator_translation
## Unogenerator scripts

With this tool you can translate several odt files with one command. It generates .pot and .po files, where you can set your translations. Then run your command again and you'll get your files translated
The package includes several useful CLI tools:

`unogenerator_translation --from_language es --to_language en --input original.odt --input original2.odt --output_directory "translation_original"`
### unogenerator_monitor
Monitors your LibreOffice server instances and their status.

You can use --fake to see simulation of your translation
### unogenerator_translation
Translate multiple ODT files using standard `.pot` and `.po` files.
`unogenerator_translation --from_language es --to_language en --input original.odt --output_directory "translated"`

### unogenerator_demo

With this tool you can generate a demo, remove its result files and make benchmark comparations in your system
Generate comprehensive example files and perform performance benchmarks on your system.

## Documentation
You can read [documentation](https://github.com/turulomio/unogenerator/blob/main/doc/unogenerator_documentation_en.odt?raw=true) in doc directory. It has been created with unogenerator.
Full technical [documentation](https://github.com/turulomio/unogenerator/blob/main/doc/unogenerator_documentation_en.odt?raw=true) is available in the `doc` directory, created using UnoGenerator itself.

## Development links

- [LibreOffice code](https://github.com/LibreOffice/core)
- [LibreOffice API](https://api.libreoffice.org/docs/idl/ref/index.html)
- [OpenOffice Forums](https://forum.openoffice.org/en/forum/viewforum.php?f=20)
- [LibreOffice Forums](https://ask.libreoffice.org/)
- [UnoGenerator API](https://coolnewton.mooo.com/doxygen/unogenerator/)
- [UnoGenerator API (Doxygen)](https://coolnewton.mooo.com/doxygen/unogenerator/)
49 changes: 49 additions & 0 deletions tests/test_cleaner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

import pytest
from unittest.mock import patch, MagicMock
from unogenerator.monitor import command_cleaner
import os
import shutil

def test_command_cleaner(tmp_path):
# Mocking scandir to return our test entries
# But wait, command_cleaner uses hardcoded "/tmp"
# To test it without actually touching /tmp, we would need to mock scandir or change the function to accept a path.
# However, since it's a "cleaner", we can test it by creating specific files in /tmp if we are careful.

test_dir = "/tmp/unogenerator_pytest_dir"
test_file = "/tmp/unogenerator_pytest_file"

os.makedirs(test_dir, exist_ok=True)
with open(test_file, "w") as f:
f.write("test")

assert os.path.exists(test_dir)
assert os.path.exists(test_file)

with patch("unogenerator.monitor.run") as mock_run:
command_cleaner()

# Verify killall was called
mock_run.assert_called_with(['killall', '-9', 'soffice.bin'], check=False)

# Verify files are gone
assert not os.path.exists(test_dir)
assert not os.path.exists(test_file)

import sys

def test_cleaner_entry_point():
# Test the cleaner() function which parses args
with patch("unogenerator.monitor.command_cleaner") as mock_command:
with patch.object(sys, 'argv', ['unogenerator_cleaner']):
from unogenerator.monitor import cleaner
cleaner()
mock_command.assert_called_once()

def test_cleaner_no_files():
# Test that it doesn't crash if no files exist
with patch("unogenerator.monitor.scandir", return_value=[]):
with patch("unogenerator.monitor.run"):
command_cleaner()
# Should not raise exception
Loading
Loading