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