Edit detail for LeoBridgeSubprocess revision 3 of 3

1 2 3
Editor: terry_n_brown
Time: 2007/05/17 13:09:48 GMT-7
Note:

changed:
-in a subprocess.  That turned out to be more, um, interesting, than
in a subprocess.  That turned out to be more, um, interesting than

This is one of those "there's no need for this but I'm going to do it anyway" things.

Currently (20070517) you can't use LeoBridge? from within Leo. There are several workarounds, as discussed in this thread: http://sourceforge.net/forum/forum.php?thread_id=1736806&forum_id=10228

But I decided to attempt another workaround, run the LeoBridge? script in a subprocess. That turned out to be more, um, interesting than anticipated, so I'm recording the results here, in case these issues come up again.

The idea is that script A running in Leo (i.e. in a regular GUI Leo session) calls script B through subprocess.Popen(), script B uses LeoBridge? to do something (parse unloaded Leo files), and returns the result to script A.

Passing the result back via the clipboard seemed like a possibility, but XWindows? / tcl/tk clipboard madness being what it is, that didn't seem to work.

First trick, calling script B from script A:

import subprocess
p = subprocess.Popen(('python',
                      path_to_script_B,
                      parameter_for_script_B,),
                     stdout=subprocess.PIPE,
                     env={'PYTHONPATH': g.app.loadDir,
                          'USER': g.app.leoID}
                     )
p.wait()

Setting PYTHONPATH in the environment seemed like the easiest way to let script B find leoBridge.py (which it needs to import). But by setting the env parameter you limit script B's environment to be only PYTHONPATH, which causes leoBridge to fail because, in unix at least, it depends on USER in the environment. So you need to pass that through too.

Now, because passing stuff back on the clipboard seems unreliable, at least in XWindows?, script B passes results back to script A via stdout (print), but there's some Leo initialization chatter you want to avoid. So put a sentinel, 'START_CLIPBOARD', in the output, and collect it like this:

response = p.stdout.readlines()
while response and 'START_CLIPBOARD' not in response[0]:
  del response[0]
del response[0]  # delete the sentinel as well
response = ''.join(response)

This is the basic mechanism. What I actually wanted to do was have script B generate a branch of nodes and pass that back to script A for insertion in the tree script A is running in. That's relatively easy if you use:

c.setCurrentPosition(pos_of_branch_to_return)
c.copyOutline()
print '<!-- START_CLIPBOARD -->'
print g.app.gui.getTextFromClipboard()
print '<!-- END_CLIPBOARD -->'

at the end of script B, and back in script A, after you've rebuilt response as shown above, just:

g.app.gui.replaceClipboardWith(response)
c.pasteOutline()