How do I invoke IPython from a macro?

I would like to be able to use an interactive shell for developing a macro. The answe to this question: How can I create books through py-uno? suggests one needs only to include

from IPython import embed as II
II()

in the macro, but that does not work and throws this error:

com.sun.star.uno.RuntimeExceptionError during invoking function macro1 in module file:///home/drew/.config/libreoffice/4/user/Scripts/python/my_macro_module.py (<class 'KeyError'>: 'ooo_script_framework'
  /usr/lib/python3/dist-packages/IPython/terminal/embed.py:211 in function mainloop() [module = sys.modules[global_ns['__name__']]]
  /usr/lib/python3/dist-packages/IPython/terminal/embed.py:158 in function __call__() [global_ns=global_ns, compile_flags=compile_flags)]
  /usr/lib/python3/dist-packages/IPython/terminal/embed.py:301 in function embed() [shell(header=header, stack_depth=2, compile_flags=compile_flags)]
  /home/drew/.config/libreoffice/4/user/Scripts/python/my_macro_module.py:10 in function macro1() [embed()]
  /usr/lib/libreoffice/program/pythonscript.py:869 in function invoke() [ret = self.func( *args )]
)

How can I make it work?

I will leave this for someone with specific Python knowledge to answer. There are links related to Python usage in LO here that may be of assistance.

The output above suggests you are trying to run your script from within LibO. That wouldn’t be all that helpful, I think, because I believe your REPL would likely be hidden to you. My answer to the other question perhaps erroneously assumed you were connecting to LibO in a “remote context”. Let me explain how to do that, in case it’s helpful.

Meanwhile, the answer to this question is “don’t embed IPython within a script that you are executing from within LibreOffice”.

Now, to get you started in case you do want to utilize LibO via a remote connection… I do not know what operating system you are running, but the below set of commands assumes Ubuntu. Note that $ is the prompt, and should not be typed by you:

  # From the raw command line, e.g., gnome-terminal, konsole, xterm
$ sudo apt-get update          # ensure you've the latest software indexes
$ apt-cache search ipython     # see what packages with 'ipython' are available
$ sudo apt-get install ipython # install the ipython package

The above just makes sure you’ve IPython available. The next starts LibO so that you can remotely connect to it:

$ libreoffice "--accept=socket,host=localhost,port=2002;urp;"

You can change that number to anything you like between 1025 and 65535 (assuming that port is not already in use by some other program), but 2002 seems to be the de facto LibO/OO choice. The next step is to get your Python script to connect to LibO on that port. Below is some boiler plate code to accomplish this:

#!/usr/bin/env python

from sys import stderr as SE   # 'SE' because I'm a lazy git.

from IPython import embed as II  # 'II' because it's a personal script, and I'm lazy.

try:
	# The order of these imports apparently matters.  Who would have guessed?
	# Not me ...
	import pyuno
	import uno
except ImportError:
	msg = ('Python bindings to pyuno or uno not found.  Try setting the '
	  'PYTHONPATH environment variable before running this script.  Like:\n'
	  '  export PYTHONPATH=/usr/lib/libreoffice/program\n' )
	SE.write( msg )
	raise

SE.write( 'Connecting to Libreoffice ... '); SE.flush()

localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext(
                 'com.sun.star.bridge.UnoUrlResolver', localContext )

connection_url = 'uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager'
# note that localhost means literally "this computer".  You could just as
# easily connect to any IP address with a waiting LibreOffice:
#connection_url = 'uno:socket,host=10.0.0.103,port=2002;urp;StarOffice.ServiceManager'
try:
	smgr = resolver.resolve( connection_url )
except:
	msg = ('\nUnable to connect to LibreOffice on port 2002.  Either start LO'
	  ' with\n'
	  '\n  $ libreoffice "--accept=socket,host=localhost,port=2002;urp;"\n'
	  "\nor update this script's connection string with the correct port.\n")
	SE.write( msg )
	raise

remoteContext = smgr.getPropertyValue( 'DefaultContext' )
desktop = smgr.createInstanceWithContext( 'com.sun.star.frame.Desktop', remoteContext)

SE.write( 'Success.'); SE.flush()

# Now, start your REPL (read-evaluate-print-loop) while developing:
SE.write( 'Starting the IPython REPL:\n\n' ); SE.flush()
II()

SE.write( '\n\nREPL exit.  Continuing to execute the rest of the script ...\n\n' )

SE.write( 'Opening new Writer document ...' ); SE.flush()

url = 'private:factory/swriter'
doc = desktop.loadComponentFromURL( url, '_blank', 0, () )

SE.write( 'Completed.  Empty Writer window should now be visible.' ); SE.flush()

II()  # now, experiment with the doc variable.  For example: doc.[tab][tab]

Now you’re off to the races. Let’s execute this script (say we called it connect_to_lib.py:

$ python connect_to_libo.py

Good luck!

Thanks, this work, I will ealuate the other answer. But I had to remove the line importing pyuno, it threw an import error on me, what is pyuno for? I use just “import uno” in the macro I am developing.

Also, as libreoffice uses python 3 (I am not sure if I can make it use python2), I guess it is best to use python3 (/usr/bin/python3 on my box) as well. Ubuntu (which is endeed my OS) still ships Python 2 as default. This also means I would need to have ipython3 installed, but I had it already.

Also, as karolous notes, in IPython, I connect to the document using odoc = desktop.CurrentComponent
In my macro run from calc itself, I use oDoc = XSCRIPTCONTEXT.getDocument(). What is the difference? Is not there a way that would work in both?

Both terms points to the same Objekt.
XSCRIPTCONTEXT is a global Variable used in LO-namespace from LO-UserInterface - this Var is not visible from remote - but you should able to add it with:

from pythonscript import ScriptContext
XSCRIPTCONTEXT = ScriptContext(client, None, None)
doc = XSCRIPTCONTEXT.getDocument()

@sup: regarding Py3: use it if you have the luxury, but it is not a requirement (I don’t think, anyway) with this use. This script is meant to run in its own process space and connect to LibO. This means that LibO doesn’t care what is talking to it, just that it’s speaking the correct language. That said, if the uno library is not Py2 compatible, then you are perhaps correct. Solution: go with what works.

@sup: regarding the XSCRIPTCONTEXT vs desktop … I am not an expert, but I think it is the difference between an internal macro and an external script. With your macro, you’re not connecting to LibO – you’re already in LibO’s process space because LibO is running your macro. Both this and @karolus answer are connecting your Python script – as an external process – to LibO: two separate processes communicating.

Hey Guys:
please give me some Karmapoints !!

Its not only the effort to write an answer - also much more to check it out !!

@hunteke Well, I could use Python two in IPython, but I use it just for developement, once the macro is made, I need to run it from inside Libreoffice and it uses python 3 by default If I am not mistaken.

Karolus: Thanks, that works!

@karolus: absolutely … how? I just write answers or ask questions on this site. The (karma)points aren’t where I’m focused. You are, however, so I’m happy to oblige … but how?

@sup: Py3: cool, then use Py3 (and you’re right, as of 4.0 it seems!)

@hunteke:
In General i’m also not focused on Karma, my comment should be signed by ;-)

karolus: you award karma by upvoting answers and comments, I think.

Hallo

I’m also several month ago struggle around the general Question[s]:

How to connect between LO and IPython ?
How to use IPython notebook as kind of Python-IDE for Libreoffice ?

and i came up with:

[Short Answer]:

  1. Start first from Console ipython notebook
    Connect remote to LO ( in same way as discribed by @hunteke )
    Have Fun !!

[Long Answer ]:

  1. If you’r working with LO-Package which comes from your Distribution (debian, ubuntu and derivates)
    everthing should be fine with @[short Answer] and goto 4.

  2. in case, you use the OriginalDownload-Packages from LO installed with sudo dpkg -i *.deb→:
    install ipython via: pip3 install --upgrade ipython --user
    run from Console:
    /opt/libreoffice4.x/program/python -m IPython notebook
    It fails ?### - ok probably you have to edit the python-startupscript and extend the PYTHONPATH (without linebreaks ) :

     PYTHONPATH=$sd_prog:$sd_prog/python-core-3.3.3/lib:$sd_prog/python-core-3.3.3/lib/lib-dynload:
     $sd_prog/python-core-3.3.3/lib/lib-tk:$sd_prog/python-core-3.3.3/lib/site-packages:/usr/lib/python3.3:
     /valid/path/to/directory_with `sqlite3`:  
     /valid/path/to/directory_with `sqlite3`/lib-dynload:
     /valid/path/to/directory with `pkg_resources.py`${PYTHONPATH+:$PYTHONPATH}  
    

    ### because they drop sqlite for unknown reasons. ;-((

  3. In case of Windows it should work if you copy the contents of Some site-packages-folder with IPython and Dependencies into $LO_program_folder/python-core3.3/lib/site-packages/ and run from Commandline the Command similar as described in 2.

  4. If everything works your webbrowser open http://localhost:8888/tree
    Klick on new Notebook and start LO in Pipe-mode in the first “Cell” with :

        from subprocess import Popen

        officepath = '/opt/libreoffice4.3/program/soffice'
        calc = '--calc'
        pipe = "--accept=pipe,name=abraxas;urp;StarOffice.Servicemanager"

        Popen([officepath, calc, pipe])   

    Calc opens ? - amazing - try to connect with:   

        import uno
        local = uno.getComponentContext()
        resolver = local.ServiceManager.createInstance("com.sun.star.bridge.UnoUrlResolver")

        client = resolver.resolve("uno:pipe,"
                           "name=abraxas;"
                           "urp;"
                           "StarOffice.ComponentContext")

        createUnoService = client.ServiceManager.createInstance

        (desktop,
         file_access,
         pathsubstition,
         mri ) = map(   createUnoService,
            ("com.sun.star.frame.Desktop",
             "com.sun.star.ucb.SimpleFileAccess",
             "com.sun.star.util.PathSubstitution",
             "mytools.Mri")
            )   
at this stage you have full access to the whole Objekt-tree , for Example the Current Calcdokument is available via
`doc = desktop.CurrentComponent` and of Course Tab-completitions works for `everyObjekt.<tab>`...

I am unaware of the uno:pipe connection. I’ll have to check that out! Meanwhile, I appreciate your use of the IPython Notebook. IPNB doesn’t work for me (in terms of how I develop, not in terms of actual function), but I wonder if it will be more approachable (given the WUI) than the CLI interaction my answer proposes. @sup: please do try these both and let us know which works for your brain (perhaps by accepting one as the answer), or if IPython is just not for you. I’m curious! :slight_smile:

some remarks:

pipe = "--accept=pipe,name=abraxas;urp;StarOffice.Servicemanager"

is roughly the same thing as:

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

except the pipe is by default restricted on connections made from the same machine.

with the socketkind your able to set a mask like:

host=192.0.0.0 to allow connections from localnet
or
host=0.0.0.0 to allow connection from everywhere in the world.

Hm, this seems amazing, but the web interface is rather confusing to me and seems like a hinderance. I am used to the text interface of ipython in the terminal, so I guess I will stick to it. Thanks anyway, though!

@sup:
Especially the IPython notebook is actual under rapid development, look and feel with an
actual version 2.1 is quietly better than with prior Versions of ipython.

Has you already tried an update with:
pip3 install --upgrade ipython --user ??

Well, I do not really see any advantage in webbased tool compared to a terminal based one - if I understand it correctly, it is good for presentation or mingling with graphs and so on, but neither is my use case, am I missing something?

I’m feel much more comfortable working on (web)-notebook[s] which the capability of writing, organizing , etc…and last not least to have my code in persistance state as somenote.ipynb

I use it not only as REPL also as IDE.

Karolus