~ellisonbg/ipython/trunk-dev

« back to all changes in this revision

Viewing changes to IPython/lib/demo.py

  • Committer: Brian Granger
  • Date: 2010-01-31 23:57:46 UTC
  • mfrom: (1109.1.113 ipython)
  • Revision ID: ellisonbg@gmail.com-20100131235746-rj81qa8klooepq2m
Merging from upstream trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
111
111
and back().  It can be reset for a new run via reset() or reloaded from disk
112
112
(in case you've edited the source) via reload().  See their docstrings below.
113
113
 
 
114
Note: To make this simpler to explore, a file called "demo-exercizer.py" has
 
115
been added to the "docs/examples/core" directory.  Just cd to this directory in
 
116
an IPython session, and type::
 
117
 
 
118
  %run demo-exercizer.py
 
119
  
 
120
and then follow the directions.
114
121
 
115
122
Example
116
123
=======
125
132
# The mark below defines a block boundary, which is a point where IPython will
126
133
# stop execution and return to the interactive prompt. The dashes are actually
127
134
# optional and used only as a visual aid to clearly separate blocks while
128
 
editing the demo code.
 
135
# editing the demo code.
129
136
# <demo> stop
130
137
 
131
138
x = 1
168
175
import shlex
169
176
import sys
170
177
 
171
 
from IPython.PyColorize import Parser
172
 
from IPython.genutils import marquee, file_read, file_readlines
 
178
from IPython.utils.PyColorize import Parser
 
179
from IPython.utils.io import file_read, file_readlines, Term
 
180
from IPython.utils.text import marquee
173
181
 
174
182
__all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
175
183
 
185
193
    re_auto     = re_mark('auto')
186
194
    re_auto_all = re_mark('auto_all')
187
195
 
188
 
    def __init__(self,fname,arg_str='',auto_all=None):
 
196
    def __init__(self,src,title='',arg_str='',auto_all=None):
189
197
        """Make a new demo object.  To run the demo, simply call the object.
190
198
 
191
199
        See the module docstring for full details and an example (you can use
193
201
 
194
202
        Inputs:
195
203
        
196
 
          - fname = filename.
 
204
          - src is either a file, or file-like object, or a
 
205
              string that can be resolved to a filename.
197
206
 
198
207
        Optional inputs:
 
208
        
 
209
          - title: a string to use as the demo name.  Of most use when the demo
 
210
          you are making comes from an object that has no filename, or if you 
 
211
          want an alternate denotation distinct from the filename.
199
212
 
200
213
          - arg_str(''): a string of arguments, internally converted to a list
201
214
          just like sys.argv, so the demo script can see a similar
207
220
          can be changed at runtime simply by reassigning it to a boolean
208
221
          value.
209
222
          """
210
 
        
211
 
        self.fname    = fname
212
 
        self.sys_argv = [fname] + shlex.split(arg_str)
 
223
        if hasattr(src, "read"):
 
224
             # It seems to be a file or a file-like object
 
225
            self.fobj = src
 
226
            self.fname = "from a file-like object"
 
227
            if title == '':
 
228
                self.title = "from a file-like object"
 
229
            else:
 
230
                self.title = title
 
231
        else:
 
232
             # Assume it's a string or something that can be converted to one
 
233
            self.fobj = open(src)
 
234
            self.fname = src
 
235
            if title == '':
 
236
                (filepath, filename) = os.path.split(src)
 
237
                self.title = filename
 
238
            else:
 
239
                self.title = title
 
240
        self.sys_argv = [src] + shlex.split(arg_str)
213
241
        self.auto_all = auto_all
214
242
        
215
243
        # get a few things from ipython.  While it's a bit ugly design-wise,
228
256
    def reload(self):
229
257
        """Reload source from disk and initialize state."""
230
258
        # read data and parse into blocks
231
 
        self.src     = file_read(self.fname)
 
259
        self.src     = self.fobj.read()
232
260
        src_b        = [b.strip() for b in self.re_stop.split(self.src) if b]
233
261
        self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
234
262
        self._auto   = [bool(self.re_auto.findall(b)) for b in src_b]
277
305
        
278
306
        if index is None:
279
307
            if self.finished:
280
 
                print 'Demo finished.  Use reset() if you want to rerun it.'
 
308
                print >>Term.cout, 'Demo finished.  Use <demo_name>.reset() if you want to rerun it.'
281
309
                return None
282
310
            index = self.block_index
283
311
        else:
346
374
        if index is None:
347
375
            return
348
376
 
349
 
        print self.marquee('<%s> block # %s (%s remaining)' %
350
 
                           (self.fname,index,self.nblocks-index-1))
351
 
        sys.stdout.write(self.src_blocks_colored[index])
 
377
        print >>Term.cout, self.marquee('<%s> block # %s (%s remaining)' %
 
378
                           (self.title,index,self.nblocks-index-1))
 
379
        print >>Term.cout,(self.src_blocks_colored[index])
352
380
        sys.stdout.flush()
353
381
 
354
382
    def show_all(self):
355
383
        """Show entire demo on screen, block by block"""
356
384
 
357
 
        fname = self.fname
 
385
        fname = self.title
 
386
        title = self.title
358
387
        nblocks = self.nblocks
359
388
        silent = self._silent
360
389
        marquee = self.marquee
361
390
        for index,block in enumerate(self.src_blocks_colored):
362
391
            if silent[index]:
363
 
                print marquee('<%s> SILENT block # %s (%s remaining)' %
364
 
                              (fname,index,nblocks-index-1))
 
392
                print >>Term.cout, marquee('<%s> SILENT block # %s (%s remaining)' %
 
393
                              (title,index,nblocks-index-1))
365
394
            else:
366
 
                print marquee('<%s> block # %s (%s remaining)' %
367
 
                              (fname,index,nblocks-index-1))
368
 
            print block,
 
395
                print >>Term.cout, marquee('<%s> block # %s (%s remaining)' %
 
396
                              (title,index,nblocks-index-1))
 
397
            print >>Term.cout, block,
369
398
        sys.stdout.flush()
370
399
 
371
400
    def runlines(self,source):
390
419
            next_block = self.src_blocks[index]
391
420
            self.block_index += 1
392
421
            if self._silent[index]:
393
 
                print marquee('Executing silent block # %s (%s remaining)' %
 
422
                print >>Term.cout, marquee('Executing silent block # %s (%s remaining)' %
394
423
                              (index,self.nblocks-index-1))
395
424
            else:
396
425
                self.pre_cmd()
397
426
                self.show(index)
398
427
                if self.auto_all or self._auto[index]:
399
 
                    print marquee('output:')
 
428
                    print >>Term.cout, marquee('output:')
400
429
                else:
401
 
                    print marquee('Press <q> to quit, <Enter> to execute...'),
 
430
                    print >>Term.cout, marquee('Press <q> to quit, <Enter> to execute...'),
402
431
                    ans = raw_input().strip()
403
432
                    if ans:
404
 
                        print marquee('Block NOT executed')
 
433
                        print >>Term.cout, marquee('Block NOT executed')
405
434
                        return
406
435
            try:
407
436
                save_argv = sys.argv
419
448
        if self.block_index == self.nblocks:
420
449
            mq1 = self.marquee('END OF DEMO')
421
450
            if mq1:
422
 
                # avoid spurious prints if empty marquees are used
423
 
                print
424
 
                print mq1
425
 
                print self.marquee('Use reset() if you want to rerun it.')
 
451
                # avoid spurious print >>Term.cout,s if empty marquees are used
 
452
                print >>Term.cout
 
453
                print >>Term.cout, mq1
 
454
                print >>Term.cout, self.marquee('Use <demo_name>.reset() if you want to rerun it.')
426
455
            self.finished = True
427
456
 
428
457
    # These methods are meant to be overridden by subclasses who may wish to
471
500
    def reload(self):
472
501
        """Reload source from disk and initialize state."""
473
502
        # read data and parse into blocks
474
 
        src_b           = [l for l in file_readlines(self.fname) if l.strip()]
 
503
        src_b           = [l for l in self.fobj.readline() if l.strip()]
475
504
        nblocks         = len(src_b)
476
 
        self.src        = os.linesep.join(file_readlines(self.fname))
 
505
        self.src        = os.linesep.join(self.fobj.readlines())
477
506
        self._silent    = [False]*nblocks
478
507
        self._auto      = [True]*nblocks
479
508
        self.auto_all   = True
494
523
 
495
524
class ClearMixin(object):
496
525
    """Use this mixin to make Demo classes with less visual clutter.
497
 
 
 
526
    
498
527
    Demos using this mixin will clear the screen before every block and use
499
528
    blank marquees.
500
 
 
 
529
    
501
530
    Note that in order for the methods defined here to actually override those
502
531
    of the classes it's mixed with, it must go /first/ in the inheritance
503
532
    tree.  For example:
504
 
 
 
533
    
505
534
        class ClearIPDemo(ClearMixin,IPythonDemo): pass
506
 
 
 
535
    
507
536
    will provide an IPythonDemo class with the mixin's features.
508
537
    """
509
538
    
510
539
    def marquee(self,txt='',width=78,mark='*'):
511
540
        """Blank marquee that returns '' no matter what the input."""
512
541
        return ''
513
 
 
 
542
    
514
543
    def pre_cmd(self):
515
544
        """Method called before executing each block.
516
 
 
 
545
        
517
546
        This one simply clears the screen."""
518
 
        os.system('clear')
519
 
 
 
547
        from IPython.utils.terminal import term_clear
 
548
        term_clear()
520
549
 
521
550
class ClearDemo(ClearMixin,Demo):
522
551
    pass