Load module from package to another package

I’ve made an extension which is called my_utils.

In a second extension my_tools, I need to import some function from the first extension my_utils.

Is it possible?

Packages are located in directory suche as this one:

.config/libreoffice/4/user/uno_packages/cache/uno_packages/lu404906gqb45r.tmp_

Which knowledge doesn’t help me a lot.

Crossposting without reference is rude @bastoche

It’s rude telling people they’re acting rudely without having read the thread in question :slight_smile:

Thanks god there’s specific forum places (like forum.openoffice.org where I posted this issue too) where I btw found all my knowledges but in this case, it’s too specific.

why did you assume I’have NOT read both threads?

@bastoche, it seems you did not notice the date on the first comment by karolus. It was posted before your other comment. Also your comment did not link to the relevant post, so it would not have been particularly helpful anyway.

If my_utils exposes the function as an UNO service, then the service can be called from an extension. My own extensions call the MRI service all the time.

For a simple example, see my recent answer and comments at Is it possible to transfer a struct from Python to StarBasic? - #4 by jimk.

Are you aware that Python-UNO files can import other .py files that are in a pythonpath subdirectory? That would be inside the same extension, or in the LO Scripts user directory (.config/libreoffice/4/user/Scripts/python/pythonpath on your system), not between different extensions as your question describes.

2 Likes

Are you aware that Python-UNO files can import other .py files that are in a pythonpath subdirectory?
Sure, but as you well pointed it, it’s not my question.

I’m not sure to understand what you mean by :

If my_utils exposes the function as an UNO service.

See my answer in the link, especially the python code starting with IMPL_NAME. Or you could look at the MRI source code.

Ok, it becomes a bit clearer to me.

The implementation name I use for my first extension is com.rdt.comp.Bal which is to me a kind of location of the module (not clear) but the module itself is called rdt_bal.py and it contains some useful functions.

The difference I can see with your nice example is that you call a class while I need to import function.

If you only have one function, then use the XJobExecutor interface, so your function will be callable by .trigger(). This seems to be the most common interface that custom services use. So maybe your code would look like:

class Bal(unohelper.Base, XJobExecutor):
    def __init__(self, ctx):
        self.ctx = ctx
 
    def trigger(self, args):
        ...

For multiple unrelated functions, add more jobs in the same file. Here is an example from my real-world project.

g_ImplementationHelper = unohelper.ImplementationHelper()

g_ImplementationHelper.addImplementation(
    PhonologySettingsJob,
    "name.JimK.LinguisticTools.PhonologySettings",
    ("com.sun.star.task.Job",),)
g_ImplementationHelper.addImplementation(
    PhonologyGrabExJob,
    "name.JimK.LinguisticTools.PhonologyGrabExamples",
    ("com.sun.star.task.Job",),)
g_ImplementationHelper.addImplementation(
    InterlinSettingsJob,
    "name.JimK.LinguisticTools.InterlinSettings",
    ("com.sun.star.task.Job",),)
1 Like

I’d love to understand! My module looks like this:

import os
import json
import pyuno
... # all imports here


def bal_launcher(*args):
    ...

def open_medias(*args):
     ...

g_exportedScripts = (
    bal_launcher,
    post_launcher,
    open_document,
    start_cq,
    convert_to_srt_format,
    convert_to_elan,
    register_new_correction,
 )

Ok you completed your answer. Thanks and where would you include your:

g_ImplementationHelper.addImplementation(
InterlinSettingsJob,
“name.JimK.LinguisticTools.InterlinSettings”,
(“com.sun.star.task.Job”,),)

EDIT: I’d like to clarify what I’m looking for exactly.

I made an extension for managers that interacts with a webserver and an other one, more public, that allows to work on local documents.

The second one allows to open a VLC player. So my goal was: 1/ check if the manager extension was installed 2/ if yes, this one has a function to get the url to open in VLC. If no, the url selection is done manually.

So I was thinking of using this pattern:

try:
    from rdt_bal import get_my_url
except:
    get_my_url = None

and in my function:

def open_vlc(**args):
    if get_my_url:
        vlc(get_my_url())
    else:
        vlc()

I’m afraid that in the case of using addImplementatiion It would crash if the manager extension is not installed.

I think it should work without crashing. Wrap code like the following in a try block as in your pattern.

    mri_obj = ctx.ServiceManager.createInstanceWithContext(
        "mytools.Mri", ctx)

I got this issue:

script.CannotConvertException: value does not implement com.sun.star.uno.XComponentContext

If you want help with that error message, post a complete example that shows how to reproduce the error. Python instructions for calling MRI are at https://github.com/hanya/MRI/wiki/RunMRI#Python.

Personal messages prevent collaboration among the group. I don’t like it when people use them to request more help.

You can post a follow-up question by creating a clear question with a simplified example. Include a link to the original question. See How do I ask a good question? - Help Center - Stack Overflow.

Ok. I meant professional help.

What are personal messages for if it’s not for helping without polluting a thread with very specific needs? I’m very conscious of the importance to share help and indeed, I have the habit after a long (sometimes very long) time to give a clear solution to the issue expressed. Unfortunately, I don’t have the time right now to find the solution as I’m not a LibreOffice dev. I don’t either know how to get a training class. Thanks god there’s specific forum places (like forum.openoffice.org where I posted this issue too) where I btw found all my knowledges but in this case, it’s too specific.
At least, if you don’t want to give a deeper look at this, would you be kind enough to address me to someone that might help me ?

If your code appears in Tools>Macros>Organize>Python… you have created a Python macro. A macro can be distributed as an extension package but it IS NOT an extension in the narrower sense because it does not add any UNO service to the office suite.

I distribute Python macros with my own script installer [Solved] Retrieve embedded Python script display in Writer (View topic) • Apache OpenOffice Community Forum which saves any text file anywhere in the user profile, for instance Scripts/python/pythonpath/my_tools.py
It is a simple Basic macro wrapped in a text template.

Thanks for your answer ! I was mislead by the fact that I distribute my macros using an extension package. They’re quite well integrated in Libreoffice Menu, Toolbar, Configuration in Options… I really thought it was an extension ! I’m a bit disappointed :slight_smile:
Is there some documentation about building a ‘real’ python extension then? And in what sense, could it solve my issue?

https://wiki.openoffice.org/wiki/UNO_component_packaging

g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(
        Wavelet,
        "name.vojta.openoffice.Wavelet",
        ("com.sun.star.task.Job",),)

The above declaration saves you a lot of typing. You declare the name of your own service name and that it supports the c.s.s.task.Job service. The service name is also used in Addons.xcu.
The module header and declaration of your class look like:

import uno
import unohelper
from com.sun.star.task import XJobExecutor
 
class Wavelet( unohelper.Base, XJobExecutor ):``

Your class implements XJobExecutor with the help of unohelper.Base. The ImplementationHelper takes care of all the missing functions, such as dispose().
Once the extension has been installed successfully, any macro code calls the trigger method like this:

REM Basic
srv = createUnoService("name.vojta.openoffice.Wavelet")
srv.trigger("dummy")

I’m not proficient with this complicated stuff. I have written 3 Python extensions that happen to work somehow. I copied most of the framework stuff from other extensions (simple ones) and replaced the strings.

Thanks for your very encouraging post (btw are you the author of the Wavelet example?)

I just wonder how to bind menu and toolbar il you have more than one function. From what I see, it launch a default trigger() method.

It’s maybe the solution given above by @jimk having more classes ! One foreach function.