In MacOS adding an listener with python code upon opening a new spreadsheet failed

Hi guys, I have a strange problem. I wrote some python code to open a brand new calc document and upon opening the spreadsheet, some Xmodifylisteners are registered to monitor the changing values of some cells. It works in my Windows and raspberrypi Linux OSs, but failed in my Mac laptop. I thought it may have something to do with my code so I decided to try this example python macro Monitoring Document Events and followed the guidance of this post How to get save listener event to python code - #3 by Nancy2510 by issuing the following command:

soffice ‘vnd.sun.star.script:test2.py$OnLoad?language=Python&location=user’ test.ods

test2.py is the name I saved for the example code and put in the right folder. Obviously the file was found and executed but still failed with the following message:

com.sun.star.uno.RuntimeException: Error during invoking function OnLoad in module file:///Users/edwinli/Library/Application%20Support/LibreOffice/4/user/Scripts/python/test2.py (<class ‘AttributeError’>: ‘NoneType’ object has no attribute ‘addDocumentEventListener’
File “/Applications/LibreOffice.app/Contents/Resources/pythonscript.py”, line 915, in invoke
ret = self.func( *args )
File “/Users/edwinli/Library/Application Support/LibreOffice/4/user/Scripts/python/test2.py”, line 62, in OnLoad
listener = UiDocument() # Initiates listening
File “/Users/edwinli/Library/Application Support/LibreOffice/4/user/Scripts/python/test2.py”, line 26, in init
self.listen() # Start monitoring doc. events
File “/Users/edwinli/Library/Application Support/LibreOffice/4/user/Scripts/python/test2.py”, line 41, in listen
self.doc.addDocumentEventListener(self)
)

I wonder what I did wrong? Any help is greatly appreciated. Thanks in advance.
(By the way, if I just run the macro from the opened spreadsheet it has no problem.)

Ed

self.doc is unset. Check your init method.

Hi Villeroy, thanks for your reply. I think the self.doc is set at the class instantiation if you look at the original code:

The listen function is called after the doc is set.

And also it works in Linux and Windows OSs.

To further clarify, I did some more testing across all the operating systems that I currently can access.

In Windows 11, I can issue the following command

“C:\Program Files\LibreOffice\program\soffice.exe” “vnd.sun.star.script:test2.py$OnLoad?language=Python&location=user” test.ods

and the example code will execute correctly. (Note that I need to wrap around vnd…user with double quotes in Windows.)

I also have a Windows WSL with a Ubuntu subsystem in the same laptop and if I issue the following command

soffice ‘vnd.sun.star.script:test2.py$OnLoad?language=Python&location=user’ test.ods

and it works too. In both cases test.ods is a 0 byte blank document.

In my raspberrypi machine (Debian 12 bookworm) things are a little different. If the spreadsheet file test.ods is a blank file I got exactly the same error message as in my opening post. Only if I use LibreOffice to open and save a spreadsheet test.ods and then close it, then the command

soffice ‘vnd.sun.star.script:test2.py$OnLoad?language=Python&location=user’ test.ods

will work.

Unfortunately, this extra step still does not work in the Mac laptop (macOS Sequoia 15.1.1). I still get the same error message.

If I open a spreadsheet document first and run the code as macro, it will work for all the OS systems.

So my question is, other than opening the spreadsheet first and run the code, is there a workaround that works for all systems?

Thanks for your attention.

Ed

If this happens to be a macro, try
self.doc =XSCRIPTCONTEXT.getDocument()
Won’t work with an extension.

Thanks Villeroy for your quick response. Yes I did try that, to no avail.

:question:

So in WSL I just use touch test.ods to create the file, so the file size is 0 byte. In raspberrypi I have to create a new file test.ods in LibreOffice and then save and exit LibreOffice. The file created this way has a size of ~6500 bytes, and I guess it’s a proper LibreOffice spreadsheet file, even if I didn’t enter any data in it.

So since the example code always works if I open a spreadsheet and run it as a macro, I thought maybe I can simulate that with the DispatchHelper as a workaround. So after I opened the calc doc and got the service manager object and connect to the document, I created the dispatcher this way:
componentContext = smgr.getPropertyValue(‘DefaultContext’)
oDisp = smgr.createInstanceWithContext(‘com.sun.star.frame.DispatchHelper’, componentContext)

and then I tried to set the property value and run the code:
propVal = PropertyValue()
propVal.Name = ‘Script’
propVal.Value = ‘vnd.sun.star.script:test2.py$OnLoad?language=Python&location=user’
oDisp.executeDispatch(oDoc.CurrentController.Frame, ‘.uno:RunMacro’, ‘’, 0, propVal)

Unfortunately what I got is the run macro dialog box as if I opened it manually, and I have to find the macro and click the OK button, etc., etc.

My question is: can I run a macro this way without manual intervention? If so is there any documentation about the uno:RunMacro and how to set the property values? Really appreciate any help.

Do you really try to add a script event on document open? Why don’t you simply work with a template where the script event is preconfigured?

Thanks Villeroy fro your comment. Yes originally that was how I approached it. But since then my client made a comment that it would be easier to distribute the program to others in his company with just one file: either a spreadsheet with the python macro embedded or a python script without the spreadsheet attached. Spreadsheet only is a fine solution but if anybody needs to modify the program then they will have to add the APSO extension to export the script and a whole lot of other headaches. So I am just exploring different possibilities. :slightly_smiling_face:

The script events are stored with the document or template. There is no need to do that programmatically.
By the way, dispatch macros are a no go anyway. It takes several weeks to master the UNO API, given that you invest your full free time.

Finally I found a solution to my problem.

I always thought my idea of using a python script to open a new spreadsheet and then install a listener on the doc with the script is sound. For one thing it had worked in Windows and Linux OSs. In MacOS, it failed at the last line (oDoc=…), complained about oDoc being a None object.

First I thought it was a timing issue, so I added a loop
Screenshot 2025-01-10 at 8.17.50 AM

but it got stuck in the loop. By chance I clicked on the document window and it promptly broke out of the loop and the rest of my code was executed and listeners installed. Obviously the desktop object is the main culprit. So with the help of MRI and lots of trial and errors, I managed to find the frame that contains the newly opened calc document by adding the following code:

Screenshot 2025-01-10 at 8.22.59 AM

From there oDoc object can be found. :slightly_smiling_face:

By the way, I also found a way to open a macro by importing XScript: