##// END OF EJS Templates
fix again() bug in demo
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,175 +1,178 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 Sorry, but this uses Python 2.3 features, so it won't work in 2.2 environments.
3 Sorry, but this uses Python 2.3 features, so it won't work in 2.2 environments.
4 """
4 """
5 #*****************************************************************************
5 #*****************************************************************************
6 # Copyright (C) 2005 Fernando Perez. <Fernando.Perez@colorado.edu>
6 # Copyright (C) 2005 Fernando Perez. <Fernando.Perez@colorado.edu>
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #
10 #
11 #*****************************************************************************
11 #*****************************************************************************
12
12
13 import sys
13 import sys
14 import exceptions
14 import exceptions
15 import re
15 import re
16
16
17 from IPython.PyColorize import Parser
17 from IPython.PyColorize import Parser
18 from IPython.genutils import marquee, shlex_split
18 from IPython.genutils import marquee, shlex_split
19
19
20 class DemoError(exceptions.Exception): pass
20 class DemoError(exceptions.Exception): pass
21
21
22 class Demo:
22 class Demo:
23 def __init__(self,fname,arg_str='',mark_pause='# pause',
23 def __init__(self,fname,arg_str='',mark_pause='# pause',
24 mark_silent='# silent',auto=False):
24 mark_silent='# silent',auto=False):
25 """Make a new demo object. To run the demo, simply call the object.
25 """Make a new demo object. To run the demo, simply call the object.
26
26
27 Inputs:
27 Inputs:
28
28
29 - fname = filename.
29 - fname = filename.
30
30
31 Optional inputs:
31 Optional inputs:
32
32
33 - arg_str(''): a string of arguments, internally converted to a list
33 - arg_str(''): a string of arguments, internally converted to a list
34 just like sys.argv, so the demo script can see a similar
34 just like sys.argv, so the demo script can see a similar
35 environment.
35 environment.
36
36
37 - mark_pause ('# pause'), mark_silent('# silent'): marks for pausing
37 - mark_pause ('# pause'), mark_silent('# silent'): marks for pausing
38 (block boundaries) and to tag blocks as silent. The marks are
38 (block boundaries) and to tag blocks as silent. The marks are
39 turned into regexps which match them as standalone in a line, with
39 turned into regexps which match them as standalone in a line, with
40 all leading/trailing whitespace ignored.
40 all leading/trailing whitespace ignored.
41
41
42 - auto(False): flag to run each block automatically without
42 - auto(False): flag to run each block automatically without
43 confirmation. Note that silent blocks are always automatically
43 confirmation. Note that silent blocks are always automatically
44 executed. This flag is an attribute of the object, and can be
44 executed. This flag is an attribute of the object, and can be
45 changed at runtime simply by reassigning it.
45 changed at runtime simply by reassigning it.
46 """
46 """
47
47
48 self.fname = fname
48 self.fname = fname
49 self.mark_pause = mark_pause
49 self.mark_pause = mark_pause
50 self.re_pause = re.compile(r'^\s*%s\s*$' % mark_pause,re.MULTILINE)
50 self.re_pause = re.compile(r'^\s*%s\s*$' % mark_pause,re.MULTILINE)
51 self.mark_silent = mark_silent
51 self.mark_silent = mark_silent
52 self.re_silent = re.compile(r'^\s*%s\s*$' % mark_silent,re.MULTILINE)
52 self.re_silent = re.compile(r'^\s*%s\s*$' % mark_silent,re.MULTILINE)
53 self.auto = auto
53 self.auto = auto
54 self.sys_argv = [fname]+shlex_split(arg_str)
54 self.sys_argv = [fname]+shlex_split(arg_str)
55
55
56 # get a few things from ipython. While it's a bit ugly design-wise,
56 # get a few things from ipython. While it's a bit ugly design-wise,
57 # it ensures that things like color scheme and the like are always in
57 # it ensures that things like color scheme and the like are always in
58 # sync with the ipython mode being used. This class is only meant to
58 # sync with the ipython mode being used. This class is only meant to
59 # be used inside ipython anyways, so it's OK.
59 # be used inside ipython anyways, so it's OK.
60 self.ip_showtraceback = __IPYTHON__.showtraceback
60 self.ip_showtraceback = __IPYTHON__.showtraceback
61 self.ip_ns = __IPYTHON__.user_ns
61 self.ip_ns = __IPYTHON__.user_ns
62 self.ip_colors = __IPYTHON__.rc['colors']
62 self.ip_colors = __IPYTHON__.rc['colors']
63
63
64 # read data and parse into blocks
64 # read data and parse into blocks
65 fobj = file(fname,'r')
65 fobj = file(fname,'r')
66 self.src = fobj.read()
66 self.src = fobj.read()
67 fobj.close()
67 fobj.close()
68 self.src_blocks = [b.strip() for b in self.re_pause.split(self.src) if b]
68 self.src_blocks = [b.strip() for b in self.re_pause.split(self.src) if b]
69 self.silent = [bool(self.re_silent.findall(b)) for b in self.src_blocks]
69 self.silent = [bool(self.re_silent.findall(b)) for b in self.src_blocks]
70 self.nblocks = len(self.src_blocks)
70 self.nblocks = len(self.src_blocks)
71
71
72 # try to colorize blocks
72 # try to colorize blocks
73 colorize = Parser().format
73 colorize = Parser().format
74 col_scheme = self.ip_colors
74 col_scheme = self.ip_colors
75 self.src_blocks_colored = [colorize(s_blk,'str',col_scheme)
75 self.src_blocks_colored = [colorize(s_blk,'str',col_scheme)
76 for s_blk in self.src_blocks]
76 for s_blk in self.src_blocks]
77
77
78 # finish initialization
78 # finish initialization
79 self.reset()
79 self.reset()
80
80
81 def reset(self):
81 def reset(self):
82 """Reset the namespace and seek pointer to restart the demo"""
82 """Reset the namespace and seek pointer to restart the demo"""
83 self.user_ns = {}
83 self.user_ns = {}
84 self.finished = False
84 self.finished = False
85 self.block_index = 0
85 self.block_index = 0
86
86
87 def again(self):
87 def again(self):
88 """Repeat the last block"""
88 """Repeat the last block"""
89 self.block_index -= 1
89 self.block_index -= 1
90 self.finished = False
90 self()
91 self()
91
92
92 def _validate_index(self,index):
93 def _validate_index(self,index):
93 if index<0 or index>=self.nblocks:
94 if index<0 or index>=self.nblocks:
94 raise ValueError('invalid block index %s' % index)
95 raise ValueError('invalid block index %s' % index)
95
96
96 def seek(self,index):
97 def seek(self,index):
97 """Move the current seek pointer to the given block"""
98 """Move the current seek pointer to the given block"""
98 self._validate_index(index)
99 self._validate_index(index)
99 self.block_index = index-1
100 self.block_index = index-1
100 self.finished = False
101 self.finished = False
101
102
102 def show_block(self,index=None):
103 def show_block(self,index=None):
103 """Show a single block on screen"""
104 """Show a single block on screen"""
104 if index is None:
105 if index is None:
105 if self.finished:
106 if self.finished:
106 print 'Demo finished. Use reset() if you want to rerun it.'
107 print 'Demo finished. Use reset() if you want to rerun it.'
107 return
108 return
108 index = self.block_index
109 index = self.block_index
109 else:
110 else:
110 self._validate_index(index)
111 self._validate_index(index)
111 print marquee('<%s> block # %s (%s/%s)' %
112 print marquee('<%s> block # %s (%s remaining)' %
112 (self.fname,index,index+1,self.nblocks))
113 (self.fname,index,self.nblocks-index-1))
113 print self.src_blocks_colored[index],
114 print self.src_blocks_colored[index],
114
115
115 def show(self):
116 def show(self):
116 """Show entire demo on screen, block by block"""
117 """Show entire demo on screen, block by block"""
117
118
118 fname = self.fname
119 fname = self.fname
119 nblocks = self.nblocks
120 nblocks = self.nblocks
120 silent = self.silent
121 silent = self.silent
121 for index,block in enumerate(self.src_blocks_colored):
122 for index,block in enumerate(self.src_blocks_colored):
122 if silent[index]:
123 if silent[index]:
123 print marquee('<%s> SILENT block # %s (%s/%s)' %
124 print marquee('<%s> SILENT block # %s (%s remaining)' %
124 (fname,index,index+1,nblocks))
125 (fname,index,nblocks-index-1))
125 else:
126 else:
126 print marquee('<%s> block # %s (%s/%s)' %
127 print marquee('<%s> block # %s (%s remaining)' %
127 (fname,index,index+1,nblocks))
128 (fname,index,nblocks-index-1))
128 print block,
129 print block,
129
130
130 def __call__(self,index=None):
131 def __call__(self,index=None):
131 """run a block of the demo.
132 """run a block of the demo.
132
133
133 If index is given, it should be an integer >=1 and <= nblocks. This
134 If index is given, it should be an integer >=1 and <= nblocks. This
134 means that the calling convention is one off from typical Python
135 means that the calling convention is one off from typical Python
135 lists. The reason for the inconsistency is that the demo always
136 lists. The reason for the inconsistency is that the demo always
136 prints 'Block n/N, and N is the total, so it would be very odd to use
137 prints 'Block n/N, and N is the total, so it would be very odd to use
137 zero-indexing here."""
138 zero-indexing here."""
138
139
139 if index is None and self.finished:
140 if index is None and self.finished:
140 print 'Demo finished. Use reset() if you want to rerun it.'
141 print 'Demo finished. Use reset() if you want to rerun it.'
141 return
142 return
142 if index is None:
143 if index is None:
143 index = self.block_index
144 index = self.block_index
144 self._validate_index(index)
145 self._validate_index(index)
145 try:
146 try:
146 next_block = self.src_blocks[index]
147 next_block = self.src_blocks[index]
147 self.block_index += 1
148 self.block_index += 1
148 if self.silent[index]:
149 if self.silent[index]:
149 print marquee('Executing silent block # %s (%s/%s)' %
150 print marquee('Executing silent block # %s (%s remaining)' %
150 (index,index+1,self.nblocks))
151 (index,self.nblocks-index-1))
151 else:
152 else:
152 self.show_block(index)
153 self.show_block(index)
153 if not self.auto:
154 if self.auto:
155 print marquee('output')
156 else:
154 print marquee('Press <q> to quit, <Enter> to execute...'),
157 print marquee('Press <q> to quit, <Enter> to execute...'),
155 ans = raw_input().strip()
158 ans = raw_input().strip()
156 if ans:
159 if ans:
157 print marquee('Block NOT executed')
160 print marquee('Block NOT executed')
158 return
161 return
159 try:
162 try:
160 save_argv = sys.argv
163 save_argv = sys.argv
161 sys.argv = self.sys_argv
164 sys.argv = self.sys_argv
162 exec next_block in self.user_ns
165 exec next_block in self.user_ns
163 finally:
166 finally:
164 sys.argv = save_argv
167 sys.argv = save_argv
165
168
166 except:
169 except:
167 self.ip_showtraceback(filename=self.fname)
170 self.ip_showtraceback(filename=self.fname)
168 else:
171 else:
169 self.ip_ns.update(self.user_ns)
172 self.ip_ns.update(self.user_ns)
170
173
171 if self.block_index == self.nblocks:
174 if self.block_index == self.nblocks:
172 print
175 print
173 print marquee(' END OF DEMO ')
176 print marquee(' END OF DEMO ')
174 print marquee('Use reset() if you want to rerun it.')
177 print marquee('Use reset() if you want to rerun it.')
175 self.finished = True
178 self.finished = True
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now