1

I am trying to set up an comfortable environment to develop some python scripts for LibreOffice Calc.

Before I tried to edit .py files directly from "/home/user/.config/libreoffice/4/user/Scripts/python/". This would not let me debug the script, because if I start it in debug mode, most of the components, like XSCRIPTCONTEXT would not be found.

I decided to connect to LO directly via uno from my venv elsewhere.

I start my virtual environment with python -m venv --system-site-packages venv and activate it

Now which python gives ../somefolder/venv/bin/python and pip list shows pyuno (version 0.1.1) and unoserver (version 1.3).

EDIT: I installed them with pip from virtual environment. I just realized that pyuno in pip-repo is a different thing entirely (https://pypi.org/project/pyuno/) and I uninstalled it and its dependencies. So only unoserver is installed inside venv and uno-path is: /usr/lib/libreoffice/program/uno.py

Then I start unoserver with unoserver &. This created a soffice process listening on localhost:2002, which I verified with netstat -anpe | grep "2002".

Then I open a calc document. As mentioned here: https://ask.libreoffice.org/t/why-does-desktop-getcurrentcomponent-return-none-in-pyuno/59902 you should do it before running the script, lets say MySpreadsheet.ods and try tu run the following script (adapted from the link):

import uno
# import time

context = uno.getComponentContext()
resolver = context.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", context)
ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
smgr = ctx.ServiceManager

desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)

doc = desktop.getCurrentComponent()
print(doc.Title)

Upon variable inspection I can see that, all the variables are created. I do not know what to look for in all of them to verify the process, but when desktop = ... line is executed, that desktop object has all of the field None:

ComponentWindow: None
ContainerWindow: None
CurrentComponent: None
etc

which leads to the fact that desktop.getCurrentComponent() evaluates to None as well.

EDIT: When executing code I printed the created object sequence and it returns this:

context:

pyuno object (com.sun.star.uno.XComponentContext)0x558e2a7a1b20{, supportedInterfaces={com.sun.star.uno.XComponentContext,com.sun.star.container.XNameContainer,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak,com.sun.star.lang.XComponent}}

resolver

pyuno object (com.sun.star.uno.XInterface)0x558e2a941c60{implementationName=com.sun.star.comp.bridge.UnoUrlResolver, supportedServices={com.sun.star.bridge.UnoUrlResolver}, supportedInterfaces={com.sun.star.lang.XServiceInfo,com.sun.star.bridge.XUnoUrlResolver,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak}}

ctx

pyuno object (com.sun.star.uno.XInterface)0x7f1d88002b58{, supportedInterfaces={com.sun.star.uno.XComponentContext,com.sun.star.container.XNameContainer,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak,com.sun.star.lang.XComponent}}

smgr

pyuno object (com.sun.star.lang.XMultiComponentFactory)0x7f1d88002e78{implementationName=com.sun.star.comp.cppuhelper.bootstrap.ServiceManager, supportedServices={com.sun.star.lang.MultiServiceFactory,com.sun.star.lang.ServiceManager}, supportedInterfaces={com.sun.star.lang.XServiceInfo,com.sun.star.lang.XMultiServiceFactory,com.sun.star.lang.XMultiComponentFactory,com.sun.star.container.XSet,com.sun.star.container.XContentEnumerationAccess,com.sun.star.beans.XPropertySet,com.sun.star.beans.XPropertySetInfo,com.sun.star.lang.XEventListener,com.sun.star.lang.XInitialization,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak,com.sun.star.lang.XComponent}}

This answer to another post: https://stackoverflow.com/a/19158549/15452958 suggest to set PYTHONPATH to /usr/lib/libreoffice/program. Indeed pyuno.so is available in that folder and during debugging I can verify that uno is loaded from /usr/lib/libreoffice/program/uno.py.

Accepted answer here: Why does desktop.getCurrentComponent() return None in PyUNO? shows that I should wait until desktop becomes online. I tried and it did not work. I let it run like this for 5 minutes or so and doc was still None.

EDIT2: The output of netstat -anpe | grep "2002" now reads additional two lines for established connection.

tcp        0      0 127.0.0.1:2002          0.0.0.0:*               LISTEN      1000       13310724   213378/soffice.bin  
tcp        0      0 127.0.0.1:51848         127.0.0.1:2002          ESTABLISHED 1000       818657597  292648/python       
tcp        0      0 127.0.0.1:2002          127.0.0.1:51848         ESTABLISHED 1000       815824701  213378/soffice.bin 

In the documentation of older unoconv this resource is mentioned: [Tutorial] Import uno module to a different Python install http://user.services.openoffice.org/en/forum/viewtopic.php?f=45&t=36370&p=166783

As far as I understand this is irrelevant for this case as libreoffice uses system python anyway in linux.

I tried to run wget -O find_uno.py https://gist.githubusercontent.com/regebro/036da022dc7d5241a0ee97efdf1458eb/raw/find_uno.py python3 find_uno.py as shown in unoserver readme and it only gave me system python path.

What am I missing? Any hints or suggestions are appreciated.

Also if possible could someone explain the sequence of: context, resolver,ctx, smgr, desktop and what do these object means in layman terms?

laksdjfg
  • 15
  • 3
  • It sounds like you are trying to set up debugging in a special virtual environment, but perhaps a more typical start would be wiser. Have you worked through the tutorial at http://christopher5106.github.io/office/2015/12/06/openoffice-libreoffice-automate-your-office-tasks-with-python-macros.html with a standard setup? – Jim K Apr 18 '23 at 12:22
  • Thanks for the link. I skimmed through it at the beggining, but now after some struggle I can appreciate it better. I already have tried it like this: "The 2 other ways are to insert your script either globally on your computer, in your local LibreOffice installation." and it worked. I managed to write a script for basic functionality that was working, although it was a slight pain. Mainly because there were no autocompletion and debugging. Now when I want to extend it and I think it will require much more advanced calls, therefore I want to set up a way with a debug/autocomp. possibility – laksdjfg Apr 18 '23 at 14:18
  • In "First play with the Python shell to get familiar" section he describes exactly what I want to achieve, and it seems to be working. I am running the same commands (although I got them from another place) and it does not work for me. Although cleary the communication with libre office is fine as I am able to get all the objects except the last one. Any other solution that allows me to achieve debug and completion is also more than welcome. – laksdjfg Apr 18 '23 at 14:22
  • I just realized, sorry for the confusion with this: " I just want to modify some cells.. :D", I thought it was a "quick-fix" kind of problem, I removed it now ;) – laksdjfg Apr 18 '23 at 14:32
  • From these comments, it sounds like you're stuck somewhere in the tutorial. Did you successfully enter `soffice --calc --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"` in a terminal, and can you see the window? If so, then were you able to start a python shell and enter the code from `import uno` to `model = desktop.getCurrentComponent()`? I have personally performed these steps many times on various systems, so it should work if you do them correctly, unless there is something different about your system. Please also mention your operating system and version of LO. – Jim K Apr 19 '23 at 14:10
  • One more note: If you're hoping to set up debugging or autocomplete functionality, perhaps it's because you'd like to possibly take on a bigger project at some point. If so, let me say this by way of encouragement: Whether you'll get that functionality set up I'm not sure, but generally, programming with the UNO API gets easier later on, and it is very much doable to create large projects using python-uno. The struggle is primarily in the earlier stages when there is a lot to learn. Aids including MRI and possibly the APSO extension are important. – Jim K Apr 19 '23 at 14:21
  • It may also be worth mentioning that my setup consists of text editors with python syntax highlighting along with logging libraries, exception handling, unit testing, and pylint. It's flexible and easier to set up than the tightly integrated tools you're asking about. For pylint in particular, I've set up a collection of fakes based on the UNO API documentation so that it accepts those objects as valid code. If the API ever changes, or if I need a new type of object, I add a new file to the collection of fakes, but that doesn't happen very often. – Jim K Apr 19 '23 at 15:02
  • By the way, what is your IDE? If it's PyCharm, I gave an answer about it a few years ago: https://stackoverflow.com/questions/37182660/how-to-configure-pycharm-to-develop-libreoffice-python-macros. – Jim K Apr 19 '23 at 15:39
  • Ah stupid me :). `unoserver` starts `libreoffice` in `headless` mode. Here is the full command: `INFO:unoserver:Command: libreoffice --headless --invisible --nocrashreport --nodefault --nologo --nofirststartwizard --norestore -env:UserInstallation=file:///tmp/tmpe3v276_k --accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext`. I was basically doing it by starting `headless` process, then opening GUI in a separate one and wondering why would not it give me a GUI object :D. After trying with your command of course GUI was spawned for that process – laksdjfg Apr 19 '23 at 22:28
  • listening on a socket and it worked flawlessly and than it clicked. Should I post an answer, do you want to? My IDE is vscode. Maybe you could also describe your approach in detail, seems interesting. I do not understand the "collection of fakes" part. I think it might be useful for people stumbling upon this (like me.) – laksdjfg Apr 19 '23 at 22:28

1 Answers1

1

(Answer adapted from the comments which led to resolution of the problem):

Be sure to work through the tutorial at http://christopher5106.github.io/office/2015/12/06/openoffice-libreoffice-automate-your-office-tasks-with-python-macros.html.

From the comments, it sounds like you're stuck somewhere in the tutorial. Did you successfully enter the following in a terminal, and can you see the resulting window:

soffice --calc  --accept="socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"

You also asked for more information about pylint fakes. After further reading, I do not think this will be relevant for you. Anyway, for example if pylint complains about UNO objects when using a separate python distribution on Windows for static code checking, a workaround is to create a pylint-fakes directory as described at https://stackoverflow.com/a/9616857/5100564. For example, if pylint does not find XActionListener, you could create a file named pylint-fakes/com/sun/star/awt/__init__.py with the following mock code:

class XActionListener():
    pass
Jim K
  • 12,824
  • 2
  • 22
  • 51