Working with LibreOffice in Python

Version used

Overview

To operate LibreOffice with Python

  1. Launch a Python macro from the LibreOffice GUI.
  2. Start the Python macro specified by the parameter when starting LibreOffice from the command line.
  3. Launch a Python program from the command line and connect to the launched LibreOffice.

There are three methods.

The first method requires GUI operation, so batch processing from the program cannot be performed. The operator responds to any errors.

The second method can be used for batch processing because LibreOffice will be closed after the macro is finished. When an error occurs, LibreOffice displays a dialog and waits, and the program cannot handle it. Considering possible errors, it is necessary to take measures such as setting a time limit in timeout-decorator. Also, if there is LibreOffice that has already been started when LibreOffice is started, processing will be performed there, so it may not be possible to control as expected.

The third method is to specify the --accept switch to LibreOffice in advance so that it can be connected with a socket or a named pipe and start it. With this method, if LibreOffice is started first, the process will be performed there, so it may not be possible to control as expected. I could use it on Microsoft Windows, but on FreeBSD I get an error when connecting and cannot run it.

Python processing system

Microsoft Windows

In Microsoft Windows, LibreOffice comes with a Python processor% PROGRAMFILES% \ LibreOffice \ program \ python.exe, which is automatically used for macros. Even when connecting from the command line, it is necessary to use the Python processing system that comes with LibreOffice. The Python version that comes with LibreOffice 6.3.6 is 3.5.9.

The library is installed in% PROGRAMFILES% \ LibreOffice \ program \ python-core-3.5.9 \ lib. There is also a site-packages subfolder, which goes through sys.path, but only has a README file. Package installation is not easy due to lack of pip. From Installation of pip site You can install it by downloading and running get-pip.py, but if you run it with personal account privileges % PROGRAMFILES% \ LibreOffice \ program \ python-core-3.5.9 \ lib \ site-packages is not writable It is installed in% APPDATA% \ Roaming \ Python \ Python35 \ site-packages under the user's profile.

C:\Users\shota243>cd Downloads
C:\Users\shota243\Downloads>"c:\Program Files\LibreOffice\program"\python get-pip.py
Defaulting to user installation because normal site-packages is not writeable
Collecting pip
  Downloading pip-20.1.1-py2.py3-none-any.whl (1.5 MB)
     |################################| 1.5 MB 1.3 MB/s
Collecting setuptools
  Downloading setuptools-47.1.1-py3-none-any.whl (583 kB)
     |################################| 583 kB 6.8 MB/s
Collecting wheel
  Downloading wheel-0.34.2-py2.py3-none-any.whl (26 kB)
Installing collected packages: pip, setuptools, wheel
  WARNING: The scripts pip.exe, pip3.5.exe and pip3.exe are installed in 'C:\Users\shota243\AppData\Roaming\Python\Python35\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The scripts easy_install-3.5.exe and easy_install.exe are installed in 'C:\Users\shota243\AppData\Roaming\Python\Python35\Scripts' which is not on PATH.

  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script wheel.exe is installed in 'C:\Users\shota243\AppData\Roaming\Python\Python35\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-20.1.1 setuptools-47.1.1 wheel-0.34.2

pip.exe is also installed in% APPDATA% \ Roaming \ Python \ Python35 \ Scripts, but you have to set it yourself to put this folder in the PATH and% PROGRAMFILES% to run pip.exe Considering that \ LibreOffice \ program \ python35.dll is required, it is also necessary to deal with the DLL search path.

%PROGRAMFILES%\LibreOffice\program\python -m pip

It may be easier to start with. Packages installed with pip are also installed in% APPDATA% \ Roaming \ Python \ Python35 \ site-packages, but they can be used as they are because sys.path is available.

C:\Users\shota243>"c:\Program Files\LibreOffice\program"\python -m pip install timeout-decorator
Defaulting to user installation because normal site-packages is not writeable
Collecting timeout-decorator
  Downloading timeout-decorator-0.4.1.tar.gz (4.8 kB)
Building wheels for collected packages: timeout-decorator
  Building wheel for timeout-decorator (setup.py) ... done
  Created wheel for timeout-decorator: filename=timeout_decorator-0.4.1-py3-none-any.whl size=5022 sha256=5d3ecc37c619ed429c313b18ddf3b01b309d43dccc65d19ce974df
76af478609
  Stored in directory: c:\users\shota243\appdata\local\pip\cache\wheels\df\f4\3c\031226c90008861114781e36ef5898934aad3196808c40e6ea
Successfully built timeout-decorator
Installing collected packages: timeout-decorator
Successfully installed timeout-decorator-0.4.1

If you run get-pip.py with administrator privileges, you can install pip in a folder under% PROGRAMFILES% and share it on your system. Other packages can be installed under% PROGRAMFILES% as well. However, the% PROGRAMFILES% \ LibreOffice folder may be deleted when LibreOffice is updated, and it may be necessary to take action.

FreeBSD

In the case of FreeBSD, even if LibreOffice does not come with a Python processing system and it is a macro, Python that is in the PATH is used. Packages installed with pip can also be used from macros. If you start LibreOffice in a virtual environment, you can use different Python versions and packages.

UNO

Use UNO (Universal Network Objects) to operate LibreOffice programmatically. UNO is a language-independent component model that uses Python-UNO bridge (PyUNO-bridge) when used from Python. .. Use the Python-UNO bridge as well, whether from a macro or an external connection.

Python macro

Placement of Python macros

LibreOffice has neither the ability to edit Python macros nor the ability to launch editors. Create a Python macro separately and place it in the following directory.

For Microsoft Windows

--User macro

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

--System shared macro

%PROGRAMFILES%\LibreOffice\share\Scripts\python

For FreeBSD or UNIX-like systems

--User macro

${HOME}/.config/libreoffice/4/user/Scripts/python

--System shared macro

/usr/local/lib/libreoffice/share/Scripts/python

The directory for user macro placement does not exist from the beginning, so create it yourself if necessary.

APSO --Alternative Script Organizer for Python Extension

APSO --Alternative Script Organizer for Python After installing the extension, you can:

--Launch Python interpreter console --Using the GUI Debugger --Launch the editor from LibreOffice and edit the macro --Embedding Python macros in documents

This makes it possible to edit without being aware of the macro layout. You can also try accessing the UNO from the Python interpreter.

XSCRIPTCONTEXT global variable

XSCRIPTCONTEXT global variables can be referenced from Python macros. From XSCRIPTCONTEXT, you can access the environment where the macro is started by the following method.

XSCRIPTCONTEXT is an implementation of the XScriptContext interface, As a global variable of Python, it is an instance of the pythonscript.ScriptContext class.

>>> type(XSCRIPTCONTEXT)
<class 'pythonscript.ScriptContext'>

The class definition is in the /usr/local/lib/libreoffice/program/pythonscript.py file.

Invoking macros from the command line

The command line to specify macros when starting LibreOffice is as follows

soffice 'vnd.sun.star.script:<Script file name>$<Function name>?language=Python&location=user'

This will run the macro and exit LibreOffice. If the macro doesn't need to show the screen, turn on the --headless switch and the screen won't show. If an error occurs during macro execution, an error dialog will be displayed to request user confirmation, but if --headless is specified, the dialog will not be displayed and the hang will occur.

Example:

mymacro.py


def macrofunc():
    pass

To start without screen display

$ soffice --headless 'vnd.sun.star.script:mymacro.py$macrofunc?language=Python&location=user'

Connection from Python launched from the command line

Launch LibreOffice

To receive an external connection, specify the --accept switch in LibreOffice in advance and start it. For socket connection

$ soffice  "--accept=socket,host=<Host designation>,port=<port number>;urp;"

For named pipe connection

$ soffice "--accept=pipe,name=<Named pipe name>;urp;"

In both cases, UNIX-like OS shells treat semicolons (;) as command delimiters, so they need to be quoted.

Example:

$ soffice --writer "--accept=socket,host=0,port=2002;urp;"
$ soffice --calc --headless "--accept=pipe,name=librepipe;urp;"

In the example page Python-UNO bridge

"-accept=socket,host=localhost,port=2002;urp;"

And the "accept" has a single minus sign, which is the old notation and the current notation is to write two. Also, in the same example, the program inserts the "Hello, World" character string into the Writer document, but since the document is not newly created in the program, if it is executed as it is, an error will occur when accessing the text property. If you create a new document with the --writer switch when you start LibreOffice, that document will be used.

Connection from a Python program

In the Python program, the parameter of the --accept option switch when LibreOffice is started is specified when the resolver (com.sun.star.bridge.UnoUrlResolver instance) resolves the connection destination on the side connecting the same character string. Since host is the partner host name, different values will be specified.

Once you connect to LibreOffice and get the Context, you can use it to create a Desktop instance and an instance of the ScriptContext class to replace the XSCRIPTCONTEXT global variable in your macro. The third argument of the constructor of the ScriptContext class is the invocation context, but it can be NULL according to the XScriptContext Interface Documentation. Specify None.

import uno
from pythonscript import ScriptContext

def connect_script_context(host='localhost', port='2002', namedpipe=None):
    UNO_RESOLVER = "com.sun.star.bridge.UnoUrlResolver"
    UNO_DESKTOP = "com.sun.star.frame.Desktop"
    localCtx = uno.getComponentContext()
    localSmgr = localCtx.ServiceManager
    resolver = localSmgr.createInstanceWithContext(UNO_RESOLVER, localCtx)
    if namedpipe is None:
        uno_string = 'uno:socket,host=%s,port=%s;urp;StarOffice.ComponentContext' % (host, port)
    else:
        uno_string = 'uno:pipe,name=%s;urp;StarOffice.ComponentContext' % namedpipe
    ctx = resolver.resolve(uno_string)
    smgr = ctx.ServiceManager
    XSCRIPTCONTEXT = ScriptContext(ctx,
                                   smgr.createInstanceWithContext(UNO_DESKTOP, ctx),
                                   None)
    return XSCRIPTCONTEXT

Simulate the case of a macro by assigning the return value of this connect_script_context () function to the XSCRIPTCONTEXT global variable.

Settings and errors for FreeBSD

When connecting to LibreOffice from FreeBSD or a UNIX-like system, the Python program under / usr / local / lib / libreoffice / program is imported and the dynamic link library in the same location is also used, so LD_LIBRARY_PATH is used in addition to PYTHONPATH. Also pass environment variables.

export PYTHONPATH="${PYTHONPATH}:/usr/local/lib/libreoffice/program"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/local/lib/libreoffice/program"
export PATH="${PATH}:/usr/local/lib/libreoffice/program"

When I actually connect, I can connect and get the ComponentContext, but I get an error when I try to get the Desktop.

>>> import uno
import uno
>>> localContext = uno.getComponentContext()
localContext = uno.getComponentContext()
>>> resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
<reateInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
>>> ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
>>> smgr = ctx.ServiceManager
smgr = ctx.ServiceManager
>>> desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop",ctx)
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop",ctx)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
__main__.RuntimeException: Binary URP bridge disposed during call

Recommended Posts

Working with LibreOffice in Python
Working with LibreOffice in Python: import
Working with sounds in Python
Working with DICOM images in Python
Try working with binary data in Python
Post Test 3 (Working with PosgreSQL in Python)
Try working with Mongo in Python on Mac
[Introduction for beginners] Working with MySQL in Python
Scraping with selenium in Python
Scraping with chromedriver in python
Debugging with pdb in Python
Python: Working with Firefox with selenium
Scraping with Selenium in Python
Scraping with Tor in Python
Tweet with image in Python
Combined with permutations in Python
Specific sample code for working with SQLite3 in Python
Number recognition in images with Python
Testing with random numbers in Python
GOTO in Python with Sublime Text 3
Scraping with Selenium in Python (Basic)
CSS parsing with cssutils in Python
Numer0n with items made in Python
Open UTF-8 with BOM in Python
Use rospy with virtualenv in Python3
Use Python in pyenv with NeoVim
Heatmap with Dendrogram in Python + matplotlib
Read files in parallel with Python
Password generation in texto with python
Use OpenCV with Python 3 in Window
Until dealing with python in Atom
Get started with Python in Blender
Quadtree in Python --2
Python in optimization
CURL in python
FizzBuzz with Python3
Metaprogramming in Python
Spiral book in Python! Python with a spiral book! (Chapter 14 ~)
Python 3.3 in Anaconda
Geocoding in python
SendKeys in Python
Scraping with Python
Try logging in to qiita with Python
Stress Test with Locust written in Python
Python3> in keyword> True with partial match?
Statistics with python
Device monitoring with On-box Python in IOS-XE
Meta-analysis in Python
Unittest in python
Scraping with Python
Python with Go
Draw Nozomi Sasaki in Excel with python
Tips for dealing with binaries in Python
Display Python 3 in the browser with MAMP
Page cache in Python + Flask with Flask-Caching
Twilio with Python
Epoch in Python
Discord in Python
Integrate with Python
How to work with BigQuery in Python
Playing card class in Python (with comparison)