##// END OF EJS Templates
ipy_leo: doc improvements
Ville M. Vainio -
Show More
@@ -1,409 +1,409 b''
1 1 """ ILeo - Leo plugin for IPython
2 2
3 3
4 4 """
5 5 import IPython.ipapi
6 6 import IPython.genutils
7 7 import IPython.generics
8 8 from IPython.hooks import CommandChainDispatcher
9 9 import re
10 10 import UserDict
11 11 from IPython.ipapi import TryNext
12 12
13 13 ip = IPython.ipapi.get()
14 14 leo = ip.user_ns['leox']
15 15 c,g = leo.c, leo.g
16 16
17 17 # will probably be overwritten by user, but handy for experimentation early on
18 18 ip.user_ns['c'] = c
19 19 ip.user_ns['g'] = g
20 20
21 21
22 22 from IPython.external.simplegeneric import generic
23 23 import pprint
24 24
25 25 def es(s):
26 26 g.es(s, tabName = 'IPython')
27 27 pass
28 28
29 29 @generic
30 30 def format_for_leo(obj):
31 31 """ Convert obj to string representiation (for editing in Leo)"""
32 32 return pprint.pformat(obj)
33 33
34 34 @format_for_leo.when_type(list)
35 35 def format_list(obj):
36 36 return "\n".join(str(s) for s in obj)
37 37
38 38 attribute_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
39 39 def valid_attribute(s):
40 40 return attribute_re.match(s)
41 41
42 42 def all_cells():
43 43 d = {}
44 44 for p in c.allNodes_iter():
45 45 h = p.headString()
46 46 if h.startswith('@a '):
47 47 d[h.lstrip('@a ').strip()] = p.parent().copy()
48 48 elif not valid_attribute(h):
49 49 continue
50 50 d[h] = p.copy()
51 51 return d
52 52
53 53
54 54
55 55 def eval_node(n):
56 56 body = n.b
57 57 if not body.startswith('@cl'):
58 58 # plain python repr node, just eval it
59 59 return ip.ev(n.b)
60 60 # @cl nodes deserve special treatment - first eval the first line (minus cl), then use it to call the rest of body
61 61 first, rest = body.split('\n',1)
62 62 tup = first.split(None, 1)
63 63 # @cl alone SPECIAL USE-> dump var to user_ns
64 64 if len(tup) == 1:
65 65 val = ip.ev(rest)
66 66 ip.user_ns[n.h] = val
67 67 es("%s = %s" % (n.h, repr(val)[:20] ))
68 68 return val
69 69
70 70 cl, hd = tup
71 71
72 72 xformer = ip.ev(hd.strip())
73 73 es('Transform w/ %s' % repr(xformer))
74 74 return xformer(rest, n)
75 75
76 76 class LeoNode(object, UserDict.DictMixin):
77 77 """ Node in Leo outline
78 78
79 79 Most important attributes (getters/setters available:
80 80 .v - evaluate node, can also be alligned
81 81 .b, .h - body string, headline string
82 82 .l - value as string list
83 83
84 84 Also supports iteration,
85 85
86 86 setitem / getitem (indexing):
87 87 wb.foo['key'] = 12
88 88 assert wb.foo['key'].v == 12
89 89
90 90 Note the asymmetry on setitem and getitem! Also other
91 91 dict methods are available.
92 92
93 93 .ipush() - run push-to-ipython
94 94
95 95 """
96 96 def __init__(self,p):
97 97 self.p = p.copy()
98 98
99 99 def __get_h(self): return self.p.headString()
100 100 def __set_h(self,val):
101 101 print "set head",val
102 102 c.beginUpdate()
103 103 try:
104 104 c.setHeadString(self.p,val)
105 105 finally:
106 106 c.endUpdate()
107 107
108 108 h = property( __get_h, __set_h, doc = "Node headline string")
109 109
110 110 def __get_b(self): return self.p.bodyString()
111 111 def __set_b(self,val):
112 112 print "set body",val
113 113 c.beginUpdate()
114 114 try:
115 115 c.setBodyString(self.p, val)
116 116 finally:
117 117 c.endUpdate()
118 118
119 119 b = property(__get_b, __set_b, doc = "Nody body string")
120 120
121 121 def __set_val(self, val):
122 122 self.b = format_for_leo(val)
123 123
124 124 v = property(lambda self: eval_node(self), __set_val, doc = "Node evaluated value")
125 125
126 126 def __set_l(self,val):
127 127 self.b = '\n'.join(val )
128 128 l = property(lambda self : IPython.genutils.SList(self.b.splitlines()),
129 129 __set_l, doc = "Node value as string list")
130 130
131 131 def __iter__(self):
132 132 """ Iterate through nodes direct children """
133 133
134 134 return (LeoNode(p) for p in self.p.children_iter())
135 135
136 136 def __children(self):
137 137 d = {}
138 138 for child in self:
139 139 head = child.h
140 140 tup = head.split(None,1)
141 141 if len(tup) > 1 and tup[0] == '@k':
142 142 d[tup[1]] = child
143 143 continue
144 144
145 145 if not valid_attribute(head):
146 146 d[head] = child
147 147 continue
148 148 return d
149 149 def keys(self):
150 150 d = self.__children()
151 151 return d.keys()
152 152 def __getitem__(self, key):
153 153 """ wb.foo['Some stuff'] Return a child node with headline 'Some stuff'
154 154
155 155 If key is a valid python name (e.g. 'foo'), look for headline '@k foo' as well
156 156 """
157 157 key = str(key)
158 158 d = self.__children()
159 159 return d[key]
160 160 def __setitem__(self, key, val):
161 161 """ You can do wb.foo['My Stuff'] = 12 to create children
162 162
163 163 This will create 'My Stuff' as a child of foo (if it does not exist), and
164 164 do .v = 12 assignment.
165 165
166 166 Exception:
167 167
168 168 wb.foo['bar'] = 12
169 169
170 170 will create a child with headline '@k bar', because bar is a valid python name
171 171 and we don't want to crowd the WorkBook namespace with (possibly numerous) entries
172 172 """
173 173 key = str(key)
174 174 d = self.__children()
175 175 if key in d:
176 176 d[key].v = val
177 177 return
178 178
179 179 if not valid_attribute(key):
180 180 head = key
181 181 else:
182 182 head = '@k ' + key
183 183 p = c.createLastChildNode(self.p, head, '')
184 184 LeoNode(p).v = val
185 185 def __delitem__(self,key):
186 186 pass
187 187 def ipush(self):
188 188 """ Does push-to-ipython on the node """
189 189 push_from_leo(self)
190 190 def go(self):
191 191 """ Set node as current node (to quickly see it in Outline) """
192 192 c.beginUpdate()
193 193 try:
194 194 c.setCurrentPosition(self.p)
195 195 finally:
196 196 c.endUpdate()
197 197
198 198 def __get_uA(self):
199 199 p = self.p
200 200 # Create the uA if necessary.
201 201 if not hasattr(p.v.t,'unknownAttributes'):
202 202 p.v.t.unknownAttributes = {}
203 203
204 204 d = p.v.t.unknownAttributes.setdefault('ipython', {})
205 205 return d
206 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node'")
206 uA = property(__get_uA, doc = "Access persistent unknownAttributes of node")
207 207
208 208
209 209 class LeoWorkbook:
210 210 """ class for 'advanced' node access
211 211
212 212 Has attributes for all "discoverable" nodes. Node is discoverable if it
213 213 either
214 214
215 215 - has a valid python name (Foo, bar_12)
216 216 - is a parent of an anchor node (if it has a child '@a foo', it is visible as foo)
217 217
218 218 """
219 219 def __getattr__(self, key):
220 220 if key.startswith('_') or key == 'trait_names' or not valid_attribute(key):
221 221 raise AttributeError
222 222 cells = all_cells()
223 223 p = cells.get(key, None)
224 224 if p is None:
225 225 p = add_var(key)
226 226
227 227 return LeoNode(p)
228 228
229 229 def __str__(self):
230 230 return "<LeoWorkbook>"
231 231 def __setattr__(self,key, val):
232 232 raise AttributeError("Direct assignment to workbook denied, try wb.%s.v = %s" % (key,val))
233 233
234 234 __repr__ = __str__
235 235
236 236 def __iter__(self):
237 237 """ Iterate all (even non-exposed) nodes """
238 238 cells = all_cells()
239 239 return (LeoNode(p) for p in c.allNodes_iter())
240 240
241 241 ip.user_ns['wb'] = LeoWorkbook()
242 242
243 243
244 244
245 245 @IPython.generics.complete_object.when_type(LeoWorkbook)
246 246 def workbook_complete(obj, prev):
247 247 return all_cells().keys()
248 248
249 249
250 250 def add_var(varname):
251 251 c.beginUpdate()
252 252 try:
253 253 p2 = g.findNodeAnywhere(c,varname)
254 254 if p2:
255 255 return
256 256
257 257 rootpos = g.findNodeAnywhere(c,'@ipy-results')
258 258 if not rootpos:
259 259 rootpos = c.currentPosition()
260 260 p2 = rootpos.insertAsLastChild()
261 261 c.setHeadString(p2,varname)
262 262 return p2
263 263 finally:
264 264 c.endUpdate()
265 265
266 266 def add_file(self,fname):
267 267 p2 = c.currentPosition().insertAfter()
268 268
269 269 push_from_leo = CommandChainDispatcher()
270 270
271 271 def expose_ileo_push(f, prio = 0):
272 272 push_from_leo.add(f, prio)
273 273
274 274 def push_ipython_script(node):
275 275 """ Execute the node body in IPython, as if it was entered in interactive prompt """
276 276 c.beginUpdate()
277 277 try:
278 278 ohist = ip.IP.output_hist
279 279 hstart = len(ip.IP.input_hist)
280 280 script = g.getScript(c,node.p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
281 281
282 282 script = g.splitLines(script + '\n')
283 283
284 284 ip.runlines(script)
285 285
286 286 has_output = False
287 287 for idx in range(hstart,len(ip.IP.input_hist)):
288 288 val = ohist.get(idx,None)
289 289 if val is None:
290 290 continue
291 291 has_output = True
292 292 inp = ip.IP.input_hist[idx]
293 293 if inp.strip():
294 294 es('In: %s' % (inp[:40], ))
295 295
296 296 es('<%d> %s' % (idx, pprint.pformat(ohist[idx],width = 40)))
297 297
298 298 if not has_output:
299 299 es('ipy run: %s (%d LL)' %( node.h,len(script)))
300 300 finally:
301 301 c.endUpdate()
302 302
303 303 # this should be the LAST one that will be executed, and it will never raise TryNext
304 304 expose_ileo_push(push_ipython_script, 1000)
305 305
306 306 def eval_body(body):
307 307 try:
308 308 val = ip.ev(body)
309 309 except:
310 310 # just use stringlist if it's not completely legal python expression
311 311 val = IPython.genutils.SList(body.splitlines())
312 312 return val
313 313
314 314 def push_plain_python(node):
315 315 if not node.h.endswith('P'):
316 316 raise TryNext
317 317 script = g.getScript(c,node.p,useSelectedText=False,forcePythonSentinels=False,useSentinels=False)
318 318 lines = script.count('\n')
319 319 try:
320 320 exec script in ip.user_ns
321 321 except:
322 322 print " -- Exception in script:\n"+script + "\n --"
323 323 raise
324 324 es('ipy plain: %s (%d LL)' % (node.h,lines))
325 325
326 326 expose_ileo_push(push_plain_python, 100)
327 327
328 328 def push_cl_node(node):
329 329 """ If node starts with @cl, eval it
330 330
331 331 The result is put to root @ipy-results node
332 332 """
333 333 if not node.b.startswith('@cl'):
334 334 raise TryNext
335 335
336 336 p2 = g.findNodeAnywhere(c,'@ipy-results')
337 337 val = node.v
338 338 if p2:
339 339 es("=> @ipy-results")
340 340 LeoNode(p2).v = val
341 341 es(val)
342 342
343 343 expose_ileo_push(push_cl_node,100)
344 344
345 345 def push_position_from_leo(p):
346 346 push_from_leo(LeoNode(p))
347 347
348 348 ip.user_ns['leox'].push = push_position_from_leo
349 349
350 350 def leo_f(self,s):
351 351 """ open file(s) in Leo
352 352
353 353 Takes an mglob pattern, e.g. '%leo *.cpp' or %leo 'rec:*.cpp'
354 354 """
355 355 import os
356 356 from IPython.external import mglob
357 357
358 358 files = mglob.expand(s)
359 359 c.beginUpdate()
360 360 try:
361 361 for fname in files:
362 362 p = g.findNodeAnywhere(c,'@auto ' + fname)
363 363 if not p:
364 364 p = c.currentPosition().insertAfter()
365 365
366 366 p.setHeadString('@auto ' + fname)
367 367 if os.path.isfile(fname):
368 368 c.setBodyString(p,open(fname).read())
369 369 c.selectPosition(p)
370 370 finally:
371 371 c.endUpdate()
372 372
373 373 ip.expose_magic('leo',leo_f)
374 374
375 375 def leoref_f(self,s):
376 376 """ Quick reference for ILeo """
377 377 import textwrap
378 378 print textwrap.dedent("""\
379 379 %leo file - open file in leo
380 380 wb.foo.v - eval node foo (i.e. headstring is 'foo' or '@ipy foo')
381 381 wb.foo.v = 12 - assign to body of node foo
382 382 wb.foo.b - read or write the body of node foo
383 383 wb.foo.l - body of node foo as string list
384 384
385 385 for el in wb.foo:
386 386 print el.v
387 387
388 388 """
389 389 )
390 390 ip.expose_magic('leoref',leoref_f)
391 391
392 392 def show_welcome():
393 393 print "------------------"
394 394 print "Welcome to Leo-enabled IPython session!"
395 395 print "Try %leoref for quick reference."
396 396 import IPython.platutils
397 397 IPython.platutils.set_term_title('ILeo')
398 398 IPython.platutils.freeze_term_title()
399 399
400 400 def run_leo_startup_node():
401 401 p = g.findNodeAnywhere(c,'@ipy-startup')
402 402 if p:
403 403 print "Running @ipy-startup nodes"
404 404 for n in LeoNode(p):
405 405 push_from_leo(n)
406 406
407 407 run_leo_startup_node()
408 408 show_welcome()
409 409
@@ -1,409 +1,508 b''
1 1 <?xml version="1.0" encoding="utf-8"?>
2 2 <?xml-stylesheet ekr_test?>
3 3 <leo_file>
4 4 <leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
5 <globals body_outline_ratio="0.5">
6 <global_window_position top="261" left="404" height="621" width="1280"/>
5 <globals body_outline_ratio="0.307814992026">
6 <global_window_position top="140" left="145" height="627" width="1280"/>
7 7 <global_log_window_position top="0" left="0" height="0" width="0"/>
8 8 </globals>
9 9 <preferences/>
10 10 <find_panel_settings/>
11 11 <vnodes>
12 <v t="vivainio.20080222193236" a="E"><vh>Documentation</vh>
13 <v t="vivainio.20080223121915" a="E" tnodeList="vivainio.20080223121915,vivainio.20080222193236.1,vivainio.20080223133858,vivainio.20080223133922,vivainio.20080223133947,vivainio.20080223134018,vivainio.20080223134100,vivainio.20080223134118,vivainio.20080223134433,vivainio.20080223142207,vivainio.20080223134136"><vh>@nosent ileointro.txt</vh>
14 <v t="vivainio.20080222193236.1" a="E"><vh>Documentation</vh>
15 <v t="vivainio.20080223133858"><vh>Introduction</vh></v>
16 <v t="vivainio.20080223133922"><vh>Installation</vh></v>
17 <v t="vivainio.20080223133947"><vh>Accessing IPython from Leo</vh></v>
18 <v t="vivainio.20080223134018" a="TV"><vh>Accessing Leo nodes from IPython</vh></v>
19 <v t="vivainio.20080223134100"><vh>Cl definitions</vh></v>
20 <v t="vivainio.20080223134118"><vh>Special node types</vh></v>
21 <v t="vivainio.20080223134433"><vh>Custom push</vh></v>
22 <v t="vivainio.20080223142207" a="E"><vh>Code snippets</vh></v>
23 <v t="vivainio.20080223134136"><vh>Acknowledgements and history</vh></v>
24 </v>
25 </v>
26 </v>
12 27 <v t="vivainio.20080218184525"><vh>@chapters</vh></v>
13 <v t="vivainio.20080223133721" a="E"><vh>@settings</vh>
28 <v t="vivainio.20080223133721"><vh>@settings</vh>
14 29 <v t="vivainio.20080223133721.1"><vh>@enabled-plugins</vh></v>
15 30 </v>
16 31 <v t="vivainio.20080218184540" a="E"><vh>@ipy-startup</vh>
17 32 <v t="vivainio.20080218184613.1"><vh>b</vh></v>
18 <v t="vivainio.20080218200031" a="E"><vh>Some classes P</vh>
33 <v t="vivainio.20080218200031"><vh>Some classes P</vh>
19 34 <v t="vivainio.20080218190816"><vh>File-like access</vh></v>
20 35 <v t="vivainio.20080218200106"><vh>csv data</vh></v>
21 36 <v t="vivainio.20080219225120"><vh>String list</vh></v>
22 37 <v t="vivainio.20080219230342"><vh>slist to leo</vh></v>
23 38 </v>
24 39 </v>
25 40 <v t="vivainio.20080218195413"><vh>Class tests</vh>
26 41 <v t="vivainio.20080218200509"><vh>csvr</vh></v>
27 42 <v t="vivainio.20080218191007"><vh>tempfile</vh></v>
28 43 <v t="vivainio.20080218195413.1"><vh>rfile</vh></v>
29 44 <v t="vivainio.20080219225804"><vh>strlist</vh></v>
30 45 </v>
31 46 <v t="vivainio.20080218201219"><vh>Direct variables</vh>
32 47 <v t="vivainio.20080222201226"><vh>NewHeadline</vh></v>
33 48 <v t="vivainio.20080218201219.2"><vh>bar</vh></v>
34 49 </v>
35 <v t="vivainio.20080222193236" a="E"><vh>Docs</vh>
36 <v t="vivainio.20080223121915" a="E" tnodeList="vivainio.20080223121915,vivainio.20080222193236.1,vivainio.20080223133858,vivainio.20080223133922,vivainio.20080223133947,vivainio.20080223134018,vivainio.20080223134100,vivainio.20080223134118,vivainio.20080223134433,vivainio.20080223134136"><vh>@nosent ileointro.txt</vh>
37 <v t="vivainio.20080222193236.1" a="E"><vh>Quick intro</vh>
38 <v t="vivainio.20080223133858"><vh>Introduction</vh></v>
39 <v t="vivainio.20080223133922"><vh>Installation</vh></v>
40 <v t="vivainio.20080223133947"><vh>Accessing IPython from Leo</vh></v>
41 <v t="vivainio.20080223134018"><vh>Accessing Leo nodes from IPython</vh></v>
42 <v t="vivainio.20080223134100"><vh>Cl definitions</vh></v>
43 <v t="vivainio.20080223134118"><vh>Special node types</vh></v>
44 <v t="vivainio.20080223134433" a="TV"><vh>Custom push</vh></v>
45 <v t="vivainio.20080223134136"><vh>Acknowledgements and history</vh></v>
50 <v t="vivainio.20080222202211"><vh>test stuff</vh></v>
51 <v t="vivainio.20080223142403" a="E"><vh>@ipy-results</vh>
52 <v t="vivainio.20080223142403.1"><vh>foo</vh></v>
53 <v t="vivainio.20080223152600" a="E"><vh>baz</vh>
54 <v t="vivainio.20080223174603"><vh>@k hello</vh></v>
46 55 </v>
47 56 </v>
57 <v t="vivainio.20080222202211.1"><vh>spam</vh>
58 <v t="vivainio.20080223180139"><vh>foo bar</vh></v>
48 59 </v>
49 <v t="vivainio.20080222202211"><vh>test stuff</vh></v>
50 <v t="vivainio.20080222202211.1"><vh>spam</vh></v>
51 60 <v t="vivainio.20080222202211.2"><vh>NewHeadline</vh></v>
52 61 </vnodes>
53 62 <tnodes>
54 63 <t tx="vivainio.20080218184525">?</t>
55 64 <t tx="vivainio.20080218184540">?Direct children of this node will be pushed at ipython bridge startup
56 65
57 66 This node itself will *not* be pushed</t>
58 67 <t tx="vivainio.20080218184613.1">print "world"</t>
59 68 <t tx="vivainio.20080218190816">def rfile(body,n):
60 69 """ @cl rfile
61 70
62 71 produces a StringIO (file like obj of the rest of the body) """
63 72
64 73 import StringIO
65 74 return StringIO.StringIO(body)
66 75
67 76 def tmpfile(body,n):
68 77 """ @cl tmpfile
69 78
70 79 Produces a temporary file, with node body as contents
71 80
72 81 """
73 82 import tempfile
74 83 h, fname = tempfile.mkstemp()
75 84 f = open(fname,'w')
76 85 f.write(body)
77 86 f.close()
78 87 return fname
79 88 </t>
80 89 <t tx="vivainio.20080218191007">@cl tmpfile
81 90
82 91 Hello</t>
83 92 <t tx="vivainio.20080218195413">?</t>
84 93 <t tx="vivainio.20080218195413.1">@cl rfile
85 94 These
86 95 lines
87 96 should
88 97 be
89 98 readable </t>
90 99 <t tx="vivainio.20080218200031">@others</t>
91 100 <t tx="vivainio.20080218200106">def csvdata(body,n):
92 101 import csv
93 102 d = csv.Sniffer().sniff(body)
94 103 reader = csv.reader(body.splitlines(), dialect = d)
95 104 return reader</t>
96 105 <t tx="vivainio.20080218200509">@cl csvdata
97 106
98 107 a,b,b
99 108 1,2,2</t>
100 109 <t tx="vivainio.20080218201219"></t>
101 110 <t tx="vivainio.20080218201219.2">@cl
102 111 "hello world"</t>
103 112 <t tx="vivainio.20080219225120">import IPython.genutils
104 113 def slist(body,n):
105 114 return IPython.genutils.SList(body.splitlines())
106 115 </t>
107 116 <t tx="vivainio.20080219225804">@cl slist
108 117 hello
109 118 world
110 119 on
111 120 many
112 121 lines
113 122 </t>
114 123 <t tx="vivainio.20080219230342">import ipy_leo
115 124 @ipy_leo.format_for_leo.when_type(IPython.genutils.SList)
116 125 def format_slist(obj):
117 126 return "@cl slist\n" + obj.n
118 127 </t>
119 <t tx="vivainio.20080222193236"></t>
128 <t tx="vivainio.20080222193236">?</t>
120 129 <t tx="vivainio.20080222193236.1">@wrap
121 130 @nocolor</t>
122 131 <t tx="vivainio.20080222201226">1+2
123 132 print "hello"
124 133 3+4
125 134
126 135 def f(x):
127 136 return x.upper()
128 137
129 138 f('hello world')</t>
130 139 <t tx="vivainio.20080222202211"></t>
131 <t tx="vivainio.20080222202211.1">@cl rfile
140 <t tx="vivainio.20080222202211.1" ipython="7d71005506636f6f7264737101284b0c4bde747102732e">@cl rfile
132 141 hello
133 142 world
134 143 and whatever</t>
135 144 <t tx="vivainio.20080222202211.2"></t>
136 145 <t tx="vivainio.20080223121915">@others
137 146 </t>
138 147 <t tx="vivainio.20080223133721"></t>
139 148 <t tx="vivainio.20080223133721.1">ipython.py</t>
140 149 <t tx="vivainio.20080223133858">
141 150 Introduction
142 151 ============
143 152
144 153 The purpose of ILeo, or leo-ipython bridge, is being a two-way communication
145 154 channel between Leo and IPython. The level of integration is much deeper than
146 155 conventional integration in IDEs; most notably, you are able to store *data* in
147 156 Leo nodes, in addition to mere program code. The possibilities of this are
148 157 endless, and this degree of integration has not been seen previously in the python
149 158 world.
150 159
151 160 IPython users are accustomed to using things like %edit to produce non-trivial
152 161 functions/classes (i.e. something that they don't want to enter directly on the
153 162 interactive prompt, but creating a proper script/module involves too much
154 163 overhead). In ILeo, this task consists just going to the Leo window, creating a node
155 164 and writing the code there, and pressing alt+I (push-to-ipython).
156 165
157 166 Obviously, you can save the Leo document as usual - this is a great advantage
158 167 of ILeo over using %edit, you can save your experimental scripts all at one
159 168 time, without having to organize them into script/module files (before you
160 169 really want to, of course!)
161 170 </t>
162 171 <t tx="vivainio.20080223133922">
163 172 Installation
164 173 ============
165 174
166 175 You need at least Leo 4.4.7, and the development version of IPython (ILeo
167 176 will be incorporated to IPython 0.8.3).
168 177
169 178 You can get IPython from Launchpad by installing bzr and doing
170 179
171 180 bzr branch lp:ipython
172 181
173 182 and running "setup.py install".
174 183
175 184 You need to enable the 'ipython.py' plugin in Leo:
176 185
177 186 - Help -&gt; Open LeoSettings.leo
178 187
179 188 - Edit @settings--&gt;Plugins--&gt;@enabled-plugins, add/uncomment 'ipython.py'
180 189
190 - Alternatively, you can add @settings--&gt;@enabled-plugins with body ipython.py to your leo document.
191
181 192 - Restart Leo. Be sure that you have the console window open (start leo.py from console, or double-click leo.py on windows)
182 193
183 194 - Press alt+5 OR alt-x start-ipython to launch IPython in the console that
184 195 started leo. You can start entering IPython commands normally, and Leo will keep
185 196 running at the same time.
186 197 </t>
187 198 <t tx="vivainio.20080223133947">
188 199 Accessing IPython from Leo
189 200 ==========================
190 201
191 202 IPython code
192 203 ------------
193 204
194 205 Just enter IPython commands on a Leo node and press alt-I to execute
195 push-to-ipython to execute the script in IPython. 'commands' is interpreted
196 loosely here - you can enter function and class definitions, in addition to the
197 things you would usually enter at IPython prompt - calculations, system commands etc.
206 push-to-ipython in order to execute the script in IPython. 'commands' is
207 interpreted loosely here - you can enter function and class definitions, in
208 addition to the things you would usually enter at IPython prompt - calculations,
209 system commands etc.
198 210
199 211 Everything that would be legal to enter on IPython prompt is legal to execute
200 212 from ILeo.
201 213
202 214 Results will be shows in Leo log window for convenience, in addition to the console.
203 215
204 216 Suppose that a node had the following contents:
205 217 {{{
206 218 1+2
207 219 print "hello"
208 220 3+4
209 221
210 222 def f(x):
211 223 return x.upper()
212 224
213 225 f('hello world')
214 226 }}}
215 227
216 If you press alt+I on that done, you will see the following in Leo log window (IPython tab):
228 If you press alt+I on that node, you will see the following in Leo log window (IPython tab):
217 229
218 230 {{{
219 231 In: 1+2
220 232 &lt;2&gt; 3
221 233 In: 3+4
222 234 &lt;4&gt; 7
223 235 In: f('hello world')
224 236 &lt;6&gt; 'HELLO WORLD'
225 237 }}}
226 238
227 (numbers like &lt;6&gt; mean IPython output history indices).
239 (numbers like &lt;6&gt; mean IPython output history indices; the actual object can be
240 referenced with _6 as usual in IPython).
228 241
229 242
230 243 Plain Python code
231 244 -----------------
232 245
233 246 If the headline of the node ends with capital P, alt-I will not run the code
234 247 through IPython translation mechanism but use the direct python 'exec' statement
235 248 (in IPython user namespace) to execute the code. It wont be shown in IPython
236 249 history, and sometimes it is safer (and more efficient) to execute things as
237 250 plain Python statements. Large class definitions are good candidates for P
238 251 nodes.
239 252 </t>
240 253 <t tx="vivainio.20080223134018">
241 254 Accessing Leo nodes from IPython
242 255 ================================
243 256
244 257 The real fun starts when you start entering text to leo nodes, and are using
245 258 that as data (input/output) for your IPython work.
246 259
247 260 Accessing Leo nodes happens through the variable 'wb' (short for "WorkBook")
248 261 that exist in the IPython user namespace. Nodes that are directly accessible are
249 262 the ones that have simple names which could also be Python variable names;
250 263 'foo_1' will be accessible directly from IPython, whereas 'my scripts' will not.
251 264 If you want to access a node with arbitrary headline, add a child node '@a foo'
252 265 (@a stands for 'anchor'). Then, the parent of '@a foo' is accessible through
253 266 'wb.foo'.
254 267
255 268 You can see what nodes are accessible be entering (in IPython) wb.&lt;TAB&gt;. Example:
256 269
257 270 [C:leo/src]|12&gt; wb.
258 271 wb.b wb.tempfile wb.rfile wb.NewHeadline
259 272 wb.bar wb.Docs wb.strlist wb.csvr
273 [C:leo/src]|12&gt; wb.tempfile
274 &lt;12&gt; &lt;ipy_leo.LeoNode object at 0x044B6D90&gt;
275
276 So here, we meet the 'LeoNode' class that is your key to manipulating Leo
277 content from IPython!
278
279 LeoNode
280 -------
260 281
261 282 Suppose that we had a node with headline 'spam' and body:
262 283
263 284 ['12',2222+32]
264 285
265 286 we can access it from IPython (or from scripts entered into other Leo nodes!) by doing:
266 287
267 288 C:leo/src]|19&gt; wb.spam.v
268 289 &lt;19&gt; ['12', 2254]
269 290
270 291 'v' attribute stands for 'value', which means the node contents will be run
271 292 through 'eval' and everything you would be able to enter into IPython prompt
272 293 will be converted to objects. This mechanism can be extended far beyond direct
273 294 evaluation (see '@cl definitions').
274 295
275 296 'v' attribute also has a setter, i.e. you can do:
276 297
277 298 wb.spam.v = "mystring"
278 299
279 300 Which will result in the node 'spam' having the following text:
280 301
281 302 'mystring'
282 303
283 304 What assignment to 'v' does can be configured through generic functions
284 (simplegeneric module, will be explained later).
305 ('simplegeneric' module, will be explained later).
306
307 Besides v, you can set the body text directly through
308
309 wb.spam.b = "some\nstring",
310
311 headline by
312
313 wb.spam.h = 'new_headline'
285 314
286 Besides v, you can set the body text directly through wb.spam.b =
287 "some\nstring", headline by wb.spam.h = 'new_headline' (obviously you must
288 access the node through wb.new_headline from that point onwards), and access the
289 contents as string list (IPython SList) through 'wb.spam.l'.
315 (obviously you must access the node through wb.new_headline from that point
316 onwards), and access the contents as string list (IPython SList) through
317 'wb.spam.l'.
290 318
291 319 If you do 'wb.foo.v = 12' when node named 'foo' does not exist, the node titled
292 320 'foo' will be automatically created and assigned body 12.
321
322 LeoNode also supports go() that focuses the node in the Leo window, ipush that
323 simulates pressing alt+I on the node.
324
325 You can access unknownAttributes by .uA property dictionary. Unknown attributes
326 allow you to store arbitrary (pickleable) python objects in the Leo nodes;
327 the attributes are stored when you save the .leo document, and recreated when
328 you open the document again. Example::
329
330 [C:leo/src]|12&gt; wb.spam.uA['coords'] = (12,222)
331 [C:leo/src]|13&gt; wb.spam.uA
332 &lt;13&gt; {'coords': (12, 222)}
333
334 Accessing children with iteration and dict notation
335 ---------------------------------------------------
336
337 Sometimes, you may want to treat a node as a 'database', where the nodes
338 children represent elements in the database. You can create a new child node for
339 node 'spam', with headline 'foo bar' like this:
340
341 wb.spam['foo bar'] = "Hello"
342
343 And assign a new value for it by doing
344
345 wb.spam['foo bar'].v = "Hello again"
346
347 Note how you can't use .v when you first create the node - i.e. the node needs
348 to be initialized by simple assignment, that will be interpreted as assignment
349 to '.v'. This is a conscious design choice.
350
351 If you try to do wb.spam['bar'] = 'Hello', ILeo will assign '@k bar' as the
352 headline for the child instead, because 'bar' is a legal python name (and as
353 such would be incorporated in the workbook namespace). This is done to avoid
354 crowding the workbook namespace with extraneous items. The item will still be
355 accessible as wb.spam['bar']
356
357 LeoNodes are iterable, so to see the headlines of all the children of 'spam' do:
358
359 for n in wb.spam:
360 print n.h
293 361 </t>
294 362 <t tx="vivainio.20080223134100">
295 363 @cl definitions
296 364 ===============
297 365
298 366 If the first line in the body text is of the form '@cl sometext', IPython will
299 will evaluate 'sometext' and call the result with the rest of the body when you
300 do 'wb.foo.v'. An example is in place here. Suppose that we have defined a class
301 (I use the term class in a non-python sense here)
367 evaluate 'sometext' and call the result with the rest of the body when you do
368 'wb.foo.v'. An example is in place here. Suppose that we have defined a class (I
369 use the term class in a non-python sense here)
302 370
303 371 {{{
304 def rfile(body,n):
372 def rfile(body,node):
305 373 """ @cl rfile
306 374
307 375 produces a StringIO (file like obj) of the rest of the body """
308 376
309 377 import StringIO
310 378 return StringIO.StringIO(body)
311 379 }}}
312 380
313 Now, let's say you node 'spam' with text
381 (note that node is ignored here - but it could be used to access headline,
382 children etc.),
383
384 Now, let's say you have node 'spam' with text
314 385
315 386 {{{
316 387 @cl rfile
317 388 hello
318 389 world
319 390 and whatever
320 391 }}}
321 392
322 Now, on IPython, we can do this:
393 Now, in IPython, we can do this:
323 394
324 395 {{{
325 396 [C:leo/src]|22&gt; f = wb.spam.v
326 397 [C:leo/src]|23&gt; f
327 398 &lt;23&gt; &lt;StringIO.StringIO instance at 0x04E7E490&gt;
328 399 [C:leo/src]|24&gt; f.readline()
329 400 &lt;24&gt; u'hello\n'
330 401 [C:leo/src]|25&gt; f.readline()
331 402 &lt;25&gt; u'world\n'
332 403 [C:leo/src]|26&gt; f.readline()
333 404 &lt;26&gt; u'and whatever'
334 405 [C:leo/src]|27&gt; f.readline()
335 406 &lt;27&gt; u''
336 407 }}}
337 408
338 You should declare new @cl types to make ILeo as convenient your problem domain as possible. For example, a "@cl etree" could return the elementtree object for xml content, or
409 You should declare new @cl types to make ILeo as convenient your problem domain
410 as possible. For example, a "@cl etree" could return the elementtree object for
411 xml content.
339 412 </t>
340 413 <t tx="vivainio.20080223134118">
341 414 Special node types
342 415 ==================
343 416
344 417 @ipy-startup
345 418 ------------
346 419
347 420 If this node exist, the *direct children* of this will be pushed to IPython when
348 421 ILeo is started (you press alt+5). Use it to push your own @cl definitions etc.
349 422 The contents of of the node itself will be ignored.
350 423
351 424 @ipy-results
352 425 ------------
353 426
354 427 When you create a new node (wb.foo.v = 'stuff'), the node foo will be created as
355 428 a child of this node. If @ipy-results does not exist, the new node will be created after the currently selected node.
356 429
357 430 @a nodes
358 431 --------
359 432
360 433 You can attach these as children of existing nodes to provide a way to access
361 434 nodes with arbitrary headlines, or to provide aliases to other nodes. If
362 435 multiple @a nodes are attached as children of a node, all the names can be used
363 436 to access the same object.
364 437 </t>
365 438 <t tx="vivainio.20080223134136">
366 439 Acknowledgements &amp; History
367 440 ==========================
368 441
369 442 This idea got started when I (Ville) saw this post by Edward Ream (the author of
370 443 Leo) on IPython developer mailing list:
371 444
372 445 http://lists.ipython.scipy.org/pipermail/ipython-dev/2008-January/003551.html
373 446
374 447 I was using FreeMind as mind mapping software, and so I had an immediate use
375 448 case for Leo (which, incidentally, is superior to FreeMind as mind mapper). The
376 449 wheels started rolling, I got obsessed with the power of this concept
377 450 (everything clicked together), and Edwards excitement paralleled mine.
378 451 Everything was mind-bogglingly easy/trivial, something that is typical of all
379 452 revolutionary technologies (think Python here).
380 453
381 454 The discussion that "built" ILeo is here:
382 455 http://sourceforge.net/forum/forum.php?thread_id=1911662&amp;forum_id=10226
383 456
384 457 ?</t>
385 458 <t tx="vivainio.20080223134433">
386 459 Declaring custom push-to-ipython handlers
387 460 =========================================
388 461
389 462 Sometimes, you might want to configure what alt+I on a node does. You can do
390 463 that by creating your own push function and expose it using
391 464 ipy_leo.expose_ileo_push(f, priority). The function should check whether the
392 node should by handled by it and raise IPython.ipapi.TryNext if it will not do
393 the handling.
465 node should by handled by the function and raise IPython.ipapi.TryNext if it
466 will not do the handling, giving the next function in the chain a chance to see
467 whether it should handle the push.
394 468
395 This would print an uppercase version of node body if the node headline ends
396 with U (yes, this is completely useless!)
469 This example would print an uppercase version of node body if the node headline ends
470 with U (yes, this is completely useless!):
397 471
472 {{{
398 473 def push_upcase(node):
399 474 if not node.h.endswith('U'):
400 475 raise TryNext
401 476 print node.b.upper()
402 477
403 expose_ileo_push(push_upcase, 12)
478 ipy_leo.expose_ileo_push(push_upcase, 12)
479 }}}
404 480
405 481 (the priority should be between 0-100 - typically, you don't need to care about
406 it and can omit the argument altogether)
482 it and can usually omit the argument altogether)
483 </t>
484 <t tx="vivainio.20080223142207">
485 Example code snippets
486 =====================
487
488 Get list of all headlines of all the nodes in leo:
489
490 [node.h for node in wb]
491
492 Create node with headline 'baz', empty body:
493 wb.baz
494
495 Create 10 child nodes for baz, where i is headline and 'Hello ' + i is body:
496
497 for i in range(10):
498 wb.baz[i] = 'Hello %d' % i
499
500
407 501 </t>
502 <t tx="vivainio.20080223142403"></t>
503 <t tx="vivainio.20080223142403.1">12</t>
504 <t tx="vivainio.20080223152600"></t>
505 <t tx="vivainio.20080223174603"></t>
506 <t tx="vivainio.20080223180139">'hello again'</t>
408 507 </tnodes>
409 508 </leo_file>
General Comments 0
You need to be logged in to leave comments. Login now