##// END OF EJS Templates
fix borken demo.py
Moez Bouhlel -
Show More
@@ -1,583 +1,582 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 107 copy this into a file named ex_demo.py, and try running it via::
108 108
109 109 from IPython.demo import Demo
110 110 d = Demo('ex_demo.py')
111 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 from IPython.utils import io
187 186 from IPython.utils.text import marquee
188 187 from IPython.utils import openpy
189 188 from IPython.utils import py3compat
190 189 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
191 190
192 191 class DemoError(Exception): pass
193 192
194 193 def re_mark(mark):
195 194 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
196 195
197 196 class Demo(object):
198 197
199 198 re_stop = re_mark('-*\s?stop\s?-*')
200 199 re_silent = re_mark('silent')
201 200 re_auto = re_mark('auto')
202 201 re_auto_all = re_mark('auto_all')
203 202
204 203 def __init__(self,src,title='',arg_str='',auto_all=None):
205 204 """Make a new demo object. To run the demo, simply call the object.
206 205
207 206 See the module docstring for full details and an example (you can use
208 207 IPython.Demo? in IPython to see it).
209 208
210 209 Inputs:
211 210
212 211 - src is either a file, or file-like object, or a
213 212 string that can be resolved to a filename.
214 213
215 214 Optional inputs:
216 215
217 216 - title: a string to use as the demo name. Of most use when the demo
218 217 you are making comes from an object that has no filename, or if you
219 218 want an alternate denotation distinct from the filename.
220 219
221 220 - arg_str(''): a string of arguments, internally converted to a list
222 221 just like sys.argv, so the demo script can see a similar
223 222 environment.
224 223
225 224 - auto_all(None): global flag to run all blocks automatically without
226 225 confirmation. This attribute overrides the block-level tags and
227 226 applies to the whole demo. It is an attribute of the object, and
228 227 can be changed at runtime simply by reassigning it to a boolean
229 228 value.
230 229 """
231 230 if hasattr(src, "read"):
232 231 # It seems to be a file or a file-like object
233 232 self.fname = "from a file-like object"
234 233 if title == '':
235 234 self.title = "from a file-like object"
236 235 else:
237 236 self.title = title
238 237 else:
239 238 # Assume it's a string or something that can be converted to one
240 239 self.fname = src
241 240 if title == '':
242 241 (filepath, filename) = os.path.split(src)
243 242 self.title = filename
244 243 else:
245 244 self.title = title
246 245 self.sys_argv = [src] + shlex.split(arg_str)
247 246 self.auto_all = auto_all
248 247 self.src = src
249 248
250 249 # get a few things from ipython. While it's a bit ugly design-wise,
251 250 # it ensures that things like color scheme and the like are always in
252 251 # sync with the ipython mode being used. This class is only meant to
253 252 # be used inside ipython anyways, so it's OK.
254 253 ip = get_ipython() # this is in builtins whenever IPython is running
255 254 self.ip_ns = ip.user_ns
256 255 self.ip_colorize = ip.pycolorize
257 256 self.ip_showtb = ip.showtraceback
258 257 self.ip_run_cell = ip.run_cell
259 258 self.shell = ip
260 259
261 260 # load user data and initialize data structures
262 261 self.reload()
263 262
264 263 def fload(self):
265 264 """Load file object."""
266 265 # read data and parse into blocks
267 266 if hasattr(self, 'fobj') and self.fobj is not None:
268 267 self.fobj.close()
269 268 if hasattr(self.src, "read"):
270 269 # It seems to be a file or a file-like object
271 270 self.fobj = self.src
272 271 else:
273 272 # Assume it's a string or something that can be converted to one
274 273 self.fobj = openpy.open(self.fname)
275 274
276 275 def reload(self):
277 276 """Reload source from disk and initialize state."""
278 277 self.fload()
279 278
280 279 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
281 280 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
282 281 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
283 282 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
284 283
285 284 # if auto_all is not given (def. None), we read it from the file
286 285 if self.auto_all is None:
287 286 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
288 287 else:
289 288 self.auto_all = bool(self.auto_all)
290 289
291 290 # Clean the sources from all markup so it doesn't get displayed when
292 291 # running the demo
293 292 src_blocks = []
294 293 auto_strip = lambda s: self.re_auto.sub('',s)
295 294 for i,b in enumerate(src_b):
296 295 if self._auto[i]:
297 296 src_blocks.append(auto_strip(b))
298 297 else:
299 298 src_blocks.append(b)
300 299 # remove the auto_all marker
301 300 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
302 301
303 302 self.nblocks = len(src_blocks)
304 303 self.src_blocks = src_blocks
305 304
306 305 # also build syntax-highlighted source
307 306 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
308 307
309 308 # ensure clean namespace and seek offset
310 309 self.reset()
311 310
312 311 def reset(self):
313 312 """Reset the namespace and seek pointer to restart the demo"""
314 313 self.user_ns = {}
315 314 self.finished = False
316 315 self.block_index = 0
317 316
318 317 def _validate_index(self,index):
319 318 if index<0 or index>=self.nblocks:
320 319 raise ValueError('invalid block index %s' % index)
321 320
322 321 def _get_index(self,index):
323 322 """Get the current block index, validating and checking status.
324 323
325 324 Returns None if the demo is finished"""
326 325
327 326 if index is None:
328 327 if self.finished:
329 328 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.')
330 329 return None
331 330 index = self.block_index
332 331 else:
333 332 self._validate_index(index)
334 333 return index
335 334
336 335 def seek(self,index):
337 336 """Move the current seek pointer to the given block.
338 337
339 338 You can use negative indices to seek from the end, with identical
340 339 semantics to those of Python lists."""
341 340 if index<0:
342 341 index = self.nblocks + index
343 342 self._validate_index(index)
344 343 self.block_index = index
345 344 self.finished = False
346 345
347 346 def back(self,num=1):
348 347 """Move the seek pointer back num blocks (default is 1)."""
349 348 self.seek(self.block_index-num)
350 349
351 350 def jump(self,num=1):
352 351 """Jump a given number of blocks relative to the current one.
353 352
354 353 The offset can be positive or negative, defaults to 1."""
355 354 self.seek(self.block_index+num)
356 355
357 356 def again(self):
358 357 """Move the seek pointer back one block and re-execute."""
359 358 self.back(1)
360 359 self()
361 360
362 361 def edit(self,index=None):
363 362 """Edit a block.
364 363
365 364 If no number is given, use the last block executed.
366 365
367 366 This edits the in-memory copy of the demo, it does NOT modify the
368 367 original source file. If you want to do that, simply open the file in
369 368 an editor and use reload() when you make changes to the file. This
370 369 method is meant to let you change a block during a demonstration for
371 370 explanatory purposes, without damaging your original script."""
372 371
373 372 index = self._get_index(index)
374 373 if index is None:
375 374 return
376 375 # decrease the index by one (unless we're at the very beginning), so
377 376 # that the default demo.edit() call opens up the sblock we've last run
378 377 if index>0:
379 378 index -= 1
380 379
381 380 filename = self.shell.mktempfile(self.src_blocks[index])
382 381 self.shell.hooks.editor(filename,1)
383 382 with open(filename, 'r') as f:
384 383 new_block = f.read()
385 384 # update the source and colored block
386 385 self.src_blocks[index] = new_block
387 386 self.src_blocks_colored[index] = self.ip_colorize(new_block)
388 387 self.block_index = index
389 388 # call to run with the newly edited index
390 389 self()
391 390
392 391 def show(self,index=None):
393 392 """Show a single block on screen"""
394 393
395 394 index = self._get_index(index)
396 395 if index is None:
397 396 return
398 397
399 398 print(self.marquee('<%s> block # %s (%s remaining)' %
400 399 (self.title,index,self.nblocks-index-1)))
401 400 print(self.src_blocks_colored[index])
402 401 sys.stdout.flush()
403 402
404 403 def show_all(self):
405 404 """Show entire demo on screen, block by block"""
406 405
407 406 fname = self.title
408 407 title = self.title
409 408 nblocks = self.nblocks
410 409 silent = self._silent
411 410 marquee = self.marquee
412 411 for index,block in enumerate(self.src_blocks_colored):
413 412 if silent[index]:
414 413 print(marquee('<%s> SILENT block # %s (%s remaining)' %
415 414 (title,index,nblocks-index-1)))
416 415 else:
417 416 print(marquee('<%s> block # %s (%s remaining)' %
418 417 (title,index,nblocks-index-1)))
419 418 print(block, end=' ')
420 419 sys.stdout.flush()
421 420
422 421 def run_cell(self,source):
423 422 """Execute a string with one or more lines of code"""
424 423
425 424 exec(source, self.user_ns)
426 425
427 426 def __call__(self,index=None):
428 427 """run a block of the demo.
429 428
430 429 If index is given, it should be an integer >=1 and <= nblocks. This
431 430 means that the calling convention is one off from typical Python
432 431 lists. The reason for the inconsistency is that the demo always
433 432 prints 'Block n/N, and N is the total, so it would be very odd to use
434 433 zero-indexing here."""
435 434
436 435 index = self._get_index(index)
437 436 if index is None:
438 437 return
439 438 try:
440 439 marquee = self.marquee
441 440 next_block = self.src_blocks[index]
442 441 self.block_index += 1
443 442 if self._silent[index]:
444 443 print(marquee('Executing silent block # %s (%s remaining)' %
445 444 (index,self.nblocks-index-1)))
446 445 else:
447 446 self.pre_cmd()
448 447 self.show(index)
449 448 if self.auto_all or self._auto[index]:
450 449 print(marquee('output:'))
451 450 else:
452 451 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ')
453 452 ans = py3compat.input().strip()
454 453 if ans:
455 454 print(marquee('Block NOT executed'))
456 455 return
457 456 try:
458 457 save_argv = sys.argv
459 458 sys.argv = self.sys_argv
460 459 self.run_cell(next_block)
461 460 self.post_cmd()
462 461 finally:
463 462 sys.argv = save_argv
464 463
465 464 except:
466 465 self.ip_showtb(filename=self.fname)
467 466 else:
468 467 self.ip_ns.update(self.user_ns)
469 468
470 469 if self.block_index == self.nblocks:
471 470 mq1 = self.marquee('END OF DEMO')
472 471 if mq1:
473 472 # avoid spurious print if empty marquees are used
474 473 print()
475 474 print(mq1)
476 475 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'))
477 476 self.finished = True
478 477
479 478 # These methods are meant to be overridden by subclasses who may wish to
480 479 # customize the behavior of of their demos.
481 480 def marquee(self,txt='',width=78,mark='*'):
482 481 """Return the input string centered in a 'marquee'."""
483 482 return marquee(txt,width,mark)
484 483
485 484 def pre_cmd(self):
486 485 """Method called before executing each block."""
487 486 pass
488 487
489 488 def post_cmd(self):
490 489 """Method called after executing each block."""
491 490 pass
492 491
493 492
494 493 class IPythonDemo(Demo):
495 494 """Class for interactive demos with IPython's input processing applied.
496 495
497 496 This subclasses Demo, but instead of executing each block by the Python
498 497 interpreter (via exec), it actually calls IPython on it, so that any input
499 498 filters which may be in place are applied to the input block.
500 499
501 500 If you have an interactive environment which exposes special input
502 501 processing, you can use this class instead to write demo scripts which
503 502 operate exactly as if you had typed them interactively. The default Demo
504 503 class requires the input to be valid, pure Python code.
505 504 """
506 505
507 506 def run_cell(self,source):
508 507 """Execute a string with one or more lines of code"""
509 508
510 509 self.shell.run_cell(source)
511 510
512 511 class LineDemo(Demo):
513 512 """Demo where each line is executed as a separate block.
514 513
515 514 The input script should be valid Python code.
516 515
517 516 This class doesn't require any markup at all, and it's meant for simple
518 517 scripts (with no nesting or any kind of indentation) which consist of
519 518 multiple lines of input to be executed, one at a time, as if they had been
520 519 typed in the interactive prompt.
521 520
522 521 Note: the input can not have *any* indentation, which means that only
523 522 single-lines of input are accepted, not even function definitions are
524 523 valid."""
525 524
526 525 def reload(self):
527 526 """Reload source from disk and initialize state."""
528 527 # read data and parse into blocks
529 528 self.fload()
530 529 lines = self.fobj.readlines()
531 530 src_b = [l for l in lines if l.strip()]
532 531 nblocks = len(src_b)
533 532 self.src = ''.join(lines)
534 533 self._silent = [False]*nblocks
535 534 self._auto = [True]*nblocks
536 535 self.auto_all = True
537 536 self.nblocks = nblocks
538 537 self.src_blocks = src_b
539 538
540 539 # also build syntax-highlighted source
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
540 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
542 541
543 542 # ensure clean namespace and seek offset
544 543 self.reset()
545 544
546 545
547 546 class IPythonLineDemo(IPythonDemo,LineDemo):
548 547 """Variant of the LineDemo class whose input is processed by IPython."""
549 548 pass
550 549
551 550
552 551 class ClearMixin(object):
553 552 """Use this mixin to make Demo classes with less visual clutter.
554 553
555 554 Demos using this mixin will clear the screen before every block and use
556 555 blank marquees.
557 556
558 557 Note that in order for the methods defined here to actually override those
559 558 of the classes it's mixed with, it must go /first/ in the inheritance
560 559 tree. For example:
561 560
562 561 class ClearIPDemo(ClearMixin,IPythonDemo): pass
563 562
564 563 will provide an IPythonDemo class with the mixin's features.
565 564 """
566 565
567 566 def marquee(self,txt='',width=78,mark='*'):
568 567 """Blank marquee that returns '' no matter what the input."""
569 568 return ''
570 569
571 570 def pre_cmd(self):
572 571 """Method called before executing each block.
573 572
574 573 This one simply clears the screen."""
575 from IPython.utils.terminal import term_clear
576 term_clear()
574 from IPython.utils.terminal import _term_clear
575 _term_clear()
577 576
578 577 class ClearDemo(ClearMixin,Demo):
579 578 pass
580 579
581 580
582 581 class ClearIPDemo(ClearMixin,IPythonDemo):
583 582 pass
General Comments 0
You need to be logged in to leave comments. Login now