Skip to content

Instantly share code, notes, and snippets.

@Amourspirit
Last active June 10, 2023 20:04
Show Gist options
  • Save Amourspirit/1540a52f21c020a8190b468a3e9efc16 to your computer and use it in GitHub Desktop.
Save Amourspirit/1540a52f21c020a8190b468a3e9efc16 to your computer and use it in GitHub Desktop.
Start the LibreOffice (FlatPak) in a virtual environment.
"""
This module is used to start the LibreOffice (FlatPak) in a virtual environment.
When this script is run, it will start the LibreOffice (FlatPak) and include
the virtual environment's site-packages directory in the PYTHONPATH.
In short when this module is included in the root of a project with a virtual environment
then the LibreOffice (FlatPak) will be able to import the project's modules installed with pip.
Usage:
python office.py [options] [app]
Examples:
python office.py --nologo writer
Known Issues:
The --minimized option does not work (at least not when I tested).
See:
https://gist.github.com/Amourspirit/1540a52f21c020a8190b468a3e9efc16
"""
from __future__ import annotations
from typing import List, Union
import argparse
import os
import sys
from pathlib import Path
from subprocess import Popen
# region Get Virtual Environment Location
def _get_root_dir() -> Path:
return Path(_get_virtual_env()).parent
def _get_virtual_env() -> Path:
"""
Gets the Virtual Environment for current python environment.
Raises:
FileNotFoundError: If no virtual environment is found.
Returns:
Path: Viruatl Environment path such as ``/home/user/my_project/.venv``.
"""
env = os.getenv("VIRTUAL_ENV", "")
if env:
return Path(env)
current_dir = Path(__file__).parent
if (current_dir / ".venv").exists():
return current_dir / ".venv"
if (current_dir / "venv").exists():
return current_dir / "venv"
if (current_dir / "env").exists():
return current_dir / "env"
raise FileNotFoundError("No Virtual Environment Found")
def _get_site_packages_dir() -> Union[Path, None]:
"""
Gets the ``site-packages`` directory for current python environment.
Returns:
Union[Path, None]: site-packages dir if found; Otherwise, None.
"""
v_path = _get_virtual_env()
p_site = v_path / "Lib" / "site-packages"
if p_site.exists() and p_site.is_dir():
return p_site
ver = f"{sys.version_info[0]}.{sys.version_info[1]}"
p_site = v_path / "lib" / f"python{ver}" / "site-packages"
if p_site.exists() and p_site.is_dir():
return p_site
return None
# endregion Get Virtual Environment Location
# region Manage Arguments
def _add_args(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--invisible",
action="store_true",
default=False,
help="""Starts in invisible mode. Neither the start-up logo nor
the initial program window will be visible. Application
can be controlled, and documents and dialogs can be
controlled and opened via the API. Using the parameter,
the process can only be ended using the taskmanager
(Windows) or the kill command (UNIX-like systems). It
cannot be used in conjunction with --quickstart. """,
)
parser.add_argument(
"--nologo", action="store_true", default=False, help="Disables the splash screen at program start."
)
parser.add_argument(
"--minimized", action="store_true", default=False, help="Starts minimized. The splash screen is not displayed."
)
parser.add_argument(
"--norestore",
action="store_true",
default=False,
help="enables restart and file recovery after a system crash.",
)
parser.add_argument(
"--headless",
action="store_true",
default=False,
help="""Starts in "headless mode" which allows using the
application without GUI. This special mode can be used
when the application is controlled by external clients
via the API.""",
)
parser.add_argument("app", choices=["writer", "calc", "draw", "impress", "math", "base", 'global", "web', "none"])
parser.add_argument(
"--path-no-root", action="store_true", default=False, help="If set then the root path is not included in PYTHONPATH."
)
def _update_args(args: argparse.Namespace, args_lst: List[str]) -> None:
if args.invisible:
args_lst.append("--invisible")
if args.norestore:
args_lst.append("--norestore")
if args.nologo:
args_lst.append("--nologo")
if args.minimized:
args_lst.append("--minimized")
if args.headless:
args_lst.append("--headless")
if args.app != "none":
args_lst.append(f"--{args.app}")
# endregion Manage Arguments
def main() -> None:
parser = argparse.ArgumentParser(description="Office")
_add_args(parser)
args = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help(sys.stderr)
sys.exit(1)
python_path = str(_get_site_packages_dir())
if args.path_no_root is False:
python_path += f":{_get_root_dir()}"
open_args = [
"flatpak",
f'--env=PYTHONPATH="{python_path}"',
"run",
"org.libreoffice.LibreOffice/x86_64/stable",
"--nofirststartwizard",
]
_update_args(args, open_args)
# display is included because of this issue when it is omitted:
# Set DISPLAY environment variable, use -display option
# or check permissions of your X-Server
# (See "man X" resp. "man xhost" for details)
open_args.append(f"--display {os.getenv('DISPLAY', ':0')}")
# print(" ".join(open_args))
Popen(" ".join(open_args), shell=True)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment