##// END OF EJS Templates
- Bug fixes in Demo code to support demos with IPython syntax...
fperez -
Show More
@@ -1,7 +1,7 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Magic functions for InteractiveShell.
3 3
4 $Id: Magic.py 1981 2006-12-12 21:51:54Z vivainio $"""
4 $Id: Magic.py 2036 2007-01-27 07:30:22Z fperez $"""
5 5
6 6 #*****************************************************************************
7 7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
@@ -2617,16 +2617,20 b' Defaulting color scheme to \'NoColor\'"""'
2617 2617 if ps:
2618 2618 try:
2619 2619 os.chdir(os.path.expanduser(ps))
2620 ttitle = ("IPy:" + (
2621 os.getcwd() == '/' and '/' or os.path.basename(os.getcwd())))
2622 platutils.set_term_title(ttitle)
2620 if self.shell.rc.term_title:
2621 #print 'set term title:',self.shell.rc.term_title # dbg
2622 ttitle = ("IPy:" + (
2623 os.getcwd() == '/' and '/' or \
2624 os.path.basename(os.getcwd())))
2625 platutils.set_term_title(ttitle)
2623 2626 except OSError:
2624 2627 print sys.exc_info()[1]
2625 2628 else:
2626 2629 self.shell.user_ns['_dh'].append(os.getcwd())
2627 2630 else:
2628 2631 os.chdir(self.shell.home_dir)
2629 platutils.set_term_title("IPy:~")
2632 if self.shell.rc.term_title:
2633 platutils.set_term_title("IPy:~")
2630 2634 self.shell.user_ns['_dh'].append(os.getcwd())
2631 2635 if not 'q' in opts:
2632 2636 print self.shell.user_ns['_dh'][-1]
@@ -5,6 +5,10 b' 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
9 Provided classes
10 ================
11
8 12 The classes are (see their docstrings for further details):
9 13
10 14 - Demo: pure python demos
@@ -20,6 +24,24 b' The classes are (see their docstrings for further details):'
20 24 executed a line at a time, but processed via IPython).
21 25
22 26
27 Subclassing
28 ===========
29
30 The classes here all include a few methods meant to make customization by
31 subclassing more convenient. Their docstrings below have some more details:
32
33 - marquee(): generates a marquee to provide visible on-screen markers at each
34 block start and end.
35
36 - pre_cmd(): run right before the execution of each block.
37
38 - pre_cmd(): run right after the execution of each block. If the block
39 raises an exception, this is NOT called.
40
41
42 Operation
43 =========
44
23 45 The file is run in its own empty namespace (though you can pass it a string of
24 46 arguments as if in a command line environment, and it will see those as
25 47 sys.argv). But at each stop, the global IPython namespace is updated with the
@@ -76,6 +98,12 b' has a few useful methods for navigation, like again(), edit(), jump(), seek()'
76 98 and back(). It can be reset for a new run via reset() or reloaded from disk
77 99 (in case you've edited the source) via reload(). See their docstrings below.
78 100
101
102 Example
103 =======
104
105 The following is a very simple example of a valid demo file.
106
79 107 #################### EXAMPLE DEMO <ex_demo.py> ###############################
80 108 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
81 109
@@ -111,6 +139,7 b" print 'z is now:', z"
111 139 print 'bye!'
112 140 ################### END EXAMPLE DEMO <ex_demo.py> ############################
113 141 """
142
114 143 #*****************************************************************************
115 144 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
116 145 #
@@ -296,8 +325,8 b' class Demo:'
296 325 if index is None:
297 326 return
298 327
299 print marquee('<%s> block # %s (%s remaining)' %
300 (self.fname,index,self.nblocks-index-1))
328 print self.marquee('<%s> block # %s (%s remaining)' %
329 (self.fname,index,self.nblocks-index-1))
301 330 print self.src_blocks_colored[index],
302 331 sys.stdout.flush()
303 332
@@ -307,6 +336,7 b' class Demo:'
307 336 fname = self.fname
308 337 nblocks = self.nblocks
309 338 silent = self._silent
339 marquee = self.marquee
310 340 for index,block in enumerate(self.src_blocks_colored):
311 341 if silent[index]:
312 342 print marquee('<%s> SILENT block # %s (%s remaining)' %
@@ -335,6 +365,7 b' class Demo:'
335 365 if index is None:
336 366 return
337 367 try:
368 marquee = self.marquee
338 369 next_block = self.src_blocks[index]
339 370 self.block_index += 1
340 371 if self._silent[index]:
@@ -353,7 +384,9 b' class Demo:'
353 384 try:
354 385 save_argv = sys.argv
355 386 sys.argv = self.sys_argv
387 self.pre_cmd()
356 388 self.runlines(next_block)
389 self.post_cmd()
357 390 finally:
358 391 sys.argv = save_argv
359 392
@@ -364,10 +397,25 b' class Demo:'
364 397
365 398 if self.block_index == self.nblocks:
366 399 print
367 print marquee(' END OF DEMO ')
368 print marquee('Use reset() if you want to rerun it.')
400 print self.marquee(' END OF DEMO ')
401 print self.marquee('Use reset() if you want to rerun it.')
369 402 self.finished = True
370 403
404 # These methods are meant to be overridden by subclasses who may wish to
405 # customize the behavior of of their demos.
406 def marquee(self,txt='',width=78,mark='*'):
407 """Return the input string centered in a 'marquee'."""
408 return marquee(txt,width,mark)
409
410 def pre_cmd(self):
411 """Method called before executing each block."""
412 pass
413
414 def post_cmd(self):
415 """Method called after executing each block."""
416 pass
417
418
371 419 class IPythonDemo(Demo):
372 420 """Class for interactive demos with IPython's input processing applied.
373 421
@@ -384,7 +432,7 b' class IPythonDemo(Demo):'
384 432 def runlines(self,source):
385 433 """Execute a string with one or more lines of code"""
386 434
387 self.runlines(source)
435 self.shell.runlines(source)
388 436
389 437 class LineDemo(Demo):
390 438 """Demo where each line is executed as a separate block.
@@ -6,7 +6,7 b' Requires Python 2.1 or better.'
6 6
7 7 This file contains the main make_IPython() starter function.
8 8
9 $Id: ipmaker.py 2029 2007-01-22 06:35:15Z fperez $"""
9 $Id: ipmaker.py 2036 2007-01-27 07:30:22Z fperez $"""
10 10
11 11 #*****************************************************************************
12 12 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
@@ -162,7 +162,7 b" object? -> Details about 'object'. ?object also works, ?? prints more."
162 162 'separate_out2|so2=s xmode=s wildcards_case_sensitive! '
163 163 'magic_docstrings system_verbose! '
164 164 'multi_line_specials! '
165 'wxversion=s '
165 'term_title! wxversion=s '
166 166 'autoedit_syntax!')
167 167
168 168 # Options that can *only* appear at the cmd line (not in rcfiles).
@@ -225,6 +225,7 b" object? -> Details about 'object'. ?object also works, ?? prints more."
225 225 q4thread = 0,
226 226 wthread = 0,
227 227 pylab = 0,
228 term_title = 1,
228 229 tk = 0,
229 230 upgrade = 0,
230 231 Version = 0,
@@ -49,7 +49,7 b' runner [opts] script_name'
49 49 class InteractiveRunner(object):
50 50 """Class to run a sequence of commands through an interactive program."""
51 51
52 def __init__(self,program,prompts,args=None):
52 def __init__(self,program,prompts,args=None,out=sys.stdout,echo=True):
53 53 """Construct a runner.
54 54
55 55 Inputs:
@@ -73,6 +73,9 b' class InteractiveRunner(object):'
73 73 - args(None): optional list of strings to pass as arguments to the
74 74 child program.
75 75
76 - out(sys.stdout): if given, an output stream to be used when writing
77 output. The only requirement is that it must have a .write() method.
78
76 79 Public members not parameterized in the constructor:
77 80
78 81 - delaybeforesend(0): Newer versions of pexpect have a delay before
@@ -87,11 +90,30 b' class InteractiveRunner(object):'
87 90 self.prompts = prompts
88 91 if args is None: args = []
89 92 self.args = args
93 self.out = out
94 self.echo = echo
90 95 # Other public members which we don't make as parameters, but which
91 96 # users may occasionally want to tweak
92 97 self.delaybeforesend = 0
93
94 def run_file(self,fname,interact=False):
98
99 # Create child process and hold on to it so we don't have to re-create
100 # for every single execution call
101 c = self.child = pexpect.spawn(self.program,self.args,timeout=None)
102 c.delaybeforesend = self.delaybeforesend
103 # pexpect hard-codes the terminal size as (24,80) (rows,columns).
104 # This causes problems because any line longer than 80 characters gets
105 # completely overwrapped on the printed outptut (even though
106 # internally the code runs fine). We reset this to 99 rows X 200
107 # columns (arbitrarily chosen), which should avoid problems in all
108 # reasonable cases.
109 c.setwinsize(99,200)
110
111 def close(self):
112 """close child process"""
113
114 self.child.close()
115
116 def run_file(self,fname,interact=False,get_output=False):
95 117 """Run the given file interactively.
96 118
97 119 Inputs:
@@ -103,11 +125,13 b' class InteractiveRunner(object):'
103 125
104 126 fobj = open(fname,'r')
105 127 try:
106 self.run_source(fobj,interact)
128 out = self.run_source(fobj,interact,get_output)
107 129 finally:
108 130 fobj.close()
131 if get_output:
132 return out
109 133
110 def run_source(self,source,interact=False):
134 def run_source(self,source,interact=False,get_output=False):
111 135 """Run the given source code interactively.
112 136
113 137 Inputs:
@@ -119,6 +143,12 b' class InteractiveRunner(object):'
119 143
120 144 - interact(False): if true, start to interact with the running
121 145 program at the end of the script. Otherwise, just exit.
146
147 - get_output(False): if true, capture the output of the child process
148 (filtering the input commands out) and return it as a string.
149
150 Returns:
151 A string containing the process output, but only if requested.
122 152 """
123 153
124 154 # if the source is a string, chop it up in lines so we can iterate
@@ -126,39 +156,38 b' class InteractiveRunner(object):'
126 156 if not isinstance(source,file):
127 157 source = source.splitlines(True)
128 158
129 # grab the true write method of stdout, in case anything later
130 # reassigns sys.stdout, so that we really are writing to the true
131 # stdout and not to something else. We also normalize all strings we
132 # write to use the native OS line separators.
133 linesep = os.linesep
134 stdwrite = sys.stdout.write
135 write = lambda s: stdwrite(s.replace('\r\n',linesep))
136
137 c = pexpect.spawn(self.program,self.args,timeout=None)
138 c.delaybeforesend = self.delaybeforesend
139
140 # pexpect hard-codes the terminal size as (24,80) (rows,columns).
141 # This causes problems because any line longer than 80 characters gets
142 # completely overwrapped on the printed outptut (even though
143 # internally the code runs fine). We reset this to 99 rows X 200
144 # columns (arbitrarily chosen), which should avoid problems in all
145 # reasonable cases.
146 c.setwinsize(99,200)
159 if self.echo:
160 # normalize all strings we write to use the native OS line
161 # separators.
162 linesep = os.linesep
163 stdwrite = self.out.write
164 write = lambda s: stdwrite(s.replace('\r\n',linesep))
165 else:
166 # Quiet mode, all writes are no-ops
167 write = lambda s: None
147 168
169 c = self.child
148 170 prompts = c.compile_pattern_list(self.prompts)
149
150 171 prompt_idx = c.expect_list(prompts)
172
151 173 # Flag whether the script ends normally or not, to know whether we can
152 174 # do anything further with the underlying process.
153 175 end_normal = True
176
177 # If the output was requested, store it in a list for return at the end
178 if get_output:
179 output = []
180 store_output = output.append
181
154 182 for cmd in source:
155 183 # skip blank lines for all matches to the 'main' prompt, while the
156 184 # secondary prompts do not
157 185 if prompt_idx==0 and \
158 186 (cmd.isspace() or cmd.lstrip().startswith('#')):
159 print cmd,
187 write(cmd)
160 188 continue
161 189
190 #write('AFTER: '+c.after) # dbg
162 191 write(c.after)
163 192 c.send(cmd)
164 193 try:
@@ -168,8 +197,17 b' class InteractiveRunner(object):'
168 197 write(c.before)
169 198 end_normal = False
170 199 break
200
171 201 write(c.before)
172
202
203 # With an echoing process, the output we get in c.before contains
204 # the command sent, a newline, and then the actual process output
205 if get_output:
206 store_output(c.before[len(cmd+'\n'):])
207 #write('CMD: <<%s>>' % cmd) # dbg
208 #write('OUTPUT: <<%s>>' % output[-1]) # dbg
209
210 self.out.flush()
173 211 if end_normal:
174 212 if interact:
175 213 c.send('\n')
@@ -182,13 +220,19 b' class InteractiveRunner(object):'
182 220 # space is there to make sure it gets printed, otherwise
183 221 # OS buffering sometimes just suppresses it.
184 222 write(' \n')
185 sys.stdout.flush()
186 else:
187 c.close()
223 self.out.flush()
188 224 else:
189 225 if interact:
190 226 e="Further interaction is not possible: child process is dead."
191 227 print >> sys.stderr, e
228
229 # Leave the child ready for more input later on, otherwise select just
230 # hangs on the second invocation.
231 c.send('\n')
232
233 # Return any requested output
234 if get_output:
235 return ''.join(output)
192 236
193 237 def main(self,argv=None):
194 238 """Run as a command-line script."""
@@ -221,26 +265,28 b' class IPythonRunner(InteractiveRunner):'
221 265 prompts would break this.
222 266 """
223 267
224 def __init__(self,program = 'ipython',args=None):
268 def __init__(self,program = 'ipython',args=None,out=sys.stdout,echo=True):
225 269 """New runner, optionally passing the ipython command to use."""
226 270
227 271 args0 = ['-colors','NoColor',
228 272 '-pi1','In [\\#]: ',
229 '-pi2',' .\\D.: ']
273 '-pi2',' .\\D.: ',
274 '-noterm_title',
275 '-noautoindent']
230 276 if args is None: args = args0
231 277 else: args = args0 + args
232 278 prompts = [r'In \[\d+\]: ',r' \.*: ']
233 InteractiveRunner.__init__(self,program,prompts,args)
279 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
234 280
235 281
236 282 class PythonRunner(InteractiveRunner):
237 283 """Interactive Python runner."""
238 284
239 def __init__(self,program='python',args=None):
285 def __init__(self,program='python',args=None,out=sys.stdout,echo=True):
240 286 """New runner, optionally passing the python command to use."""
241 287
242 288 prompts = [r'>>> ',r'\.\.\. ']
243 InteractiveRunner.__init__(self,program,prompts,args)
289 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
244 290
245 291
246 292 class SAGERunner(InteractiveRunner):
@@ -250,11 +296,11 b' class SAGERunner(InteractiveRunner):'
250 296 to use 'colors NoColor' in the ipythonrc config file, since currently the
251 297 prompt matching regexp does not identify color sequences."""
252 298
253 def __init__(self,program='sage',args=None):
299 def __init__(self,program='sage',args=None,out=sys.stdout,echo=True):
254 300 """New runner, optionally passing the sage command to use."""
255 301
256 302 prompts = ['sage: ',r'\s*\.\.\. ']
257 InteractiveRunner.__init__(self,program,prompts,args)
303 InteractiveRunner.__init__(self,program,prompts,args,out,echo)
258 304
259 305 # Global usage string, to avoid indentation issues if typed in a function def.
260 306 MAIN_USAGE = """
@@ -1,3 +1,15 b''
1 2007-01-27 Fernando Perez <Fernando.Perez@colorado.edu>
2
3 * IPython/irunner.py (InteractiveRunner.run_source): major updates
4 to irunner to allow it to correctly support real doctesting of
5 out-of-process ipython code.
6
7 * IPython/Magic.py (magic_cd): Make the setting of the terminal
8 title an option (-noterm_title) because it completely breaks
9 doctesting.
10
11 * IPython/demo.py: fix IPythonDemo class that was not actually working.
12
1 13 2007-01-24 Fernando Perez <Fernando.Perez@colorado.edu>
2 14
3 15 * IPython/irunner.py (main): fix small bug where extensions were
General Comments 0
You need to be logged in to leave comments. Login now