- Introduction
- State
- Changes
- Installation guide
-- Binary
-- Source
- External references
- UNO type mapping
- Implementing UNO objects
- Implementing UNO components
- Out parameter handling
- Exception handling
- Dependencies
- Bootstrapping in non-OOo environments
- unohelper module
- Authors
- License
Introduction
The Python-UNO bridge allows to use the standard OpenOffice.org API from
the well known python scripting language. It addtionally allows to develop UNO components
in python, thus python UNO components may be run within the office process and
e.g. can be called
from Java, C++ or the built in StarBasic scripting langauge.
You should find the most current version of this document at
http://udk.openoffice.org/python/python-bridge.html
State
The Python-UNO bridge is in a beta state. It runs with the instable OpenOffice.org 1.1 source tree (to be more exact with the OO643C version). It does not run with an OpenOffice.org 1.0.x source tree.
PyUNO can be downloaded as a separate binary package, it does not come with the default OpenOffice.org installation. This may change in future, when a signifcant number of people have shown interest in PyUNO. So if you think, that PyUNO should be part of OOo installation, raise your voice on the dev@udk.openoffice.org mailing list.
The documentation in its current state is targeted at developers, who
have already some experience with OpenOffice.org API with some other
programmaing language (Java/C++/StarBasic). If you are a newbie and you think,
that some background information is missing, you should try the
developer manual mentioned in the external reference section.
Changes
fixed bugs: - #i11487# PyUNO interfaces are not transitive - python list aren't accepted anymore in place of UNO sequences. Only tuples are accepted. - unicode string conversions should now also work on systems where sizeof( wchar_t ) == 4 changes: - The source is now available from the OOo CVS repository. - uno.ByteSequence (idl sequence) is now treated differently than before (this is an incompatible change). See documentation for more information) - file url conversion routines added (API calls need file urls) ( unohelper.systemPathToFileUrl(), unohelper.fileUrlToSystemPath(), unohelper.absolutize()) - added two more samples. * ooextract.py extracts pure text from a given OOo document and dumps it on stdout (which allows you to grep through OOo documents :o) ) * biblioaccess.py is a small example showing how to access the database API within OOo. - uno.Bool is now deprecated, instead python True and False are used. changes in source distribution: - build -i for the windows python build is not necessary anymore. - Build environment has changed. Only the d.lst and the makefile in the python module depends now on the concrete used python version. This should make python version changes easier in future. changes in binary distribution: - pyuno ships now with a precompiled python runtime. This is necessary, because pyuno and python must be compiled with the same compiler version of gcc on unix platforms. - therefor, pyuno's environment files pyunoenv.[bat|tcsh] have simplified a little.
all platforms: program/pydemo program/uno.py program/unohelper.py program/pythonloader.py additionally on windows: program/pyuno.dll program/pycpld.dll program/pyuno_setup.bat program/regcomp.exe program/pyunoenv.bat program/pyuno.ini addtiionally on unix: program/pyuno_setup.sh program/libpyuno.so program/libpycpld.so program/regcomp program/pyunoenv.tcsh program/pyuno.so program/libpython.so program/pyunorcNote that pyuno now ships with a python runtime, so you don't need to install python anymore.
windows http://udk.openoffice.org/python/download/pyuno-win32-0.9.2.zip
linux x86
http://udk.openoffice.org/python/download/pyuno-linux-x86-0.9.2.tar.gz
linux-ppc
ftp://ftp.yellowdoglinux.com/pub/yellowdog/software/openoffice/pyuno-linux-ppc-0.9.2.tar.gz
(and its mirrors).
e.g. Linux:
joe@foobar:/home/joe/OpenOffice.org643> gunzip < pyuno-linux-x86-0.9.2.tar.gz | tar -xvf -
setenv OOOHOME /home/joe/OpenOffice.org643
or (windows)
set OOOHOME=c:\programs\OpenOffice.org643
register component "pycpld" in registry "applicat.rdb" succesful! register component "swritercomp" in registry "applicat.rdb" succesful!If you get an error message, have a look at the troubleshooting section below.
Make sure, that the office doesn't run. Start the office from a python prepared shell ( do the pyunoenv step above). In order to let the demos run, start the office with
./soffice "-accept=socket,host=localhost,port=2002;urp;"
Now start the swriter demo script
python pydemo/swriter.py
It should connect to the office, create a new document and put some text and a table into it. Note that this swriter.py example does the same things as the swriter.java example, which comes with the OpenOffice.org development kit. If you have some java source code and you are unsure how to translate it to python, you might have a look at these source files to get an idea how to do this.
Additionally, there comes a python UNO component named
swritercomponent.py, which implements the com.sun.star.lang.XMain interface.
The only method run()
does the same thing as the swriter.py
example, the only difference is, that it is run within the OpenOffice.org process,
which improves performance.
You may either trigger
the python component in the office directory from another python script
python pydemo/swritercompclient.py
or you may use the following Basic script via Tools/Macro/New macro
dim args() pycomp = createUnoService( "org.openoffice.demo.SWriter" ) pycomp.run( args )Now have a look at the sample files to get an idea, how to use the bridge. Visit the rest of this document, if you are uncertain, how a concrete UNO feature is treated by the python bridge. Have fun !
Note for python 0.9.1 users !
When you want to build pyuno 0.9.2 in a solver tree, which
already contains pyuno 0.9.1, you should first remove the files from
the solver tree. These are the
your-platform/bin/python[.exe]
your-platform/lib/[lib]pycpld.[dll|so]
your-platform/lib/[lib]python.[dll|so]
your-platform/lib/[lib]pyuno.[dll|so]
your-platform/lib/python2.2 (whole directory)
your-platform/inc/python2.2 (whole directory)
Linux: Please add the following line to your LinuxIntelEnv.Set (Attention 0.9.1-users: The pathes have changed ! )
setenv PYTHONPATH .:"$SOLARVER"/"$UPD"/"$INPATH"/lib/python: "$SOLARVER"/"$UPD"/"$INPATH"/lib/python/lib-dynloadWindows: Please add the following to your winenv.bat file
set PYTHONPATH=.;%SOLARVER%\%UPD%\%INPATH%\lib\python; %SOLARVER%\%UPD%\%INPATH%\lib\python\lib-dynloadCheckout the source from the CVS repository. These are external/python and udk/pyuno (I hope to get the alias python and pyuno working). The external/python project might not yet be available because of legal issues, it can be downloaded from the attachment of the issue http://www.openoffice.org/issues/show_bug.cgi?id=11753 inbetween.
Build and deliver this project.
prj -- build details source/module -- contains the core Python-UNO bridge and the module, that is loaded my the python executable. The result is a shared C++ library, to which the python loader links to. source/loader -- contains the UNO loader for python components inc/pyuno -- contains exported API for the python module. unotypes -- generates the types needed for the bridge test -- contains test python scripts. In order to execture the tests, simply type dmake test demo -- contains demo python scripts and a makefile , which creates a deployment file for the OO643C build.Build this project. In order to run the tests, you need to get a HEAD version of the testtools project, which currently does not get built by default, build and deliver the testtools project. Afterwards run the tests in the pyuno/test directory using dmake runtest, you shouldn't get any errors there. Deliver this project.
From now on, you can use UNO python scripts in the build environment, e.g. create some glue code for some UNO components to do a certain job. In the build environment, only the core UNO components to make the bridge work are preregistered. Have a look at the Bootstrapping section below to see, how you can register your components. The really nice thing is that you now can do UNO just with a text editor without any compilation :o).
Python homepage | http://www.python.org |
Python tutorial | TODO |
UNO homepage | http://udk.openoffice.org |
OpenOffice.org developer manual | http://api.openoffice.org/DevelopersGuide/DevelopersGuide.html |
IDL datatype | representation in python | ||
---|---|---|---|
integer types (byte, short, unsigned short, long, unsigned long, hyper, unsigned hyper |
Python internally knows only the C datatypes long and long long as integer types.
On most machines, a long is a 32 bit value while long long is a 64 bit value.
|
boolean | Python internally has a boolean data type, which is derived from the
integer type ( see
http://python.org/peps/pep-0285.html
). There exists the singletons True and
False , which pyuno uses to distinguish between integers
and boolean values.
As long as a boolean is specified in the interface method signature, you may also you numbers. In the following example, all calls are valid:
True
or False .
Note: There also exists the uno.Bool class, which is deprecated since pyuno 0.9.2, but still supported. Don't use it anymore. |
string | In general, the string is mapped to the python unicode string. However, you may pass an
8 bit python string where a UNO string is expected, the bridge converts the
8 bit string to a unicode string using the system locale.
|
||
char |
A char is mapped to a uno.Char . It has a public unicode string member value
with length 1 containing the unicode char.
|
||
enum | A concrete enum value is represented by an instance of the class uno.Enum . It has
two members, typeName is a string containing the name of the enum type and
value |
||
type | A type is mapped to a uno.Type . It has public members typeName (string) and
typeClass (enum value of com.sun.star.uno.TypeClass).
There exists a function uno.getTypeByName() to easily
create a type instance, the functions raises a RuntimeException in case the
type is unknown.
You may create concrete type values in two ways
|
||
struct (and exception) |
For each UNO struct (or exception), a new python class is generated on the fly. It
is guaranteed, that there is only one instance of the struct (or exception) class per
python interpreter instance. The generated class does reflect the inheritance
hierarchy of the conrete UNO type (e.g. important for exception handling, see below).
One can generate a struct class by using the import mechanism. An instance of a struct can then be instantiated by using the python constructor. The constructor supports zero arguments (members get default constructed), 1 argument which the same type (copy constructor), and n arguments, where n is the number of elements of the concrete struct. The struct supports the equality operator, two structs are equal, if they are of the same type and each member is equal. Example:
uno.createUnoStruct() and passing the name of the struct
as the first parameter and optionial constructor arguments (see above for
an example of possible ctors).
ATTENTION: In UNO, structs have value semantic, however the handling in python does not reflect this. When a struct gets passed as a parameter to a function, the values are passed to the callee. Later modification of the struct instance does not influence the callee anymore. However, simply assigning a struct to another local variable does not create a copy, but simply creates an alias to the original instance.
|
||
sequence | A sequence is in general mapped to a python tuple. A python list is not (!)
accepted.
sequence<byte>
is mapped to the class uno.ByteSequence .
It has a string member named value , which holds the data of the byte sequence.
As the bytesequence most often is a container for binary data, this class allows to handle
binaries efficiently. This also embeds pyuno nicely into python, as python keeps binary
data in strings. Example:
|
||
constants | An UNO idl constant can be given by the following ways:
|
To be an UNO object, a python class MUST implement the com.sun.star.lang.XTypeProvider interface by implementing two methods getTypes() and getImplementationId(), which inform the python-UNO bridge, which concrete UNO interfaces the python class implements. The getTypes() function defines, which interfaces are implemented by the class.
To make this easier, there exists a unohelper.Base
class, where
a python UNO object should derive from. You can then implement a UNO interface
simply by deriving from the wanted interfaces. The following example
implements a com.sun.star.io.XOutputStream, which stores
all data written into the stream within a ByteSequence. (Note that this is
quite a poor implementation, which is just for demonstration purposes).
import unohelper from com.sun.star.io import XOutputStream class SequenceOutputStream( unohelper.Base, XOutputStream ): def __init__( self ): self.s = uno.ByteSequence("") self.closed = 0 def closeOutput(self): self.closed = 1 def writeBytes( self, seq ): self.s = self.s + seq def flush( self ): pass def getSequence( self ): return self.s |
If the reader is unfamilar with the component registration process, it should visit the OpenOffice.org developer manual for a comprehensive explanation.
The python loader supports currently supports the following protocols for incoming urls.
Protocol name | Description |
---|---|
vnd.openoffice.pymodule | The protocol dependend part is interpreted as a python module name, which is imported
using the common python import mechanism (which uses the PYTHONPATH environment variable).
After the module has been imported, the python loader looks for a module-global variable
with the name |
import unohelper from com.sun.star.io import XOutputStream g_ImplementationHelper = unohelper.ImplementationHelper() class TupleOutputStream( unohelper.Base, XOutputStream ): # The component must have a ctor with the component context as argument. def __init__( self, ctx ): self.t = () self.closed = 0 # idl void closeOutput(); def closeOutput(self): self.closed = 1 # idl void writeBytes( [in] sequence |
regcomp -register -br applicat.rdb -r applicat.rdb -c vnd.openoffice.pymodule:tuplestrm
The component can be instantiated e.g. from OpenOffice Basic with
tupleStrm = createUnoService( "com.sun.star.io.OutputStream" ) tupleStrm.flush() |
None
value should be used as a place holder.
This is best explained with an example.
Lets' assume we have the following IDL method spec
long foo( [in] long first, [inout] long second, [out] third ) |
class Dummy( XFoo ): def foo( self, first,second,third): # Note: the value of third is always None, but it must be there # as a placeholder if more args would follow ! return first,2*second,second + first |
ret,second,third = unoObject.foo( 2, 5 , None ) print ret,second,third # results into 2,10,7 |
However, note that
RuntimeException
during the call.
None
followed by possible
out parameters, so when you have a void method with one out parameter
you must assign the output to two variables (though the first one
will always be None).
None
as the first parameter.
Example for catching
from com.sun.star.uno import RuntimeException from com.sun.star.lang import IllegalArgumentException from com.sun.star.connection import NoConnectException try: uuresoler.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" ) except NoConnectException e: print "The OpenOffice process is not started or does not listen on the resource ("+e.Message+")" except IllegalArgumentException e: print "The url is invalid ( "+ e.Message+ ")" except RuntimeException e: print "An unknown error occured: " + e.Message |
class TupleOutputStream(XOutputStream,unohelper.Base): def writeBytes( self, seq ): if self.closed: raise IOException( "Output stream already closed", self ) self.t = self.t + seq |
Unlike the Java or C++ UNO binding, the python UNO binding is not self contained. It requires the C++ UNO binding and additional scripting components. These additional components currently live in the shared libraries tcv,inv,corefl,insp,invadp,proxyfac,pycpld (on windows tcv.dll,inv.dll,etc.; unix libtcv.so, etc.).
Often, the components for setting up an interprocess connection are additonally required. These are uuresolver,connectr,remotebridge,brdgfctr shared libraries.
The path environment variables ( LD_LIBRARY_PATH on unix, PATH on windows)
must point to a directory, where the core UNO libraries, the above listed
components and the pyuno shared library is located. (On unix, there exists
two files: libpyuno.so containing the code and a pyuno.so which is needed
for importing a native python module).
Additionally, the python module uno.py, unohelper.py and pythonloader.py must
be located in a directory, which is listed in the PYTHONPATH environment variable.
Bootstrapping pyuno from the python executable
When the uno module gets first imported from an arbitrary python script, it must bootstrap a properly prepared UNO component context.
# bootstraps the uno component context import uno # retrieve the already bootstrapped component context unoContext = uno.getComponentContext() |
PYUNOLIBDIR is a special bootstrap variable, which contains the path to the currently used pyuno shared library. Example:
# The bootstrap variable PYUNOLIBDIR will be set by the pyuno runtime library UNO_TYPES=$PYUNOLIBDIR/applicat.rdb UNO_SERVICES=$PYUNOLIBDIR/pyuno_services.rdb |
$ python myscript.py
Sometimes it is preferable to mention the librarynames of the desired
components directly within the script instead of preparing a registry
(however note that the above mentioned bootstrap components always needs
to be registered in a registry).
This can be achieved by using the function
unohelper.addComponentsToContext(
toBeExtendedContext, contextRuntime, componentUrls, loaderName )
Example:
import uno import unohelper localContext = uno.getComponentContext() unohelper.addComponentsToContext( localContext, localContext, ("stm",), "com.sun.star.loader.SharedLibrary") pipe = localContext.ServiceManager.createInstanceWithContext( "com.sun.star.io.Pipe", localContext ) pipe.writeBytes( uno.ByteSequence( "abc" ) ) ret,seq = pipe.readBytes( None, 3 ) |
def systemPathToFileUrl( systemPath )
|
Returns a file-url for the given system path. Most of the OOo API functions
expect a file-url, while the python runtime functions in general only work
with system pathes. The function is implemented using the core C function
osl_getFileUrlFromSystemPath() .
|
def fileUrlToSystemPath( url ) |
Returns a system path (determined by the system, the python interpreter
is running on). Most OOo function return a file-url, while most python
runtime functions expect system pathes. The function is implemented by
using the core osl_getSystemPathFromFileUrl() function.
|
def absolutize( path, relativeUrl )
|
Returns an absolute file url from a given, mandatory absolute, directory url
and a relative file url, which may be absolute or relative (which includes
e.g. ../ parts. The function is implemented by using the core
osl_getAbsolutePathFromFileUrl() function.
|
def addComponentsToContext( toBeExtendedContext, contextRuntime, componentUrls, loaderName ) |
This functions adds a tuple of component urls
to the
toBeExtendedContext using the contextRuntime to
instantiate the loader loaderName and some other services needed for this
task. After completing the function, all services within these components
can be instantiated as long as the toBeExtendedContext is
not disposed. The changes are not made persistent.
|
Please use the dev@udk.openoffice.org mailing list for
further questions.
License
The code is currently available under the BSD licence available from
http://www.opensource.org/licenses/bsd-license.php.