[Python] Develop *Office macros within IDEs

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
User avatar
LibreOfficiant
Posts: 12
Joined: Wed Jan 25, 2017 9:36 pm

[Python] Develop *Office macros within IDEs

Post by LibreOfficiant »

Developing Python macros within an Integrated Development Environment (IDE) is possible as indicated in Designing & Developing Python Applications.

A (Libre/Open)Office Python macro looks like:

Code: Select all

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 *Office. 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
These steps imply, from few to many Python extra code, to be removed from your macro, once ready for *Office validation.

IDE_utils module innocuously integrates in Python macros with the following features:
  • start, connect, adapt, run and stop steps are optional
  • Support multiple platforms i.e. essentially Linux, MacOS and Windows
  • on-demand startup --options
  • Permit pipe and/or socket connections
  • decoupled coding using Inversion of Control
  • Provide Service pooling, context pooling
  • and KISS
IDE_utils' content: A Runner() context manager class is responsible for starting and stopping soffice instances. An optional 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() functions are coding facilities that wrap-up Runner() features.

Code: Select all

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

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

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

def connect(host='localhost', port=2002, pipe=None): pass
def start(): pass
def stop(): pass
Thus a LibreOffice Python macro library may ressemble these examples:

Code: Select all

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

g_exportedScripts = macro_1, macro_2  # *Office public macros

#! EXAMPLE 1
if __name__ == "__main__":
    ''' LibreOffice as a Service IDE runnable code'''
    import IDE_utils as geany
    with geany.Runner() as jesse_owens:  # Start/Stop
        XSCRIPTCONTEXT = geany.XSCRIPTCONTEXT  # Connect/Adapt
        macro_2()  # Run
Example 1: As Runners.json does not exist jesse_owens starts nothing. officehelper(i) opens a named pipe of random name, XSCRIPTCONTEXT injection occurs, macro_2 gets executed and LibreOffice running pipe gets stopped as jesse_owens context manager triggers it.

Code: Select all

#! EXAMPLE 2
if __name__ == "__main__":
    import IDE_utils as pycharm
    with pycharm.Runner(json={pgm: [*options]}) as carl_lewis:  # Start/Stop
        ctx = pycharm.connect(pipe='LibreOffice')
        XSCRIPTCONTEXT = pycharm.ScriptContext(ctx)  # Adapt
        macro_1()  # Run
Example 2: As carl_lewis explores JSON pgm-options(ii) dictionary pairs, (Libre/Open)Office instances start. A hardwired 'LibreOffice' pipe connection is requested, macro_1 executes and carl_lewis terminates all started instances.
Note: A default injection is performed, in the background, with last pgm-options(ii) pair, and overrides officehelper bootstraping.

Code: Select all

#! EXAMPLE 3
if __name__ == "__main__":
    import IDE_utils as usain_bolt  # Runner()
    usain_bolt.start()
    ctx = usain_bolt.connect()
    XSCRIPTCONTEXT = usain_bolt.ScriptContext(ctx)  # Adapt
    pass  # Your code goes here
    usain_bolt.stop()
Example 3: usain_bolt starts all services found in optional Runners.json input file, attempts a common socket connection on port 2002, injects an implementation of XSCRIPTCONTEXT built-in. No macro code is called and usain_bolt finally stops all possible (Libre/Open)Office instances.

Usage:
  1. Copy this module into your <OFFICE>/program/ directory OR Include it into your IDE project directory
  2. Include one of the examples into your Python macro
  3. Run your (Libre|Open) macro from your preferred IDE
IDE_utils module motivations are available. Source code can be obtained from GitLab. Module design decisions are also drafted.

Notes:
  1. officehelper is a LibreOffice and OpenOffice standard module
  2. {pgm: [*options]} syntax is described in Services Specification
libO 5.4 64bit, (PortableApps: libO 6.0, aOO 4.1, OOo 3.2 32bit) on Win7/Win10 x64 | aOO 4.1.x & libO 5.4.x on Mint 18 Sarah & OSX 10.9 Mavericks x64
Python toolbox: Geany, PyCharm and APSO, MRI extensions..
https://wiki.documentfoundation.org/Macros/Design_Guide
Post Reply