##// END OF EJS Templates
Fix broken demo reload()....
Fernando Perez -
Show More
@@ -1,554 +1,562 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
4 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
5 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
6 control to IPython.
6 control to IPython.
7
7
8
8
9 Provided classes
9 Provided classes
10 ================
10 ================
11
11
12 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
13
13
14 - Demo: pure python demos
14 - Demo: pure python demos
15
15
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
18 may have added via input prefilters).
18 may have added via input prefilters).
19
19
20 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
21 one line at a time, and require no markup.
21 one line at a time, and require no markup.
22
22
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
25
25
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
28 block (see Subclassing below).
28 block (see Subclassing below).
29
29
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 classes.
31 classes.
32
32
33
33
34 Subclassing
34 Subclassing
35 ===========
35 ===========
36
36
37 The classes here all include a few methods meant to make customization by
37 The classes here all include a few methods meant to make customization by
38 subclassing more convenient. Their docstrings below have some more details:
38 subclassing more convenient. Their docstrings below have some more details:
39
39
40 - marquee(): generates a marquee to provide visible on-screen markers at each
40 - marquee(): generates a marquee to provide visible on-screen markers at each
41 block start and end.
41 block start and end.
42
42
43 - pre_cmd(): run right before the execution of each block.
43 - pre_cmd(): run right before the execution of each block.
44
44
45 - post_cmd(): run right after the execution of each block. If the block
45 - post_cmd(): run right after the execution of each block. If the block
46 raises an exception, this is NOT called.
46 raises an exception, this is NOT called.
47
47
48
48
49 Operation
49 Operation
50 =========
50 =========
51
51
52 The file is run in its own empty namespace (though you can pass it a string of
52 The file is run in its own empty namespace (though you can pass it a string of
53 arguments as if in a command line environment, and it will see those as
53 arguments as if in a command line environment, and it will see those as
54 sys.argv). But at each stop, the global IPython namespace is updated with the
54 sys.argv). But at each stop, the global IPython namespace is updated with the
55 current internal demo namespace, so you can work interactively with the data
55 current internal demo namespace, so you can work interactively with the data
56 accumulated so far.
56 accumulated so far.
57
57
58 By default, each block of code is printed (with syntax highlighting) before
58 By default, each block of code is printed (with syntax highlighting) before
59 executing it and you have to confirm execution. This is intended to show the
59 executing it and you have to confirm execution. This is intended to show the
60 code to an audience first so you can discuss it, and only proceed with
60 code to an audience first so you can discuss it, and only proceed with
61 execution once you agree. There are a few tags which allow you to modify this
61 execution once you agree. There are a few tags which allow you to modify this
62 behavior.
62 behavior.
63
63
64 The supported tags are:
64 The supported tags are:
65
65
66 # <demo> stop
66 # <demo> stop
67
67
68 Defines block boundaries, the points where IPython stops execution of the
68 Defines block boundaries, the points where IPython stops execution of the
69 file and returns to the interactive prompt.
69 file and returns to the interactive prompt.
70
70
71 You can optionally mark the stop tag with extra dashes before and after the
71 You can optionally mark the stop tag with extra dashes before and after the
72 word 'stop', to help visually distinguish the blocks in a text editor:
72 word 'stop', to help visually distinguish the blocks in a text editor:
73
73
74 # <demo> --- stop ---
74 # <demo> --- stop ---
75
75
76
76
77 # <demo> silent
77 # <demo> silent
78
78
79 Make a block execute silently (and hence automatically). Typically used in
79 Make a block execute silently (and hence automatically). Typically used in
80 cases where you have some boilerplate or initialization code which you need
80 cases where you have some boilerplate or initialization code which you need
81 executed but do not want to be seen in the demo.
81 executed but do not want to be seen in the demo.
82
82
83 # <demo> auto
83 # <demo> auto
84
84
85 Make a block execute automatically, but still being printed. Useful for
85 Make a block execute automatically, but still being printed. Useful for
86 simple code which does not warrant discussion, since it avoids the extra
86 simple code which does not warrant discussion, since it avoids the extra
87 manual confirmation.
87 manual confirmation.
88
88
89 # <demo> auto_all
89 # <demo> auto_all
90
90
91 This tag can _only_ be in the first block, and if given it overrides the
91 This tag can _only_ be in the first block, and if given it overrides the
92 individual auto tags to make the whole demo fully automatic (no block asks
92 individual auto tags to make the whole demo fully automatic (no block asks
93 for confirmation). It can also be given at creation time (or the attribute
93 for confirmation). It can also be given at creation time (or the attribute
94 set later) to override what's in the file.
94 set later) to override what's in the file.
95
95
96 While _any_ python file can be run as a Demo instance, if there are no stop
96 While _any_ python file can be run as a Demo instance, if there are no stop
97 tags the whole file will run in a single block (no different that calling
97 tags the whole file will run in a single block (no different that calling
98 first %pycat and then %run). The minimal markup to make this useful is to
98 first %pycat and then %run). The minimal markup to make this useful is to
99 place a set of stop tags; the other tags are only there to let you fine-tune
99 place a set of stop tags; the other tags are only there to let you fine-tune
100 the execution.
100 the execution.
101
101
102 This is probably best explained with the simple example file below. You can
102 This is probably best explained with the simple example file below. You can
103 copy this into a file named ex_demo.py, and try running it via:
103 copy this into a file named ex_demo.py, and try running it via:
104
104
105 from IPython.demo import Demo
105 from IPython.demo import Demo
106 d = Demo('ex_demo.py')
106 d = Demo('ex_demo.py')
107 d() <--- Call the d object (omit the parens if you have autocall set to 2).
107 d() <--- Call the d object (omit the parens if you have autocall set to 2).
108
108
109 Each time you call the demo object, it runs the next block. The demo object
109 Each time you call the demo object, it runs the next block. The demo object
110 has a few useful methods for navigation, like again(), edit(), jump(), seek()
110 has a few useful methods for navigation, like again(), edit(), jump(), seek()
111 and back(). It can be reset for a new run via reset() or reloaded from disk
111 and back(). It can be reset for a new run via reset() or reloaded from disk
112 (in case you've edited the source) via reload(). See their docstrings below.
112 (in case you've edited the source) via reload(). See their docstrings below.
113
113
114 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
114 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
115 been added to the "docs/examples/core" directory. Just cd to this directory in
115 been added to the "docs/examples/core" directory. Just cd to this directory in
116 an IPython session, and type::
116 an IPython session, and type::
117
117
118 %run demo-exercizer.py
118 %run demo-exercizer.py
119
119
120 and then follow the directions.
120 and then follow the directions.
121
121
122 Example
122 Example
123 =======
123 =======
124
124
125 The following is a very simple example of a valid demo file.
125 The following is a very simple example of a valid demo file.
126
126
127 #################### EXAMPLE DEMO <ex_demo.py> ###############################
127 #################### EXAMPLE DEMO <ex_demo.py> ###############################
128 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
128 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
129
129
130 print 'Hello, welcome to an interactive IPython demo.'
130 print 'Hello, welcome to an interactive IPython demo.'
131
131
132 # The mark below defines a block boundary, which is a point where IPython will
132 # The mark below defines a block boundary, which is a point where IPython will
133 # stop execution and return to the interactive prompt. The dashes are actually
133 # stop execution and return to the interactive prompt. The dashes are actually
134 # optional and used only as a visual aid to clearly separate blocks while
134 # optional and used only as a visual aid to clearly separate blocks while
135 # editing the demo code.
135 # editing the demo code.
136 # <demo> stop
136 # <demo> stop
137
137
138 x = 1
138 x = 1
139 y = 2
139 y = 2
140
140
141 # <demo> stop
141 # <demo> stop
142
142
143 # the mark below makes this block as silent
143 # the mark below makes this block as silent
144 # <demo> silent
144 # <demo> silent
145
145
146 print 'This is a silent block, which gets executed but not printed.'
146 print 'This is a silent block, which gets executed but not printed.'
147
147
148 # <demo> stop
148 # <demo> stop
149 # <demo> auto
149 # <demo> auto
150 print 'This is an automatic block.'
150 print 'This is an automatic block.'
151 print 'It is executed without asking for confirmation, but printed.'
151 print 'It is executed without asking for confirmation, but printed.'
152 z = x+y
152 z = x+y
153
153
154 print 'z=',x
154 print 'z=',x
155
155
156 # <demo> stop
156 # <demo> stop
157 # This is just another normal block.
157 # This is just another normal block.
158 print 'z is now:', z
158 print 'z is now:', z
159
159
160 print 'bye!'
160 print 'bye!'
161 ################### END EXAMPLE DEMO <ex_demo.py> ############################
161 ################### END EXAMPLE DEMO <ex_demo.py> ############################
162 """
162 """
163
163
164 #*****************************************************************************
164 #*****************************************************************************
165 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
165 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
166 #
166 #
167 # Distributed under the terms of the BSD License. The full license is in
167 # Distributed under the terms of the BSD License. The full license is in
168 # the file COPYING, distributed as part of this software.
168 # the file COPYING, distributed as part of this software.
169 #
169 #
170 #*****************************************************************************
170 #*****************************************************************************
171
171
172 import exceptions
172 import exceptions
173 import os
173 import os
174 import re
174 import re
175 import shlex
175 import shlex
176 import sys
176 import sys
177
177
178 from IPython.PyColorize import Parser
178 from IPython.PyColorize import Parser
179 from IPython.genutils import marquee, file_read, file_readlines, Term
179 from IPython.genutils import marquee, file_read, file_readlines, Term
180
180
181 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
181 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
182
182
183 class DemoError(exceptions.Exception): pass
183 class DemoError(exceptions.Exception): pass
184
184
185 def re_mark(mark):
185 def re_mark(mark):
186 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
186 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
187
187
188 class Demo(object):
188 class Demo(object):
189
189
190 re_stop = re_mark('-*\s?stop\s?-*')
190 re_stop = re_mark('-*\s?stop\s?-*')
191 re_silent = re_mark('silent')
191 re_silent = re_mark('silent')
192 re_auto = re_mark('auto')
192 re_auto = re_mark('auto')
193 re_auto_all = re_mark('auto_all')
193 re_auto_all = re_mark('auto_all')
194
194
195 def __init__(self,src,title='',arg_str='',auto_all=None):
195 def __init__(self,src,title='',arg_str='',auto_all=None):
196 """Make a new demo object. To run the demo, simply call the object.
196 """Make a new demo object. To run the demo, simply call the object.
197
197
198 See the module docstring for full details and an example (you can use
198 See the module docstring for full details and an example (you can use
199 IPython.Demo? in IPython to see it).
199 IPython.Demo? in IPython to see it).
200
200
201 Inputs:
201 Inputs:
202
202
203 - src is either a file, or file-like object, or a
203 - src is either a file, or file-like object, or a
204 string that can be resolved to a filename.
204 string that can be resolved to a filename.
205
205
206 Optional inputs:
206 Optional inputs:
207
207
208 - title: a string to use as the demo name. Of most use when the demo
208 - title: a string to use as the demo name. Of most use when the demo
209 you are making comes from an object that has no filename, or if you
209 you are making comes from an object that has no filename, or if you
210 want an alternate denotation distinct from the filename.
210 want an alternate denotation distinct from the filename.
211
211
212 - arg_str(''): a string of arguments, internally converted to a list
212 - arg_str(''): a string of arguments, internally converted to a list
213 just like sys.argv, so the demo script can see a similar
213 just like sys.argv, so the demo script can see a similar
214 environment.
214 environment.
215
215
216 - auto_all(None): global flag to run all blocks automatically without
216 - auto_all(None): global flag to run all blocks automatically without
217 confirmation. This attribute overrides the block-level tags and
217 confirmation. This attribute overrides the block-level tags and
218 applies to the whole demo. It is an attribute of the object, and
218 applies to the whole demo. It is an attribute of the object, and
219 can be changed at runtime simply by reassigning it to a boolean
219 can be changed at runtime simply by reassigning it to a boolean
220 value.
220 value.
221 """
221 """
222 if hasattr(src, "read"):
222 if hasattr(src, "read"):
223 # It seems to be a file or a file-like object
223 # It seems to be a file or a file-like object
224 self.fobj = src
225 self.fname = "from a file-like object"
224 self.fname = "from a file-like object"
226 if title == '':
225 if title == '':
227 self.title = "from a file-like object"
226 self.title = "from a file-like object"
228 else:
227 else:
229 self.title = title
228 self.title = title
230 else:
229 else:
231 # Assume it's a string or something that can be converted to one
230 # Assume it's a string or something that can be converted to one
232 self.fobj = open(src)
233 self.fname = src
231 self.fname = src
234 if title == '':
232 if title == '':
235 (filepath, filename) = os.path.split(src)
233 (filepath, filename) = os.path.split(src)
236 self.title = filename
234 self.title = filename
237 else:
235 else:
238 self.title = title
236 self.title = title
239 self.sys_argv = [src] + shlex.split(arg_str)
237 self.sys_argv = [src] + shlex.split(arg_str)
240 self.auto_all = auto_all
238 self.auto_all = auto_all
239 self.src = src
241
240
242 # get a few things from ipython. While it's a bit ugly design-wise,
241 # get a few things from ipython. While it's a bit ugly design-wise,
243 # it ensures that things like color scheme and the like are always in
242 # it ensures that things like color scheme and the like are always in
244 # sync with the ipython mode being used. This class is only meant to
243 # sync with the ipython mode being used. This class is only meant to
245 # be used inside ipython anyways, so it's OK.
244 # be used inside ipython anyways, so it's OK.
246 self.ip_ns = __IPYTHON__.user_ns
245 self.ip_ns = __IPYTHON__.user_ns
247 self.ip_colorize = __IPYTHON__.pycolorize
246 self.ip_colorize = __IPYTHON__.pycolorize
248 self.ip_showtb = __IPYTHON__.showtraceback
247 self.ip_showtb = __IPYTHON__.showtraceback
249 self.ip_runlines = __IPYTHON__.runlines
248 self.ip_runlines = __IPYTHON__.runlines
250 self.shell = __IPYTHON__
249 self.shell = __IPYTHON__
251
250
252 # load user data and initialize data structures
251 # load user data and initialize data structures
253 self.reload()
252 self.reload()
254
253
255 def reload(self):
254 def reload(self):
256 """Reload source from disk and initialize state."""
255 """Reload source from disk and initialize state."""
257 # read data and parse into blocks
256 # read data and parse into blocks
257 if hasattr(self, 'fobj') and self.fobj is not None:
258 self.fobj.close()
259 if hasattr(self.src, "read"):
260 # It seems to be a file or a file-like object
261 self.fobj = self.src
262 else:
263 # Assume it's a string or something that can be converted to one
264 self.fobj = open(self.fname)
265
258 self.src = self.fobj.read()
266 self.src = self.fobj.read()
259 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
267 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
260 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
268 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
261 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
269 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
262
270
263 # if auto_all is not given (def. None), we read it from the file
271 # if auto_all is not given (def. None), we read it from the file
264 if self.auto_all is None:
272 if self.auto_all is None:
265 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
273 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
266 else:
274 else:
267 self.auto_all = bool(self.auto_all)
275 self.auto_all = bool(self.auto_all)
268
276
269 # Clean the sources from all markup so it doesn't get displayed when
277 # Clean the sources from all markup so it doesn't get displayed when
270 # running the demo
278 # running the demo
271 src_blocks = []
279 src_blocks = []
272 auto_strip = lambda s: self.re_auto.sub('',s)
280 auto_strip = lambda s: self.re_auto.sub('',s)
273 for i,b in enumerate(src_b):
281 for i,b in enumerate(src_b):
274 if self._auto[i]:
282 if self._auto[i]:
275 src_blocks.append(auto_strip(b))
283 src_blocks.append(auto_strip(b))
276 else:
284 else:
277 src_blocks.append(b)
285 src_blocks.append(b)
278 # remove the auto_all marker
286 # remove the auto_all marker
279 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
287 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
280
288
281 self.nblocks = len(src_blocks)
289 self.nblocks = len(src_blocks)
282 self.src_blocks = src_blocks
290 self.src_blocks = src_blocks
283
291
284 # also build syntax-highlighted source
292 # also build syntax-highlighted source
285 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
293 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
286
294
287 # ensure clean namespace and seek offset
295 # ensure clean namespace and seek offset
288 self.reset()
296 self.reset()
289
297
290 def reset(self):
298 def reset(self):
291 """Reset the namespace and seek pointer to restart the demo"""
299 """Reset the namespace and seek pointer to restart the demo"""
292 self.user_ns = {}
300 self.user_ns = {}
293 self.finished = False
301 self.finished = False
294 self.block_index = 0
302 self.block_index = 0
295
303
296 def _validate_index(self,index):
304 def _validate_index(self,index):
297 if index<0 or index>=self.nblocks:
305 if index<0 or index>=self.nblocks:
298 raise ValueError('invalid block index %s' % index)
306 raise ValueError('invalid block index %s' % index)
299
307
300 def _get_index(self,index):
308 def _get_index(self,index):
301 """Get the current block index, validating and checking status.
309 """Get the current block index, validating and checking status.
302
310
303 Returns None if the demo is finished"""
311 Returns None if the demo is finished"""
304
312
305 if index is None:
313 if index is None:
306 if self.finished:
314 if self.finished:
307 print >>Term.cout, 'Demo finished. Use <demo_name>.reset() if you want to rerun it.'
315 print >>Term.cout, 'Demo finished. Use <demo_name>.reset() if you want to rerun it.'
308 return None
316 return None
309 index = self.block_index
317 index = self.block_index
310 else:
318 else:
311 self._validate_index(index)
319 self._validate_index(index)
312 return index
320 return index
313
321
314 def seek(self,index):
322 def seek(self,index):
315 """Move the current seek pointer to the given block.
323 """Move the current seek pointer to the given block.
316
324
317 You can use negative indices to seek from the end, with identical
325 You can use negative indices to seek from the end, with identical
318 semantics to those of Python lists."""
326 semantics to those of Python lists."""
319 if index<0:
327 if index<0:
320 index = self.nblocks + index
328 index = self.nblocks + index
321 self._validate_index(index)
329 self._validate_index(index)
322 self.block_index = index
330 self.block_index = index
323 self.finished = False
331 self.finished = False
324
332
325 def back(self,num=1):
333 def back(self,num=1):
326 """Move the seek pointer back num blocks (default is 1)."""
334 """Move the seek pointer back num blocks (default is 1)."""
327 self.seek(self.block_index-num)
335 self.seek(self.block_index-num)
328
336
329 def jump(self,num=1):
337 def jump(self,num=1):
330 """Jump a given number of blocks relative to the current one.
338 """Jump a given number of blocks relative to the current one.
331
339
332 The offset can be positive or negative, defaults to 1."""
340 The offset can be positive or negative, defaults to 1."""
333 self.seek(self.block_index+num)
341 self.seek(self.block_index+num)
334
342
335 def again(self):
343 def again(self):
336 """Move the seek pointer back one block and re-execute."""
344 """Move the seek pointer back one block and re-execute."""
337 self.back(1)
345 self.back(1)
338 self()
346 self()
339
347
340 def edit(self,index=None):
348 def edit(self,index=None):
341 """Edit a block.
349 """Edit a block.
342
350
343 If no number is given, use the last block executed.
351 If no number is given, use the last block executed.
344
352
345 This edits the in-memory copy of the demo, it does NOT modify the
353 This edits the in-memory copy of the demo, it does NOT modify the
346 original source file. If you want to do that, simply open the file in
354 original source file. If you want to do that, simply open the file in
347 an editor and use reload() when you make changes to the file. This
355 an editor and use reload() when you make changes to the file. This
348 method is meant to let you change a block during a demonstration for
356 method is meant to let you change a block during a demonstration for
349 explanatory purposes, without damaging your original script."""
357 explanatory purposes, without damaging your original script."""
350
358
351 index = self._get_index(index)
359 index = self._get_index(index)
352 if index is None:
360 if index is None:
353 return
361 return
354 # decrease the index by one (unless we're at the very beginning), so
362 # decrease the index by one (unless we're at the very beginning), so
355 # that the default demo.edit() call opens up the sblock we've last run
363 # that the default demo.edit() call opens up the sblock we've last run
356 if index>0:
364 if index>0:
357 index -= 1
365 index -= 1
358
366
359 filename = self.shell.mktempfile(self.src_blocks[index])
367 filename = self.shell.mktempfile(self.src_blocks[index])
360 self.shell.hooks.editor(filename,1)
368 self.shell.hooks.editor(filename,1)
361 new_block = file_read(filename)
369 new_block = file_read(filename)
362 # update the source and colored block
370 # update the source and colored block
363 self.src_blocks[index] = new_block
371 self.src_blocks[index] = new_block
364 self.src_blocks_colored[index] = self.ip_colorize(new_block)
372 self.src_blocks_colored[index] = self.ip_colorize(new_block)
365 self.block_index = index
373 self.block_index = index
366 # call to run with the newly edited index
374 # call to run with the newly edited index
367 self()
375 self()
368
376
369 def show(self,index=None):
377 def show(self,index=None):
370 """Show a single block on screen"""
378 """Show a single block on screen"""
371
379
372 index = self._get_index(index)
380 index = self._get_index(index)
373 if index is None:
381 if index is None:
374 return
382 return
375
383
376 print >>Term.cout, self.marquee('<%s> block # %s (%s remaining)' %
384 print >>Term.cout, self.marquee('<%s> block # %s (%s remaining)' %
377 (self.title,index,self.nblocks-index-1))
385 (self.title,index,self.nblocks-index-1))
378 print >>Term.cout,(self.src_blocks_colored[index])
386 print >>Term.cout,(self.src_blocks_colored[index])
379 sys.stdout.flush()
387 sys.stdout.flush()
380
388
381 def show_all(self):
389 def show_all(self):
382 """Show entire demo on screen, block by block"""
390 """Show entire demo on screen, block by block"""
383
391
384 fname = self.title
392 fname = self.title
385 title = self.title
393 title = self.title
386 nblocks = self.nblocks
394 nblocks = self.nblocks
387 silent = self._silent
395 silent = self._silent
388 marquee = self.marquee
396 marquee = self.marquee
389 for index,block in enumerate(self.src_blocks_colored):
397 for index,block in enumerate(self.src_blocks_colored):
390 if silent[index]:
398 if silent[index]:
391 print >>Term.cout, marquee('<%s> SILENT block # %s (%s remaining)' %
399 print >>Term.cout, marquee('<%s> SILENT block # %s (%s remaining)' %
392 (title,index,nblocks-index-1))
400 (title,index,nblocks-index-1))
393 else:
401 else:
394 print >>Term.cout, marquee('<%s> block # %s (%s remaining)' %
402 print >>Term.cout, marquee('<%s> block # %s (%s remaining)' %
395 (title,index,nblocks-index-1))
403 (title,index,nblocks-index-1))
396 print >>Term.cout, block,
404 print >>Term.cout, block,
397 sys.stdout.flush()
405 sys.stdout.flush()
398
406
399 def runlines(self,source):
407 def runlines(self,source):
400 """Execute a string with one or more lines of code"""
408 """Execute a string with one or more lines of code"""
401
409
402 exec source in self.user_ns
410 exec source in self.user_ns
403
411
404 def __call__(self,index=None):
412 def __call__(self,index=None):
405 """run a block of the demo.
413 """run a block of the demo.
406
414
407 If index is given, it should be an integer >=1 and <= nblocks. This
415 If index is given, it should be an integer >=1 and <= nblocks. This
408 means that the calling convention is one off from typical Python
416 means that the calling convention is one off from typical Python
409 lists. The reason for the inconsistency is that the demo always
417 lists. The reason for the inconsistency is that the demo always
410 prints 'Block n/N, and N is the total, so it would be very odd to use
418 prints 'Block n/N, and N is the total, so it would be very odd to use
411 zero-indexing here."""
419 zero-indexing here."""
412
420
413 index = self._get_index(index)
421 index = self._get_index(index)
414 if index is None:
422 if index is None:
415 return
423 return
416 try:
424 try:
417 marquee = self.marquee
425 marquee = self.marquee
418 next_block = self.src_blocks[index]
426 next_block = self.src_blocks[index]
419 self.block_index += 1
427 self.block_index += 1
420 if self._silent[index]:
428 if self._silent[index]:
421 print >>Term.cout, marquee('Executing silent block # %s (%s remaining)' %
429 print >>Term.cout, marquee('Executing silent block # %s (%s remaining)' %
422 (index,self.nblocks-index-1))
430 (index,self.nblocks-index-1))
423 else:
431 else:
424 self.pre_cmd()
432 self.pre_cmd()
425 self.show(index)
433 self.show(index)
426 if self.auto_all or self._auto[index]:
434 if self.auto_all or self._auto[index]:
427 print >>Term.cout, marquee('output:')
435 print >>Term.cout, marquee('output:')
428 else:
436 else:
429 print >>Term.cout, marquee('Press <q> to quit, <Enter> to execute...'),
437 print >>Term.cout, marquee('Press <q> to quit, <Enter> to execute...'),
430 ans = raw_input().strip()
438 ans = raw_input().strip()
431 if ans:
439 if ans:
432 print >>Term.cout, marquee('Block NOT executed')
440 print >>Term.cout, marquee('Block NOT executed')
433 return
441 return
434 try:
442 try:
435 save_argv = sys.argv
443 save_argv = sys.argv
436 sys.argv = self.sys_argv
444 sys.argv = self.sys_argv
437 self.runlines(next_block)
445 self.runlines(next_block)
438 self.post_cmd()
446 self.post_cmd()
439 finally:
447 finally:
440 sys.argv = save_argv
448 sys.argv = save_argv
441
449
442 except:
450 except:
443 self.ip_showtb(filename=self.fname)
451 self.ip_showtb(filename=self.fname)
444 else:
452 else:
445 self.ip_ns.update(self.user_ns)
453 self.ip_ns.update(self.user_ns)
446
454
447 if self.block_index == self.nblocks:
455 if self.block_index == self.nblocks:
448 mq1 = self.marquee('END OF DEMO')
456 mq1 = self.marquee('END OF DEMO')
449 if mq1:
457 if mq1:
450 # avoid spurious print >>Term.cout,s if empty marquees are used
458 # avoid spurious print >>Term.cout,s if empty marquees are used
451 print >>Term.cout
459 print >>Term.cout
452 print >>Term.cout, mq1
460 print >>Term.cout, mq1
453 print >>Term.cout, self.marquee('Use <demo_name>.reset() if you want to rerun it.')
461 print >>Term.cout, self.marquee('Use <demo_name>.reset() if you want to rerun it.')
454 self.finished = True
462 self.finished = True
455
463
456 # These methods are meant to be overridden by subclasses who may wish to
464 # These methods are meant to be overridden by subclasses who may wish to
457 # customize the behavior of of their demos.
465 # customize the behavior of of their demos.
458 def marquee(self,txt='',width=78,mark='*'):
466 def marquee(self,txt='',width=78,mark='*'):
459 """Return the input string centered in a 'marquee'."""
467 """Return the input string centered in a 'marquee'."""
460 return marquee(txt,width,mark)
468 return marquee(txt,width,mark)
461
469
462 def pre_cmd(self):
470 def pre_cmd(self):
463 """Method called before executing each block."""
471 """Method called before executing each block."""
464 pass
472 pass
465
473
466 def post_cmd(self):
474 def post_cmd(self):
467 """Method called after executing each block."""
475 """Method called after executing each block."""
468 pass
476 pass
469
477
470
478
471 class IPythonDemo(Demo):
479 class IPythonDemo(Demo):
472 """Class for interactive demos with IPython's input processing applied.
480 """Class for interactive demos with IPython's input processing applied.
473
481
474 This subclasses Demo, but instead of executing each block by the Python
482 This subclasses Demo, but instead of executing each block by the Python
475 interpreter (via exec), it actually calls IPython on it, so that any input
483 interpreter (via exec), it actually calls IPython on it, so that any input
476 filters which may be in place are applied to the input block.
484 filters which may be in place are applied to the input block.
477
485
478 If you have an interactive environment which exposes special input
486 If you have an interactive environment which exposes special input
479 processing, you can use this class instead to write demo scripts which
487 processing, you can use this class instead to write demo scripts which
480 operate exactly as if you had typed them interactively. The default Demo
488 operate exactly as if you had typed them interactively. The default Demo
481 class requires the input to be valid, pure Python code.
489 class requires the input to be valid, pure Python code.
482 """
490 """
483
491
484 def runlines(self,source):
492 def runlines(self,source):
485 """Execute a string with one or more lines of code"""
493 """Execute a string with one or more lines of code"""
486
494
487 self.shell.runlines(source)
495 self.shell.runlines(source)
488
496
489 class LineDemo(Demo):
497 class LineDemo(Demo):
490 """Demo where each line is executed as a separate block.
498 """Demo where each line is executed as a separate block.
491
499
492 The input script should be valid Python code.
500 The input script should be valid Python code.
493
501
494 This class doesn't require any markup at all, and it's meant for simple
502 This class doesn't require any markup at all, and it's meant for simple
495 scripts (with no nesting or any kind of indentation) which consist of
503 scripts (with no nesting or any kind of indentation) which consist of
496 multiple lines of input to be executed, one at a time, as if they had been
504 multiple lines of input to be executed, one at a time, as if they had been
497 typed in the interactive prompt."""
505 typed in the interactive prompt."""
498
506
499 def reload(self):
507 def reload(self):
500 """Reload source from disk and initialize state."""
508 """Reload source from disk and initialize state."""
501 # read data and parse into blocks
509 # read data and parse into blocks
502 src_b = [l for l in self.fobj.readline() if l.strip()]
510 src_b = [l for l in self.fobj.readline() if l.strip()]
503 nblocks = len(src_b)
511 nblocks = len(src_b)
504 self.src = os.linesep.join(self.fobj.readlines())
512 self.src = os.linesep.join(self.fobj.readlines())
505 self._silent = [False]*nblocks
513 self._silent = [False]*nblocks
506 self._auto = [True]*nblocks
514 self._auto = [True]*nblocks
507 self.auto_all = True
515 self.auto_all = True
508 self.nblocks = nblocks
516 self.nblocks = nblocks
509 self.src_blocks = src_b
517 self.src_blocks = src_b
510
518
511 # also build syntax-highlighted source
519 # also build syntax-highlighted source
512 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
520 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
513
521
514 # ensure clean namespace and seek offset
522 # ensure clean namespace and seek offset
515 self.reset()
523 self.reset()
516
524
517
525
518 class IPythonLineDemo(IPythonDemo,LineDemo):
526 class IPythonLineDemo(IPythonDemo,LineDemo):
519 """Variant of the LineDemo class whose input is processed by IPython."""
527 """Variant of the LineDemo class whose input is processed by IPython."""
520 pass
528 pass
521
529
522
530
523 class ClearMixin(object):
531 class ClearMixin(object):
524 """Use this mixin to make Demo classes with less visual clutter.
532 """Use this mixin to make Demo classes with less visual clutter.
525
533
526 Demos using this mixin will clear the screen before every block and use
534 Demos using this mixin will clear the screen before every block and use
527 blank marquees.
535 blank marquees.
528
536
529 Note that in order for the methods defined here to actually override those
537 Note that in order for the methods defined here to actually override those
530 of the classes it's mixed with, it must go /first/ in the inheritance
538 of the classes it's mixed with, it must go /first/ in the inheritance
531 tree. For example:
539 tree. For example:
532
540
533 class ClearIPDemo(ClearMixin,IPythonDemo): pass
541 class ClearIPDemo(ClearMixin,IPythonDemo): pass
534
542
535 will provide an IPythonDemo class with the mixin's features.
543 will provide an IPythonDemo class with the mixin's features.
536 """
544 """
537
545
538 def marquee(self,txt='',width=78,mark='*'):
546 def marquee(self,txt='',width=78,mark='*'):
539 """Blank marquee that returns '' no matter what the input."""
547 """Blank marquee that returns '' no matter what the input."""
540 return ''
548 return ''
541
549
542 def pre_cmd(self):
550 def pre_cmd(self):
543 """Method called before executing each block.
551 """Method called before executing each block.
544
552
545 This one simply clears the screen."""
553 This one simply clears the screen."""
546 import IPython.platutils
554 import IPython.platutils
547 IPython.platutils.term_clear()
555 IPython.platutils.term_clear()
548
556
549 class ClearDemo(ClearMixin,Demo):
557 class ClearDemo(ClearMixin,Demo):
550 pass
558 pass
551
559
552
560
553 class ClearIPDemo(ClearMixin,IPythonDemo):
561 class ClearIPDemo(ClearMixin,IPythonDemo):
554 pass
562 pass
General Comments 0
You need to be logged in to leave comments. Login now