[Solved] Possible to use custom pythonscript.py in addon?

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
Induane
Posts: 28
Joined: Fri Mar 28, 2014 4:49 am

[Solved] Possible to use custom pythonscript.py in addon?

Post by Induane »

I'm working with an extension to office where office is actually embedded in a java application (why is well beyond the scope of this question). The long short of this though is that the java runtime doesn't allocate a very large buffer for console output. When this buffer is full (something that isn't really possible to manipulate from within office afaik) and an attempt to write to stdout happens, office just freezes indefinitely. Normally I work around this by making sure that I don't use any console logger with our addon, however occasionally there were still writes to console happening. I searched the code for extraneous prints, anything that could possibly write to stdin or stderr.

So, it turns out the answer was really kind of complex. Burried deep within pythonscript.py you find (with some variation depending on pythonscript.py version):

Code: Select all

    code = None
    if url.startswith("file:"):
        code = compile(src, encfile(
            uno.fileUrlToSystemPath(url)), "exec")
    else:
        code = compile(src, url, "exec")
    exec code in entry.module.__dict__

    entry.module.__file__ = url
    self.modules[url] = entry
The magic line there ends up being exec code in entry.module.__dict__ - it turns out that when loading a library, if there are any errors that happen at that point (syntax errors, import problems, etc...) then you end up writing to stderr even when you've explicately told pythonscript.py to not log to a console. There isn't really anything you can do on the code side to make sure this never happens ever. Worse, because of the way it happens, there are absolutely no outputs, no error messages or logs anywhere to even give you the slightest IDEA of where/what is failing. It simply halts without explanation.

After a lot of mind melting process tracing and debugging though I was finally able to figure out what was going on. To work around the issue as a proof of concept I found a change that can be made to pythonscript.py that can catch any writes to stderr or stdout. Enter my IO Context Manager:

Code: Select all

import sys
import contextlib
from StringIO import StringIO

@contextlib.contextmanager
def outputIO():
    """
    Context manager that replaces standard out and standard error with a single
    file like object. This is useful for running applications where in some
    circumstances no buffer is allocated for stdout or stderr. Our common use
    case here is for executing python scripts in OpenOffice/LibreOffice from
    inside of the thick client app.
    """
    old_out = sys.stdout
    old_err = sys.stderr

    # Create a file-like object to catch output
    out_flo = StringIO()

    # Map standard out and standard error to this file like object
    sys.stdout = out_flo
    sys.stderr = out_flo

    yield out_flo

    # Reset standard out and stanard error to original settings
    sys.stdout = old_out
    sys.stderr = old_err

Once this has been added to pythonscript.py the only other change necessary is in that exec call:

Code: Select all

    
with outputIO() as f:
    exec code in entry.module.__dict__
    log.isDebugLevel() and log.debug("Exec %s" % f.getvalue())
Now, whatever your pythonscript logging settings are work to log all output from exec, all without accidentally writing to stderr or stdout if you don't want to.

WHEW! All that said, just to give a little context for a simple question:

I'd like to know if it is possible to ship/use a custom version of pythonscript.py for a specific addon. Specifically, if possible, I'd like to ship our addon with my updated version if possible.

Thoughts or ideas?
Last edited by Induane on Fri Apr 25, 2014 8:10 pm, edited 2 times in total.
OpenOffice 3.1 on Windows 7 / LibreOffice 3.6 on Ubuntu 13.10 / LibreOffice 4.1 on Ubuntu 13.10
hanya
Volunteer
Posts: 885
Joined: Fri Nov 23, 2007 9:27 am
Location: Japan

Re: Possible to use a customized pythonscript.py in addon?

Post by hanya »

I'd like to know if it is possible to ship/use a custom version of pythonscript.py for a specific addon. Specifically, if possible, I'd like to ship our addon with my updated version if possible.
You can ship the modified one in your package. Simply, put the file into your package somewhere and add entry for it in manifest.xml file as application/vnd.sun.star.uno-component;type=Python.

With this way, new registration of the script provider with the same name with existing one. The importance is the oder of the priority of registerd things. If you install an extension having some service implementations, entries of these services and implementations are written in the type library database for installed extensions. During the start up of the office, the service provides type information merges databases according to the priority.
If your extension is intended to installed as shared extension, it might be overwritten by user's one that having the service with the same implementation name. Because of that, overwritting the exisiting service is not good manager, in my oppinion. But I have done a few times on my extensions.
Please, edit this thread's initial post and add "[Solved]" to the subject line if your problem has been solved.
Apache OpenOffice 4-dev on Xubuntu 14.04
Post Reply