py3o is an elegant and scalable solution to design reports using LibreOffice or OpenOffice. py3o.template is the templating component that takes care of merging your data sets with a corresponding templated OpenOffice document.

It is plateform independent and does not require LibreOffice/OpenOffice itself to generate an ODF file.

If you want to generate a PDF or any other supported output format you will then need to have a server with either LibreOffice or OpenOffice and to install the py3o.renderserver on it. We also provide a docker image on the docker hub

If you want to have templating fusion & document conversion in one single web service usable from any language with just HTTP/POST you can install py3o.fusion server. Which also exists as a docker image

Python 3 support

py3o.fusion is python3 ready. But, yes there is a but... alas!, you'll need to install a trunk version of Genshi:

$ # activate your python env...
$ svn checkout http://svn.edgewall.org/repos/genshi/trunk genshi_trunk
$ cd genshi_trunk
$ python setup.py build
$ python setup.py install

We tested this with revision 1271. When genshi 0.8 is released we can officially say we support Python3 out of the box.

Full Documentation

We provide a documentation for this package. If anything is not correctly explained, please! create a ticket in our ticketing system

Example Usage

Below is an example that you can find in the source code inside the examples directory.

from py3o.template import Template

t = Template("py3o_example_template.odt", "py3o_example_output.odt")

t.set_image_path('staticimage.logo', 'images/new_logo.png')

class Item(object):

items = list()

item1 = Item()
item1.val1 = 'Item1 Value1'
item1.val2 = 'Item1 Value2'
item1.val3 = 'Item1 Value3'
item1.Currency = 'EUR'
item1.Amount = '12345.35'
item1.InvoiceRef = '#1234'

for i in xrange(1000):
    item = Item()
    item.val1 = 'Item%s Value1' % i
    item.val2 = 'Item%s Value2' % i
    item.val3 = 'Item%s Value3' % i
    item.Currency = 'EUR'
    item.Amount = '6666.77'
    item.InvoiceRef = 'Reference #%04d' % i

document = Item()
document.total = '9999999999999.999'

data = dict(items=items, document=document)


0.9.2 Jun. 26 2015

  • WARNING: if you used the old image replacement system, you

need to update your code to set static image from this:

# old way
t.set_image_path('logo', 'images/new_logo.png')

# You should now set it like this instead

# new way. Note the 'staticimage.' prefix added just before 'logo'
t.set_image_path('staticimage.logo', 'images/new_logo.png')
  • WARNING: after updating your code you must also update your template to prefix your static images names with the 'staticimage.' prefix.
  • Added dynamic images support. You can now add images instructions inside for loops or anywhere in your templates and pass the image data inside your objects attributes.
  • Added support for image data (dynamic ones) being passed-in as base64 data. This is useful for some clients like Odoo's report_py3o because they store image data as base64 encoded fields.

0.9.1 Jun. 3 2015

  • Fixed parser to read from the var name instead of its description, if you dont use the helper tool to introspect your reports this release is of no importance to you as it only fixes this particular point.

0.9 Jan. 8 2015

  • Added support for soft page breaks

0.8 Nov. 19 2014

  • Added better unit tests
  • Fixed corner cases in the variable introspection mechanism
  • Better handling of "ignore_undefined" that now also allows undefined images

0.7 Oct. 15 2014

  • Added Python3 support
  • Fixed a problem with validity of output in case the template contains a text:list inside a for loop
  • Added new public methods to help report servers introspect the template data dictionary
  • Added real unit tests (96% coverage ATM, way to go test team!)