3

I'd like to use openoffice to programmatically convert docx to pdf. I know unoconv can do this, and indeed unoconv will do this for me, even if I run a separate listener (using unoconv -l) and invoke unoconv -n (so that it will die if it can't connect to the listener). Accordingly, I assume that my openoffice/pyuno environment is sane.

However, when I run an unoconv listener (or manually invoke openoffice as an acceptor), and try to connect with my own python code (derived from unoconv, and cross-checked with another openoffice library), the listener dies, and the uno bridge dies.

The error I get from the listener is:

terminate called after throwing an instance of 'com::sun::star::uno::RuntimeException'

The error I get on the python end is:

unoconv: RuntimeException during import phase:
Office probably died. Binary URP bridge disposed during call

I really have no idea how to go about diagnosing the problem here. Any suggestions as to the underlying cause or how to diagnose it would be greatly appreciated.

Code below:

#dependency on openoffice-python
import openoffice.streams as oostreams
import openoffice.officehelper as oohelper
import uno, unohelper
from com.sun.star.beans import PropertyValue
from com.sun.star.connection import NoConnectException
from com.sun.star.document.UpdateDocMode import QUIET_UPDATE
from com.sun.star.lang import DisposedException, IllegalArgumentException
from com.sun.star.io import IOException, XOutputStream
from com.sun.star.script import CannotConvertException
from com.sun.star.uno import Exception as UnoException
from com.sun.star.uno import RuntimeException

import logging
logger = logging.getLogger(__name__)


#connectionstring = 'uno:socket,host=127.0.0.1,port=2002;urp;StarOffice.ComponentContext'
connectionstring = 'socket,host=127.0.0.1,port=2002'
## context = uno.getComponentContext()
## svcmgr = context.ServiceManager
## resolver = svcmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", context)

## unocontext = resolver.resolve("uno:%s" % connectionstring)
unocontext = oohelper.connect(connectionstring)

#unosvcmgr = unocontext.ServiceManager
desktop = unocontext.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", unocontext)


class OutputStream( unohelper.Base, XOutputStream ):
    def __init__(self, stream=None):
        self.closed = 0
        self.stream = stream if stream is not None else sys.stdout

    def closeOutput(self):
        self.closed = 1

    def writeBytes( self, seq ):
        self.stream.write( seq.value )

    def flush( self ):
        pass

def UnoProps(**args):
    props = []
    for key in args:
        prop = PropertyValue()
        prop.Name = key
        prop.Value = args[key]
        props.append(prop)
    return tuple(props)



FILTERS = {'pdf': 'writer_pdf_Export'}

def convert_stream(instream, outstream,
                   outdoctype=None, outformat=None):
    '''instream and outstream are streams.
    outdoctype and outformat are strings. They correspond
    to the first two parameters to the Fmt constructor.To
    convert to pdf use outdoctype="document",
    outformat="pdf".
    If you choose inappropriate values, an ValueError
    will result.'''
    #fmts is a global object of type FmtList

    outputfilter = FILTERS[outformat]

    inputprops = UnoProps(Hidden=True, ReadOnly=True, UpdateDocMode=QUIET_UPDATE, InputStream=oostreams.InputStream(instream))
    inputurl = 'private:stream'
    convert_worker(inputurl,inputprops,outputfilter,outstream=outstream)
    return outstream


def convert_worker(inputurl, inputprops, outputfilter, outstream=None,inputfn=None):
    global exitcode

    document = None

    try:
        ### Import phase
        phase = "import"

        document = desktop.loadComponentFromURL( inputurl , "_blank", 0, inputprops )

        if not document:
            raise UnoException("The document '%s' could not be opened." % inputurl, None)

        ### Import style template
        phase = "import-style"

        ### Update document links
        phase = "update-links"
        try:
            document.updateLinks()
        except AttributeError:
            # the document doesn't implement the XLinkUpdate interface
            pass

        ### Update document indexes
        phase = "update-indexes"
        for ii in range(2):
            # At first update Table-of-Contents.
            # ToC grows, so page numbers grows too.
            # On second turn update page numbers in ToC.
            try:
                document.refresh()
                indexes = document.getDocumentIndexes()
            except AttributeError:
                # the document doesn't implement the XRefreshable and/or
                # XDocumentIndexesSupplier interfaces
                break
            else:
                for i in range(0, indexes.getCount()):
                    indexes.getByIndex(i).update()

        ### Export phase
        phase = "export"

        outputprops = UnoProps(FilterName=outputfilter, OutputStream=OutputStream(stream=outstream), Overwrite=True)
        outputurl = "private:stream"

        try:
            document.storeToURL(outputurl, tuple(outputprops) )
        except IOException as e:
            raise UnoException("Unable to store document to %s (ErrCode %d)\n\nProperties: %s" % (outputurl, e.ErrCode, outputprops), None)

        phase = "dispose"
        document.dispose()
        document.close(True)

    except SystemError as e:
        logger.error("unoconv: SystemError during %s phase:\n%s" % (phase, e))
        exitcode = 1

    except RuntimeException as e:
        logger.error("unoconv: RuntimeException during %s phase:\nOffice probably died. %s" % (phase, e))
        exitcode = 6

    except DisposedException as e:
        logger.error("unoconv: DisposedException during %s phase:\nOffice probably died. %s" % (phase, e))
        exitcode = 7

    except IllegalArgumentException as e:
        logger.error("UNO IllegalArgument during %s phase:\nSource file cannot be read. %s" % (phase, e))
        exitcode = 8

    except IOException as e:
        #            for attr in dir(e): print '%s: %s', (attr, getattr(e, attr))
        logger.error("unoconv: IOException during %s phase:\n%s" % (phase, e.Message))
        exitcode = 3

    except CannotConvertException as e:
        #            for attr in dir(e): print '%s: %s', (attr, getattr(e, attr))
        logger.error("unoconv: CannotConvertException during %s phase:\n%s" % (phase, e.Message))
        exitcode = 4

    except UnoException as e:
        if hasattr(e, 'ErrCode'):
            logger.error("unoconv: UnoException during %s phase in %s (ErrCode %d)" % (phase, repr(e.__class__), e.ErrCode))
            exitcode = e.ErrCode
            pass
        if hasattr(e, 'Message'):
            logger.error("unoconv: UnoException during %s phase:\n%s" % (phase, e.Message))
            exitcode = 5
        else:
            logger.error("unoconv: UnoException during %s phase in %s" % (phase, repr(e.__class__)))
            exitcode = 2
            pass
Marcin
  • 48,559
  • 18
  • 128
  • 201
  • I should add that the proximate cause of my troubles was that I was passing to uno a stream which was backed by an `io.TextIOWrapper`, i.e. a unicode stream and not a bytestream. – Marcin Dec 12 '13 at 21:41
  • What line was this exception being raised originally? – TankorSmash Oct 03 '14 at 15:18
  • @TankorSmash There was no stack trace, which is why this was so puzzling. – Marcin Oct 03 '14 at 19:58
  • You mean before it was caught in one of the `except RuntimeException as e` type of lines there was no trace? What about building the stacktrace with the `tb` module? – TankorSmash Oct 03 '14 at 20:03
  • @TankorSmash No, I mean what I say. – Marcin Oct 04 '14 at 06:47
  • So you never found a solution to this? If the unicode thing was the solution, answer your own question. – TankorSmash Oct 04 '14 at 16:21
  • @TankorSmash The solution was as in my first comment; note however that that is not really a solution, as crashing out on the wrong type of string is not the right thing. It's also not an answer to the question as stated. – Marcin Oct 04 '14 at 16:43
  • The thing here is that you're posting your own string as an error message, and not telling me the actual line the original error was sourced from. Instead of throwing that mess of code at us, do you think you could condense it down to like 10 lines that reveal the exact nature of the issue? We don't need to see 80% of the code you've presented. – TankorSmash Oct 05 '14 at 18:04
  • @TankorSmash Maybe go talk to someone with a live problem instead of bothering me? – Marcin Oct 06 '14 at 11:01

1 Answers1

1

I don't know if this could be your case, but I discovered that LogMeIn (running on my box) is also using the port 2002. When I try unoconv on that machine, I get the same error: Binary URP bridge disposed during call. I killed LogMeIn and everything worked after that.

Hope this helps!

EricG
  • 23
  • 1
  • 6
  • The proximate cause of my issue is as stated in the comment above; however it's clear that there are number of fragilities in the pyuno bridge. – Marcin Mar 08 '14 at 00:44