|
|
""" Leo plugin for IPython
|
|
|
|
|
|
Example use:
|
|
|
|
|
|
nodes.foo = "hello world"
|
|
|
|
|
|
-> create '@ipy foo' node with text "hello world"
|
|
|
|
|
|
Access works also, and so does tab completion.
|
|
|
|
|
|
"""
|
|
|
import IPython.ipapi
|
|
|
import IPython.genutils
|
|
|
import IPython.generics
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
|
|
ip = IPython.ipapi.get()
|
|
|
leo = ip.user_ns['leox']
|
|
|
c,g = leo.c, leo.g
|
|
|
|
|
|
# will probably be overwritten by user, but handy for experimentation early on
|
|
|
ip.user_ns['c'] = c
|
|
|
ip.user_ns['g'] = g
|
|
|
|
|
|
|
|
|
from IPython.external.simplegeneric import generic
|
|
|
import pprint
|
|
|
|
|
|
@generic
|
|
|
def format_for_leo(obj):
|
|
|
""" Convert obj to string representiation (for editing in Leo)"""
|
|
|
return pprint.pformat(obj)
|
|
|
|
|
|
@format_for_leo.when_type(list)
|
|
|
def format_list(obj):
|
|
|
return "\n".join(str(s) for s in obj)
|
|
|
|
|
|
nodename_re = r'(@ipy?[\w-]+)?\s?(\w+)'
|
|
|
|
|
|
def all_cells():
|
|
|
d = {}
|
|
|
for p in c.allNodes_iter():
|
|
|
h = p.headString()
|
|
|
if h.startswith('@') and len(h.split()) == 1:
|
|
|
continue
|
|
|
mo = re.match(nodename_re, h)
|
|
|
if not mo:
|
|
|
continue
|
|
|
d[mo.group(2)] = p.copy()
|
|
|
return d
|
|
|
|
|
|
|
|
|
class TrivialLeoWorkbook:
|
|
|
""" class to find cells """
|
|
|
def __getattr__(self, key):
|
|
|
cells = all_cells()
|
|
|
p = cells[key]
|
|
|
body = p.bodyString()
|
|
|
return eval_body(body)
|
|
|
def __setattr__(self,key,val):
|
|
|
cells = all_cells()
|
|
|
p = cells.get(key,None)
|
|
|
if p is None:
|
|
|
add_var(key,val)
|
|
|
else:
|
|
|
c.setBodyString(p,format_for_leo(val))
|
|
|
def __str__(self):
|
|
|
return "<TrivialLeoWorkbook>"
|
|
|
__repr__ = __str__
|
|
|
|
|
|
ip.user_ns['nodes'] = TrivialLeoWorkbook()
|
|
|
|
|
|
|
|
|
class LeoNode(object):
|
|
|
def __init__(self,p):
|
|
|
self.p = p.copy()
|
|
|
|
|
|
def get_h(self): return self.p.headString()
|
|
|
def set_h(self,val):
|
|
|
print "set head",val
|
|
|
c.setHeadString(self.p,val)
|
|
|
|
|
|
h = property( get_h, set_h)
|
|
|
|
|
|
def get_b(self): return self.p.bodyString()
|
|
|
def set_b(self,val):
|
|
|
print "set body",val
|
|
|
c.setBodyString(self.p, val)
|
|
|
|
|
|
b = property(get_b, set_b)
|
|
|
|
|
|
def set_val(self, val):
|
|
|
self.b = pprint.pformat(val)
|
|
|
|
|
|
val = property(lambda self: ip.ev(self.b.strip()), set_val)
|
|
|
|
|
|
def set_l(self,val):
|
|
|
self.b = '\n'.join(val )
|
|
|
l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
|
|
|
set_l)
|
|
|
|
|
|
def __iter__(self):
|
|
|
return (LeoNode(p) for p in self.p.children_iter())
|
|
|
|
|
|
|
|
|
class LeoWorkbook:
|
|
|
""" class for 'advanced' node access """
|
|
|
def __getattr__(self, key):
|
|
|
if key.startswith('_') or key == 'trait_names':
|
|
|
raise AttributeError
|
|
|
cells = all_cells()
|
|
|
p = cells.get(key, None)
|
|
|
if p is None:
|
|
|
p = add_var(key,None)
|
|
|
|
|
|
return LeoNode(p)
|
|
|
|
|
|
def __str__(self):
|
|
|
return "<LeoWorkbook>"
|
|
|
__repr__ = __str__
|
|
|
ip.user_ns['wb'] = LeoWorkbook()
|
|
|
|
|
|
|
|
|
_dummyval = object()
|
|
|
@IPython.generics.complete_object.when_type(LeoWorkbook)
|
|
|
def workbook_complete(obj, prev):
|
|
|
return all_cells().keys()
|
|
|
|
|
|
|
|
|
def add_var(varname, value = _dummyval):
|
|
|
nodename = '@ipy-var ' + varname
|
|
|
p2 = g.findNodeAnywhere(c,nodename)
|
|
|
if not c.positionExists(p2):
|
|
|
p2 = c.currentPosition().insertAfter()
|
|
|
c.setHeadString(p2,'@ipy ' + varname)
|
|
|
|
|
|
c.setCurrentPosition(p2)
|
|
|
if value is _dummyval:
|
|
|
val = ip.user_ns[varname]
|
|
|
else:
|
|
|
val = value
|
|
|
if val is not None:
|
|
|
formatted = format_for_leo(val)
|
|
|
c.setBodyString(p2,formatted)
|
|
|
return p2
|
|
|
|
|
|
def add_file(self,fname):
|
|
|
p2 = c.currentPosition().insertAfter()
|
|
|
|
|
|
def push_script(p):
|
|
|
ohist = ip.IP.output_hist
|
|
|
hstart = len(ip.IP.input_hist)
|
|
|
script = g.getScript(c,p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
|
|
|
|
|
|
script = g.splitLines(script + '\n')
|
|
|
script = ''.join(z for z in script if z.strip())
|
|
|
|
|
|
ip.runlines(script)
|
|
|
|
|
|
has_output = False
|
|
|
for idx in range(hstart,len(ip.IP.input_hist)):
|
|
|
val = ohist.get(idx,None)
|
|
|
if val is None:
|
|
|
continue
|
|
|
has_output = True
|
|
|
inp = ip.IP.input_hist[idx]
|
|
|
if inp.strip():
|
|
|
g.es('In: %s' % (inp[:40], ), tabName = 'IPython')
|
|
|
|
|
|
g.es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)), tabName = 'IPython')
|
|
|
|
|
|
if not has_output:
|
|
|
g.es('ipy run: %s' %( p.headString(),), tabName = 'IPython')
|
|
|
|
|
|
|
|
|
def eval_body(body):
|
|
|
try:
|
|
|
val = ip.ev(body)
|
|
|
except:
|
|
|
# just use stringlist if it's not completely legal python expression
|
|
|
val = IPython.genutils.SList(body.splitlines())
|
|
|
return val
|
|
|
|
|
|
def push_variable(p,varname):
|
|
|
body = p.bodyString()
|
|
|
val = eval_body(body.strip())
|
|
|
ip.user_ns[varname] = val
|
|
|
g.es('ipy var: %s' % (varname,), tabName = "IPython")
|
|
|
|
|
|
def push_from_leo(p):
|
|
|
# headstring without @ are just scripts
|
|
|
if not p.headString().startswith('@'):
|
|
|
push_script(p)
|
|
|
return
|
|
|
tup = p.headString().split(None,1)
|
|
|
# @ipy foo is variable foo
|
|
|
if len(tup) == 2 and tup[0] == '@ipy':
|
|
|
varname = tup[1]
|
|
|
push_variable(p,varname)
|
|
|
return
|
|
|
|
|
|
ip.user_ns['leox'].push = push_from_leo
|
|
|
|
|
|
def leo_f(self,s):
|
|
|
ip = self.getapi()
|
|
|
s = s.strip()
|
|
|
if s in ip.user_ns:
|
|
|
add_var(s)
|
|
|
elif os.path.isfile(s):
|
|
|
# todo open file
|
|
|
pass
|
|
|
|
|
|
ip.expose_magic('leo',leo_f)
|
|
|
|