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