Of course! Using Python with LibreOffice is a powerful way to automate tasks, create custom reports, and extend the functionality of LibreOffice. The primary method for this is through UNO (Universal Network Objects), which is the component model used by LibreOffice and its sibling, OpenOffice.

Here's a comprehensive guide covering the concepts, setup, and practical examples.
What is UNO?
Think of UNO as the "nervous system" of LibreOffice. It's a programming language-neutral interface that allows different applications to communicate with each other and control each other's objects. When you use Python to control LibreOffice, you are using Python to send UNO commands to the LibreOffice process.
The Two Main Approaches
There are two primary ways to use Python with LibreOffice:
- External Script (Most Common & Recommended): You write a Python script on your computer (e.g.,
my_script.py). This script starts a hidden LibreOffice process in the background, connects to it via UNO, performs actions, and then closes LibreOffice. This is great for automation tasks like batch processing documents. - Macros (Embedded in the Document): You write Python code directly inside a LibreOffice document (
.ods,.odt, etc.) as a macro. This code runs when the user triggers it (e.g., via a button or a menu item). This is ideal for adding interactive features to a specific document.
We will focus on the External Script approach as it's more versatile for automation.

Setup: Prerequisites
You need two things installed:
- Python: A standard Python installation on your system.
- LibreOffice: A full installation of LibreOffice. The "portable" versions might not work correctly for this.
The Crucial Part: The uno Package
The uno package is not a standard Python package you install with pip. It's bundled with your LibreOffice installation. Your Python script needs to be able to find it.
How to find the path:
The uno module is located in a subdirectory of your LibreOffice installation. The path looks something like this:
- Windows:
C:\Program Files\LibreOffice\program\python-core-3.8\lib\python3.8 - Linux:
/usr/lib/libreoffice/program/python-core-3.8/lib/python3.8 - macOS:
/Applications/LibreOffice.app/Contents/Resources/program/python-core-3.8/lib/python3.8
You need to add this path to your PYTHONPATH environment variable so Python can find it.

Example 1: Creating a New Spreadsheet and Writing Data
This is the "Hello, World!" of LibreOffice automation. It will start LibreOffice, create a new Calc (spreadsheet) document, write some data into cells, and save the file.
Step 1: Create the Python Script (create_spreadsheet.py)
import os
import uno
import unohelper
# --- Configuration ---
# IMPORTANT: Change this path to your LibreOffice installation
# The path should point to the 'python-core-...' directory.
LO_PYTHON_PATH = r"C:\Program Files\LibreOffice\program\python-core-3.8\lib\python3.8"
# Path to the soffice executable (the main LibreOffice program)
SOFFICE_EXECUTABLE = r"C:\Program Files\LibreOffice\program\soffice.exe"
# Output file path
OUTPUT_FILE = r"C:\path\to\your\output\my_new_spreadsheet.ods"
def main():
# Add the LibreOffice Python path to sys.path
# This allows Python to import the 'uno' module
import sys
if LO_PYTHON_PATH not in sys.path:
sys.path.insert(0, LO_PYTHON_PATH)
# Now we can import the uno module
import uno
# Start the LibreOffice headless process
# The 'headless' part means no GUI will be shown.
# 'accept' is a security setting that allows the script to connect.
# 'norestore' prevents LibreOffice from restoring previous sessions.
# 'pipe' is a connection method.
command = [
SOFFICE_EXECUTABLE,
"--headless",
"--accept=socket,host=localhost,port=2002;urp;StarOffice.ServiceManager",
"--norestore"
]
# Start the process in the background
import subprocess
subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Connect to the running LibreOffice instance
local_context = uno.getComponentContext()
resolver = local_context.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", local_context
)
# This is the connection string. It might take a few seconds to connect.
context = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager")
desktop = context.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)
# Create a new spreadsheet document
# 'com.sun.star.sheet.SpreadsheetDocument' is the type for Calc
doc = desktop.loadComponentFromURL("private:factory/scalc", "_blank", 0, ())
# Get the first sheet
sheets = doc.getSheets()
sheet = sheets.getByIndex(0)
sheet.setName("Sales Data")
# Write data to cells
# Cell addressing is 0-based
sheet.getCellByPosition(0, 0).setString("Product")
sheet.getCellByPosition(1, 0).setString("Q1 Sales")
sheet.getCellByPosition(0, 1).setString("Laptop")
sheet.getCellByPosition(1, 1).setString("150")
sheet.getCellByPosition(0, 2).setString("Mouse")
sheet.getCellByPosition(1, 2).setString("250")
# Save the document
# The URL must be in file:/// format
save_url = uno.systemPathToFileUrl(OUTPUT_FILE)
doc.storeToURL(save_url, ())
# Close the document without saving changes again (storeToURL already did)
doc.close(True)
print(f"Spreadsheet created successfully at: {OUTPUT_FILE}")
if __name__ == "__main__":
main()
Step 2: Run the Script
- Modify the paths in the script (
LO_PYTHON_PATH,SOFFICE_EXECUTABLE,OUTPUT_FILE) to match your system. - Open your command prompt or terminal.
- Navigate to the directory where you saved
create_spreadsheet.py. - Run the script:
python create_spreadsheet.py
You should see a new file named my_new_spreadsheet.ods appear at the specified location.
Example 2: Reading Data from an Existing Spreadsheet
This script will open an existing spreadsheet, read data from a specific cell, and print it to the console.
Step 1: Create the Python Script (read_spreadsheet.py)
import os
import uno
import unohelper
import subprocess
# --- Configuration ---
LO_PYTHON_PATH = r"C:\Program Files\LibreOffice\program\python-core-3.8\lib\python3.8"
SOFFICE_EXECUTABLE = r"C:\Program Files\LibreOffice\program\soffice.exe"
INPUT_FILE = r"C:\path\to\your\output\my_new_spreadsheet.ods" # Use the file from the previous example
def main():
# Setup PYTHONPATH
import sys
if LO_PYTHON_PATH not in sys.path:
sys.path.insert(0, LO_PYTHON_PATH)
# Start LibreOffice headless process
command = [
SOFFICE_EXECUTABLE,
"--headless",
"--accept=socket,host=localhost,port=2002;urp;StarOffice.ServiceManager",
"--norestore"
]
subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Connect to LibreOffice
local_context = uno.getComponentContext()
resolver = local_context.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", local_context
)
context = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager")
desktop = context.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)
# Open the existing document
file_url = uno.systemPathToFileUrl(INPUT_FILE)
doc = desktop.loadComponentFromURL(file_url, "_blank", 0, ())
# Get the first sheet
sheet = doc.getSheets().getByIndex(0)
# Read data from cell B2 (which is at position 1, 1)
cell_value = sheet.getCellByPosition(1, 1).getString()
print(f"The value in cell B2 is: {cell_value}")
# Close the document
doc.close(True)
print("Script finished.")
if __name__ == "__main__":
main()
Step 2: Run the Script
python read_spreadsheet.py
Expected Output:
The value in cell B2 is: 150
Script finished.
Important Considerations and Best Practices
- Performance: Starting LibreOffice for every script is slow. For batch processing, it's much more efficient to start LibreOffice once in a persistent headless mode and have your script connect to it. You can even run a LibreOffice instance as a service.
- Error Handling: Always wrap your UNO calls in
try...exceptblocks. If LibreOffice isn't running or the path is wrong, your script will fail with acom.sun.star.connection.NoConnectExceptionor similar. - Documentation: The best documentation for UNO is the API reference itself. It can be dense, but it's the ultimate source of truth.
- LibreOffice API Documentation: https://api.libreoffice.org/
- Search for services like
com.sun.star.sheet.SpreadsheetDocument,com.sun.star.table.CellRange, etc.
- LibreOffice Basic: You can also record macros in LibreOffice using its built-in Basic language. This is a great way to learn the UNO object names and methods. You can then translate the recorded Basic code into Python.
Advanced Topic: Using Python Macros (Embedded)
To run Python code inside a LibreOffice document:
- Enable Python Macros:
- Go to
Tools -> Options -> LibreOffice -> Advanced. - Check the box for
Enable macros support. - Select
Show security warning for macrosorConfirm opening macros.
- Go to
- Create a Python Module:
- Go to
Tools -> Macros -> Organize Python Macros -> LibreOffice Basic.... - This opens the Macro Organizer. In the "Python" tab, you can create a new library and module.
- Give your module a name, e.g.,
MyDocumentMacros.
- Go to
- Write the Code:
- The IDE will open. You can now write your Python code. The global
XSCRIPTCONTEXTvariable is automatically provided, which gives you access to the document, desktop, etc.
- The IDE will open. You can now write your Python code. The global
Example Embedded Macro Code:
# This code would be inside your MyDocumentMacros.py module
def hello_world_macro():
"""
This is a simple macro that creates a message box.
"""
doc = XSCRIPTCONTEXT.getDocument()
desktop = XSCRIPTCONTEXT.getDesktop()
# Get the first sheet of the current document
sheet = doc.getSheets().getByIndex(0)
sheet.getCellByPosition(0, 4).setString("Hello from a Python Macro!")
# Create a message box
toolkit = desktop.getToolkit()
msgbox = toolkit.createMessageBox(
doc.getCurrentController().getFrame(),
"com.sun.star.awt.MessageBoxType.INFO",
1,
"Python Macro",
"The macro has run successfully!"
)
msgbox.execute()
# This line makes the function callable from LibreOffice's macro dialog
g_exportedScripts = hello_world_macro,
After saving this, you can run it from Tools -> Macros -> Run Macro....
