Skripte programmieren für LibreOffice – Teil 1

LibreOffice-Makros mit Python

LibreOffice-Makros mit Python

Skripte programmieren für LibreOffice – Teil 1

LibreOffice-Makros mit Python


Unter Berücksichtigung technischer und anderer Faktoren betragen die Durchschnittskosten eines Softwareprojekts im Schnitt zwischen 70 000 und 250 000 US-Dollar [1]. Die Kosten können reduziert werden, wenn nicht alles komplett aus dem Boden gestampft wird. So lässt sich die Office-Suite LibreOffice mit Hilfe der Makrosprache BASIC beliebig erweitern.

Neue Features werden mit Hilfe von Makros oder Dialogfenstern in LibreOffice implementiert. Die Suite verfügt zwar über eine eigene IDE, um damit Makros in der Programmiersprache BASIC zu erstellen, doch für in Python geschriebene Makros funktioniert sie nicht [2]. Stattdessen kommt als Entwicklungsumgebung der gewohnte Editor oder die IDE infrage, mit der ohnehin unter Python programmiert wird.

In der Dokumentation von LibreOffice wird auf Routinen Bezug genommen, die im Grunde genommen Makros im eigentlichen Sinne sind. Makros beziehungsweise Routinen werden in LibreOffice mit Hilfe von Modulen organisiert, wobei in einem Modul nicht nur Funktionen, sondern auch Konstanten oder globale Variablen definiert sind. Module, die logisch zusammenhängen, befinden sich in einer Bibliothek (Library). An oberster Stelle der LibreOffice-Organisation steht der Library-Container, der die eigenen Bibliotheken beherbergt. So entspricht das gerade geöffnete LibreOffice-Dokument einem Library-Container.

Makros lassen sich für ein spezifisches LibreOffice-Dokument erstellen. Der Vorteil ist, dass das Makro mit dem Dokument verknüpft bleibt, sodass es nach dem Öffnen des Dokuments unmittelbar ausgeführt werden kann. Falls mehrere Dokumente auf das Makro zugreifen, verfügt jedes Dokument über eine Kopie davon, was dazu führt, dass bei Änderungen eines Dokuments unterschiedliche Versionen des Makros im Umlauf sind. Hierfür eignet sich die Speicherung des Makros im Library-Container, der bei der Installation von LibreOffice auf der eigenen Festplatte angelegt wird [3].

Für die geläufigen Betriebssysteme sind jeweils zwei Pfade von Interesse, wobei diese sich von Betriebssystem zu Betriebssystem unterscheiden. LibreOffice erkennt Makros beim Starten der Anwendung, wenn diese sich entweder im Speicherort des Benutzers befinden oder in der systemweiten Installation abgelegt sind (Tabelle 1).

Betriebssystem

Pfad

Einsatzzweck

Linux

~/.config/libreoffice/4/user/Scripts/python

benutzerspezifisch

/usr/lib64/libreoffice/share/Scripts/python

systemweit

macOS

/Users/<Benutzer>/Library/Application\ Support/LibreOffice/4/user/Scripts/python

benutzerspezifisch

-

-

Windows

C:\Users\<user>\AppData\Roaming\LibreOffice\4\user\Scripts\python

benutzerspezifisch

%APPDATA%\LibreOffice\4\user\Scripts\python

systemweit

Tabelle 1: Wo Makros gespeichert werden

Der Zugriff auf die LibreOffice-Tools geschieht unter Python mittels der Bibliothek PyUNO [4]. PyUNO kann als Abkürzung zum LibreOffice-API aufgefasst werden, das über die folgenden Features verfügt:

  • Zugriff auf das Standard-OpenOffice-API innerhalb von Python

  • Entwicklung von UNO-Komponenten mit Python, die sich in einem LibreOffice-Dokument ausführen lassen

  • Erstellen und Ausführen von Skripten mit dem Office-Skripting-Framework OOo 2.0 oder höher

PyUNO wird während der Installation von LibreOffice bereitgestellt und landet unter Linux im Ordner /usr/lib64/libreoffice/program.

Neben der offiziellen Dokumentation existiert speziell zum Erlernen der Makrosprache BASIC Andrew Pitonyaks E-Book. Die vom LibreOffice-API zur Verfügung gestellten Schnittstellen, Klassen und Methoden sind auch unter PyUNO verfügbar, wobei sich die Schreibweise zum Teil nur minimal voneinander unterscheidet [5]:

# Basic
oCursor.paraStyleName
# PyUNO
oCursor.ParaStyleName

Im einfachsten Fall lässt sich auf die Attribute einer Klasse wie im Beispiel oben durch die Änderung der Groß- und Kleinschreibung zugreifen. Dasselbe gilt auch für die verfügbaren Methoden, die im Grunde dieselben sind, außer dass ihr Aufruf unter Python aus dem API durch Voranstellung von get beziehungsweise set bevorzugt wird:

# Basic
oDoc.Sheets.insertNewByName(name,0)
# PyUNO
oDoc.getSheets().insertNewByName(name,0)

Speziell für die Umstellung von Basic auf PyUNO existiert eine Wiki-Seite, die nicht nur die Erstellung von LibreOffice-Erweiterungen in Python behandelt, sondern auch weitere Codebeispiele liefert [6]. Darüber hinaus verfügt die Hilfsbibliothek Unotools in der Version 0.3.3 über einen vereinfachten Zugriff auf vorhandene und neue Dokumente [7]. Sofern benutzerspezifische Makros zum Einsatz kommen, ist es sinnvoll, Unotools für den Benutzer oder Entwickler, der die Makros schließlich ausführt, über $ pip install unotools --user zu installieren.

Ohne diese Hilfsbibliothek weicht der Zugriff auf das aktuell geöffnete Dokument sehr von Basic ab, weshalb zusätzlich die erwähnte Wiki-Seite für weitere Informationen herangezogen werden muss. Deshalb ist es ratsam, die eigenen Python-Skripte in den Ordnern abzulegen beziehungsweise mit den Ordnern zu verlinken, die in Tabelle 1 genannt sind. Dadurch wird garantiert, dass sich PyUNO in das Python-Skript importieren lässt.

Der Zugriff auf PyUNO erfolgte in unserer Testumgebung unter Fedora 40 automatisch. Es gibt jedoch Distributionen, die die Installation zusätzlicher Pakete voraussetzen. Der Code, der in unserer Testumgebung im Folgenden eingesetzt wird, ist zu Python 3.12.3 und der LibreOffice-Version 24.2.3.2 kompatibel.

Die ersten Schritte

Für die Erstellung von Makros mit Hilfe von Python ist dieselbe Dateiendung relevant wie bei allen anderen Python-Skripten, nämlich .py. In Listing 1 kommen die wichtigsten Importe vor, die zum Öffnen eines LO-Calc-Dokuments mit der Endung .ods erforderlich sind. Darin wird mit Hilfe der Funktion load_calc_document ein leeres Calc-Dokument geladen und als Objekt zurückgegeben.

Listing 1

from unotools import Socket, connect
from unotools.component.calc import Calc
# Aktuell geöffnetes Calc-Dokument laden
def load_calc_document():
  context = connect(Socket('localhost', 8100))
  calc = Calc(context)
  return calc

In Anlehnung an BASIC wird das Objekt, das auf das Dokument zeigt, üblicherweise oDoc genannt (Listing 2), wobei es sich genauso gut unter einem x-beliebigen Namen referenzieren lässt. Um ein Arbeitsblatt zu bearbeiten, wird in diesem Fall auf das aktive Arbeitsblatt zurückgegriffen und es wird in der Variable oSheet abgelegt. Danach erfolgt das Laden der ersten Zelle innerhalb des geöffneten Arbeitsblatts, indem über die folgende Methode darauf zugegriffen wird. Bei Basic kann auf eine Zelle zugegriffen werden, wenn die Spalten und Zeilen in Ziffern angegeben werden:

oCell = oSheet.getCellByPosition(<Spalte>, <Zeile>)

Die geladene Zelle wird bei Texten beziehungsweise Strings durch den Einsatz des Attributs String beschrieben, indem der Zelle der Text aus Listing 2 zugewiesen wird (Abb. 1).

Listing 2

def HelloWorldPythonCalc():
  # lädt das aktive aktive Arbeitsblatt
  oDoc = load_calc_document()
  oSheet = oDoc.CurrentController.ActiveSheet
  # in Zelle 'A1' wechseln
  oCell = oSheet.getCellByPosition(0, 0)
  # String in abgerufener Zelle ablegen
  oCell.String = 'Hello World via Python'
  return None
minosi_skriptprogrammierung_1_1

Abb. 1: Ausfüllen der ersten Zelle via Makro

Makros können auf verschiedene Arten gestartet werden. Eine davon ist der Aufruf des Makros auf der LibreOffice-Oberfläche, indem zunächst die von LibreOffice entdeckten Python-Skripte unter Tools | Macros | Organize Macros | Python aufgerufen werden. Anschließend wird im Fenster Macros innerhalb der eigenen Bibliothek My Macros des jeweiligen Benutzers die entsprechende Funktion markiert und auf Run geklickt (Abb. 2).

minosi_skriptprogrammierung_1_2

Abb. 2: Von LibreOffice erkannte Makros des jeweiligen Benutzers

Fallbeispiel: Preiskalkulation

Darüber hinaus lässt sich ein Python-Makro auf der Konsole ausführen, indem der folgende Arbeitsablauf auf fortgeschrittene Makros angewandt wird:

  1. LibreOffice auf der Konsole starten:

    $ soffice --accept='socket,host=localhost,port=8100;urp;StarOffice.Service'
    
  2. Im Python-Skript die Bibliotheken Unotools sowie Uno importieren

  3. Das Python-Skript mit Hilfe des Befehls python -m <Skriptname> auf der Konsole ausführen

Bei bestehenden Dokumenten kann mittels der Funktion open_calcdocument ein Calc-Dokument in Python geladen und als Objekt zurückgegeben werden (Listing 3). Im zweiten Makro wird damit eine Preiskalkulation geöffnet, um das günstigste Computersystem zu...