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