Linux - Manually Creating a Virtual Environment for LibreOffice Snap

Overview

Unlike Windows, The Snap version LibreOffice on Linux does not use embedded Python. Instead, it use the system Python3. This means Snap LibreOffice on Linux has access to full python.

Using Install Zaz-Pip LibreOffice Extension would be the recommended way to install pip and python packages in LibreOffice.

Another option is to use the Include Python Path for LibreOffice extension to add virtual environment paths to LibreOffice, this would work with all LibreOffice versions after Version 7.0 on all operating systems.

Note that this guide for of an snap installed version of LibreOffice. It does not cover the Flatpak version or the APT version. See: Linux - Manually Creating a Virtual Environment, Linux - Manually Creating a Virtual Environment using Poetry.

Note: at the time of writing this guide, the Snap version of LibreOffice is considerably slower starting up than the APT version when starting with a script.

Prerequisites

The libreoffice-script-provider-python apt package must be installed. This package allows scripts to connect to LibreOffice. On Windows this in not needed because LibreOffice embeds Python. However, on Linux LibreOffice requires it even for Snaps.

sudo apt install libreoffice-script-provider-python

Steps

Get LibreOffice Python Path

We need to know exactly where the system Python3 is located that LibreOffice Snap is using. Generally this will be /usr/bin/python3 but it is best to check. Perhaps the easiest way is to use the APSO extension for LibreOffice. See Install APSO LibreOffice Extension for more information.

Start LibreOffice Snap and open the APSO extension. In this case we are using Writer.

Tools -> Macros -> Organize python scripts

APSO Extension

Start the Python Console

APSO python console [LibreOffice]
3.10.6 (main, May 29 2023, 11:10:38) [GCC 11.3.0]
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.executable
'/usr/bin/python3'
>>>

import sys and then use sys.executable to get the path to the system Python3. In this case the system Python3 is located at /usr/bin/python3. This is the path needed to create the virtual environment.

Close the Python Console and Writer.

Create Project Directory

Create a Directory for your project.

In this case we will use a directory called myproject in the home directory.

mkdir ~/myproject
cd ~/myproject

Create Virtual Environment

In your project folder run the following command.

/usr/bin/python3 -m venv .venv

If you get an error about python3.10-venv not being installed, then install it.

sudo apt install python3.10-venv

Activate Virtual Environment

Activate the virtual environment.

source .venv/bin/activate

Install OOOENV

The virtual environment has been created but it does not yet have access to uno.py and unohelper.py which are needed to use the LibreOffice API.

For this we will use the oooenv package.

Make sure you have activated the virtual environment.

oooenv is a Python package that allows you to auto configure a virtual environment to be used by LibreOffice.

Install oooenv in the virtual environment:

python -m pip install oooenv

Now that the package is installed we can use it to configure the virtual environment to use uno.py and unohelper.py.

oooenv cmd-link -a

Now the virtual environment is configured to use uno.py and unohelper.py.

Test installed package

The Virtual Environment must be activated to use the installed packages.

source .venv/bin/activate

First we will install ooo-dev-tools.

python -m pip install ooo-dev-tools

For a test we will write a short script and run it on the command line. This simple script starts python, Loads Snap LibreOffice Calc, and writes Hello World! into the first cell. Then a message box is displayed asking if you want to close the document.

This script does a few extra things to make the virtual environment work with a snap installed version of LibreOffice.

First it gets the path to the virtual environment site packages directory in the current virtual environment. Internally the get_virtual_env_site_packages_path() function uses VIRTUAL_ENV environment variable to build up the virtual environment path. If you are running a special case where the virtual environment is not activated, set the VIRTUAL_ENV environment variable to the virtual environment path.

This is an example of a custom Build System For Sublime Text that uses the virtual environment. If you are not using Sublime Text, you can ignore this.

{
    "selector": "source.python",
    "working_dir": "$project_path",
    "env": {"PYTHONPATH":".", "VIRTUAL_ENV": "./.venv"},
    "path":"$project_path/.venv/bin:$PATH",
    "cmd": ["$project_path.venv/bin/python", "-u", "$file"],
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)"
}

The PYTHONPATH environment variable is set to include the virtual environment site-packages directory. This value is read By Snap LibreOffice to include any Python packages that are installed in the virtual environment.

By default OooDev will not look for LibreOffice in the snap directory. For this reason we need to set the soffice path to the snap directory.

Lo.ConnectSocket(soffice="/snap/bin/libreoffice", env_vars={"PYTHONPATH": py_pth})

Note

OooDev Also has an Environment Variable that can be set to the Path of LibreOffice. This is ODEV_CONN_SOFFICE. If this environment variable is set then the soffice is not needed; However, the soffice parameter will override the environment variable.

Note

Alternatively a script can be run the APSO console as seen in Test installed package.

Warning

Snap LibreOffice does not seem to allow connections if it started with a pipe connection. For this reason use Lo.ConnectSocket() to connect to Snap LibreOffice as seen in the example below.

from __future__ import annotations
import uno
from pathlib import Path
from ooodev.calc import CalcDoc
from ooodev.utils.kind.zoom_kind import ZoomKind
from ooodev.loader import Lo
from ooodev.utils import paths
from ooodev.dialog.msgbox import (
    MessageBoxType, MessageBoxButtonsEnum, MessageBoxResultsEnum
)


def main() -> int:
    py_pth = paths.get_virtual_env_site_packages_path()
    # uncomment to include current working directory in PYTHONPATH
    # py_pth += f":{Path.cwd()}"
    _ = Lo.load_office(
        Lo.ConnectSocket(soffice="/snap/bin/libreoffice", env_vars={"PYTHONPATH": py_pth})
    )
    try:
        doc = CalcDoc.create_doc(visible=True)
        Lo.delay(500)
        doc.zoom(ZoomKind.ZOOM_100_PERCENT)

        sheet = doc.sheets[0]
        sheet["A1"]value = "Hello World!"

        msg_result = doc.msgbox(
            "Do you wish to close document?",
            "All done",
            boxtype=MessageBoxType.QUERYBOX,
            buttons=MessageBoxButtonsEnum.BUTTONS_YES_NO,
        )
        if msg_result == MessageBoxResultsEnum.YES:
            doc.close()
            Lo.close_office()
        else:
            print("Keeping document open")

    except Exception:
        Lo.close_office()
        raise
    return 0


if __name__ == "__main__":
    SystemExit(main())

The resulting document should look like this:

LibreOffice Calc Hello World

The System path shows that the virtual environment site packages directory is included.

APSO python console [LibreOffice]
3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> from pprint import pprint
>>> pprint(sys.path)
['/snap/libreoffice/275/lib/libreoffice/program',
'/home/guide/myproject/.venv/lib/python3.10/site-packages',
'/snap/libreoffice/275/gnome-platform/usr/lib/python3/dist-packages',
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload',
'/home/guide/snap/libreoffice/275/.local/lib/python3.10/site-packages',
'/usr/lib/python3/dist-packages',
'/home/guide/snap/libreoffice/275/.config/libreoffice/4/user/uno_packages/cache/uno_packages/lu46534i9c.tmp_/apso.oxt/python/pythonpath']
>>>