Starting, Stopping, and Connecting to OpenOffice with Python
Using pyuno you can script OpenOffice with Python. Pyuno allows you to create macros inside OpenOffice and it also allows you to create external Python scripts that talk to a running copy of OpenOffice. If you want to get started with pyuno be prepared for an often frustrating experience: the documentation is sketchy and often just plain hard to locate, and the version of Python that's embedded in OpenOffice has been stuck at version 2.3 for quite a while now.
Pyuno is the Python layer that implements OpenOffice's UNO interface. UNO is an application programming language independent interface to OpenOffice. UNO is specified in IDL and often the only documentation for pyuno is the IDL documentation for UNO.
The code presented here runs outside of OpenOffice and shows how to start, stop, and connect to OpenOffice in "headless" mode. Running OpenOffice in "headless" mode means that OpenOffice doesn't display a window it just waits for UNO operations (via a TCP/IP port). The code presented here was tested with version 2.5 of Python and version 2.4 of OpenOffice. I also tested it with version 3.0 of OpenOffice but it only runs if you use the version of Python that comes with OpenOffice.
The code consists mainly of the Python class OORunner which has methods for connecting to OpenOffice, for starting it, and for shutting it down. The code also keeps track of all the copies of OpenOffice that it's started and shuts them all down on exit. This code is based on some code that I found here, I refactored the connecting and added the ability to start and and stop OpenOffice from Python. The file name is ooutils.py.
# OpenOffice utils.
#
# Based on code from:
# PyODConverter (Python OpenDocument Converter) v1.0.0 - 2008-05-05
# Copyright (C) 2008 Mirko Nasato <mirko@artofsolving.com>
# Licensed under the GNU LGPL v2.1 - or any later version.
# http://www.gnu.org/licenses/lgpl-2.1.html
#
import sys
import os
import time
import atexit
OPENOFFICE_PORT = 8100
# Find OpenOffice.
_oopaths=(
('/usr/lib64/ooo-2.0/program', '/usr/lib64/ooo-2.0/program'),
('/opt/openoffice.org3/program', '/opt/openoffice.org/basis3.0/program'),
)
for p in _oopaths:
if os.path.exists(p[0]):
OPENOFFICE_PATH = p[0]
OPENOFFICE_BIN = os.path.join(OPENOFFICE_PATH, 'soffice')
OPENOFFICE_LIBPATH = p[1]
# Add to path so we can find uno.
if sys.path.count(OPENOFFICE_LIBPATH) == 0:
sys.path.insert(0, OPENOFFICE_LIBPATH)
break
import uno
from com.sun.star.beans import PropertyValue
from com.sun.star.connection import NoConnectException
class OORunner:
"""
Start, stop, and connect to OpenOffice.
"""
def __init__(self, port=OPENOFFICE_PORT):
""" Create OORunner that connects on the specified port. """
self.port = port
def connect(self, no_startup=False):
"""
Connect to OpenOffice.
If a connection cannot be established try to start OpenOffice.
"""
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
context = None
did_start = False
n = 0
while n < 6:
try:
context = resolver.resolve("uno:socket,host=localhost,port=%d;urp;StarOffice.ComponentContext" % self.port)
break
except NoConnectException:
pass
# If first connect failed then try starting OpenOffice.
if n == 0:
# Exit loop if startup not desired.
if no_startup:
break
self.startup()
did_start = True
# Pause and try again to connect
time.sleep(1)
n += 1
if not context:
raise Exception, "Failed to connect to OpenOffice on port %d" % self.port
desktop = context.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)
if not desktop:
raise Exception, "Failed to create OpenOffice desktop on port %d" % self.port
if did_start:
_started_desktops[self.port] = desktop
return desktop
def startup(self):
"""
Start a headless instance of OpenOffice.
"""
args = [OPENOFFICE_BIN,
'-accept=socket,host=localhost,port=%d;urp;StarOffice.ServiceManager' % self.port,
'-norestore',
'-nofirststartwizard',
'-nologo',
'-headless',
]
env = {'PATH' : '/bin:/usr/bin:%s' % OPENOFFICE_PATH,
'PYTHONPATH' : OPENOFFICE_LIBPATH,
}
try:
pid = os.spawnve(os.P_NOWAIT, args[0], args, env)
except Exception, e:
raise Exception, "Failed to start OpenOffice on port %d: %s" % (self.port, e.message)
if pid <= 0:
raise Exception, "Failed to start OpenOffice on port %d" % self.port
def shutdown(self):
"""
Shutdown OpenOffice.
"""
try:
if _started_desktops.get(self.port):
_started_desktops[self.port].terminate()
del _started_desktops[self.port]
except Exception, e:
pass
# Keep track of started desktops and shut them down on exit.
_started_desktops = {}
def _shutdown_desktops():
""" Shutdown all OpenOffice desktops that were started by the program. """
for port, desktop in _started_desktops.items():
try:
if desktop:
desktop.terminate()
except Exception, e:
pass
atexit.register(_shutdown_desktops)
def oo_shutdown_if_running(port=OPENOFFICE_PORT):
""" Shutdown OpenOffice if it's running on the specified port. """
oorunner = OORunner(port)
try:
desktop = oorunner.connect(no_startup=True)
desktop.terminate()
except Exception, e:
pass
def oo_properties(**args):
"""
Convert args to OpenOffice property values.
"""
props = []
for key in args:
prop = PropertyValue()
prop.Name = key
prop.Value = args[key]
props.append(prop)
return tuple(props)
Using the class is straightforward: you simply create an instance of it and call connect() on that instance. Connect returns the OpenOffice desktop object. This is the object that you use for most interactions with OpenOffice.
oor = ooutils.OORunner() desktop = oor.connect() # Do something with the "desktop"
As I mentioned there are also startup and shutdown methods, but you don't really need to call them: the connect method will call the startup method if it's unable to connect and the atexit code will shutdown all started copies of OpenOffice on exit. There's also a function oo_shutdown_if_running() that can be called to shutdown a desktop if it's running.
Next week I'll show you how to use the code presented here to write a Python program to convert spreadsheets to CSV files.
Mitch Frazier is an Associate Editor for Linux Journal.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
- RSS Feeds
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- Dynamic DNS—an Object Lesson in Problem Solving
- New Products
- Validate an E-Mail Address with PHP, the Right Way
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Download the Free Red Hat White Paper "Using an Open Source Framework to Catch the Bad Guy"
- Tech Tip: Really Simple HTTP Server with Python
- Keeping track of IP address
21 min 14 sec ago - Roll your own dynamic dns
5 hours 34 min ago - Please correct the URL for Salt Stack's web site
8 hours 46 min ago - Android is Linux -- why no better inter-operation
11 hours 1 min ago - Connecting Android device to desktop Linux via USB
11 hours 29 min ago - Find new cell phone and tablet pc
12 hours 28 min ago - Epistle
13 hours 56 min ago - Automatically updating Guest Additions
15 hours 5 min ago - I like your topic on android
15 hours 51 min ago - This is the easiest tutorial
22 hours 27 min ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



Comments
License?
That's a great module! I was looking for how to start/stop OO.o from python for an app i'm doing i find your module as a great start point for my project.
And then arrived at the point that i've noticed you said nothing about license to use your module.
So just in case i'm asking here ;)
It would be nice if i could develop a gpl'ed app starting from your module (as it would need some modifications in order to fit my needs)
So what can be done with it? what kind of license it's under? lgpl, gpl, cc, bsd , public domain ...?
Public Domain
Use it however you like, as long as it doesn't violate the license terms of the code it's based on (see the top of the code).
Mitch Frazier is an Associate Editor for Linux Journal.
Long lines
It's nice, indeed, but could I suggest not to write lines longer than 80 characters in the Python code.
The longest line is 131 characters; and my browser does not show the end of these long lines.
I think we need a web site fix
The site should be putting that in a scroll box, I'll have to check with the webmaster.
Mitch Frazier is an Associate Editor for Linux Journal.
Nice tutorial
Awesome tutorial if you want to help us with the documenttion and experimientation of PyUNO please go to the Python wiki at the OpenOffice.org Wiki site.
http://wiki.services.openoffice.org/wiki/Python