Python IDE Basics

From The Document Foundation Wiki
Jump to: navigation, search

Preamble

This page presents the steps enabling to develop LibreOffice Python macros within an Integrated Development Environment (IDE). Configuration or preferences setup are presented for a limited set of free and open source (FOSS) IDEs. Direct editing and testing of Python macros within LibreOffice requires solely the Alternative Python Script Organizer (APSO) extension. In which case Start, Connect, & Stop chapter content can be skipped.

( ... Documents, Configuration, Object Inspection ... )

Useful LibreOffice Packs

For those wishing to explore cross-compatibility:

IDE Project Setup

Each IDE requires a different configuration or setup.

Geany

Libreoffice or OpenOffice embedded Python interpreters require to be defined explicity in Geany Projects - Properties - Build dialogs:

Example values:

  • MacOS
    • P1. Compile = /Applications/LibreOffice.app/Contents/Resources/python -m py_compile "%f"
    • E1. Execute = /Applications/LibreOffice.app/Contents/Resources/python "%f"
  • Linux
    • P1. Compile = opt/openoffice4/program/python -m py_compile "%f"
    • E1. Execute = opt/openoffice4/program/python "%f"
  • Windows
    • Python commands
      • 1. Compile = "D:\Program Files\LibreOffice 5\program\python" -m py_compile "%f"
      • 2. Interpret = "D:\Program Files\LibreOffice 5\program\python"
    • Execute commands
      • 1. Execute = "D:\Program Files\LibreOffice 5\program\python" "%f"
      • 2. Unit Tests = "D:\Program Files\LibreOffice 5\program\python" -m unittest discover

Pyzo

Pyzo configuration dialog for embedded Python interpreters as of Shell - Edit shell configurations... menu:
Pyzo - Shell - Shell configurations...

PyCharm

LibreOffice Python interpreter configuration with PyCharm default settings dialog:

PyCharm - Default Settings - Project Interpreter

What's in a Macro

A LibreOffice Python macro may look like:

import uno
def my_1st_macro():
    # Won't run directly in Anaconda, Geany, KDevelop, PyCharm or else
    doc = XSCRIPTCONTEXT.getDocument()
    doc.getText().setString("Hello World!")

g_exportedScripts = my_1st_macro,

Executing the above requires to bridge together the IDE and LibreOffice. Once done UNO objects become accessible.

Up to five steps can be necessary to achieve this:

  1. Start LibreOffice as a service,
  2. Connect to a service,
  3. create a XSCRIPTCONTEXT Adaptor,
  4. Run the macro,
  5. Stop LibreOffice as a service

While examples available on the internet do not resort to all these steps, their study exhibits coding guidelines that the IDE_utils.py module borrows from in order to innocuously integrate in IDEs.

Start, Connect, Adapt, Run & Stop

Below table is listing a few public (Libre/Open)Office Python macros examples. Their usage of the Start, Connect, Adapt, Run, Stop steps is indicated.

Example codes
Description Start Connect Adapt Run

Debug

Stop
a. LibreOffice and OpenOffice officehelper.py module x x
b.Office.bridge.py A bridge for IDE with XSCRIPTCONTEXT revisité, Feb. 2017 (in french) x x x
c. Interface-oriented programming in OpenOffice / LibreOffice: automate your office tasks with Python macros, Sep. 2013 x x
d. unopy.py LibreOffice macro execution with PyCharm, Jan. 2014 (in japanese) x x x
e. ooutils.py - Starting, Stopping and Connecting to OpenOffice with Python, Dec. 2008 x x x x
f. Python UNO-bridge, Oct. 2008 x

IDE enablement

Based on these resources, requirements for Python macro enablement in IDEs summarize as:

  • start, connect, adapt, run and stop steps to be optional
  • Support multiple platforms i.e. essentially Linux, MacOS and Windows
  • on-demand startup --options
  • Permit pipe and/or socket connections
  • decoupled coding using injection
  • Provide Service pooling, context pooling
  • and KISS

IDE_utils module proposal: A Runner() context manager class is responsible for starting and stopping soffice instances. An optional Runners.json configuration file contains service-options pairs holding the services to start and their running conditions. A connect() function bridges the actual IDE and LibreOffice instances. A ScriptContext() object is injected as XSCRIPTCONTEXT built-in. start() and stop() coding facilities are wrapping-up Runner() features. The module skeleton looks like:

#!  # IDE_utils.py
import officehelper
RUNNERS = 'Runners.json'

class Runner(soffice=None): pass
class ScriptContext(): pass

_ctx = officehelper.bootstrap()
XSCRIPTCONTEXT = ScriptContext(_ctx)

def connect(host='localhost', port=2002, pipe=None): pass
def start(soffice=None): pass
def _stop(): pass

IDE_utils.py can be obtained from GitLab.

Recommended Use

import uno
def my_1st_macro(): pass  # Your code goes here

g_exportedScripts = my_1st_macro,  # Published macros

if __name__ == '__main__':
    from IDE_utils import Runner, XSCRIPTCONTEXT
    with Runner as jesse_owens:  # Start/Stop, Connect/Adapt
        my_1st_macro  # Run

The example above should be your preferred use for IDE_utils. As starting and stopping a service may not fit all situations, these steps are optional. That same module allows the customization of LibreOffice - or OpenOffice - services running conditions. "Getting Started" user guide provides detailed description of the 3 different ways to use IDE_utils:

  • Resorting to (Libre/Open)Office default Python bootstrap() mechanism,
  • Letting Runner() and ScriptContext() objects take responsibility for start, connect, adapt, run and stop steps,
  • Deciding when to perform start, connect, adapt, run and stop steps.

Managing Documents (draft)

Opening a Document

Creating a Document

Saving a Document

Closing a Document

A General Purpose Converter

Bug Detection & Reporting

Examining (draft)

Examining LibreOffice

Configuration Properties

Path Settings

Getting & Setting DocumentProperties

Reporting OS File Properties

Setting Document Properties

Inspecting a Document for API Information

MRI, xRay & ObjectInspector

Listening (draft)

... catching document(s) events, catching URP bridge events...

import uno, msgbox
def listening():
    pass  # Your code goes here

g_exportedScripts = listening,
import msgbox
help(msgbox)