##// END OF EJS Templates
Make sure splitter._buffer is reset. Handle suppressed output better
Skipper Seabold -
Show More
@@ -1,808 +1,812 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Sphinx directive to support embedded IPython code.
3 3
4 4 This directive allows pasting of entire interactive IPython sessions, prompts
5 5 and all, and their code will actually get re-executed at doc build time, with
6 6 all prompts renumbered sequentially. It also allows you to input code as a pure
7 7 python input by giving the argument python to the directive. The output looks
8 8 like an interactive ipython section.
9 9
10 10 To enable this directive, simply list it in your Sphinx ``conf.py`` file
11 11 (making sure the directory where you placed it is visible to sphinx, as is
12 12 needed for all Sphinx directives).
13 13
14 14 By default this directive assumes that your prompts are unchanged IPython ones,
15 15 but this can be customized. The configurable options that can be placed in
16 16 conf.py are
17 17
18 18 ipython_savefig_dir:
19 19 The directory in which to save the figures. This is relative to the
20 20 Sphinx source directory. The default is `html_static_path`.
21 21 ipython_rgxin:
22 22 The compiled regular expression to denote the start of IPython input
23 23 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
24 24 shouldn't need to change this.
25 25 ipython_rgxout:
26 26 The compiled regular expression to denote the start of IPython output
27 27 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
28 28 shouldn't need to change this.
29 29 ipython_promptin:
30 30 The string to represent the IPython input prompt in the generated ReST.
31 31 The default is 'In [%d]:'. This expects that the line numbers are used
32 32 in the prompt.
33 33 ipython_promptout:
34 34
35 35 The string to represent the IPython prompt in the generated ReST. The
36 36 default is 'Out [%d]:'. This expects that the line numbers are used
37 37 in the prompt.
38 38
39 39 ToDo
40 40 ----
41 41
42 42 - Turn the ad-hoc test() function into a real test suite.
43 43 - Break up ipython-specific functionality from matplotlib stuff into better
44 44 separated code.
45 45
46 46 Authors
47 47 -------
48 48
49 49 - John D Hunter: orignal author.
50 50 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
51 51 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
52 52 - Skipper Seabold, refactoring, cleanups, pure python addition
53 53 """
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Imports
57 57 #-----------------------------------------------------------------------------
58 58
59 59 # Stdlib
60 60 import cStringIO
61 61 import os
62 62 import re
63 63 import sys
64 64 import tempfile
65 65
66 66 # To keep compatibility with various python versions
67 67 try:
68 68 from hashlib import md5
69 69 except ImportError:
70 70 from md5 import md5
71 71
72 72 # Third-party
73 73 import matplotlib
74 74 import sphinx
75 75 from docutils.parsers.rst import directives
76 76 from docutils import nodes
77 77 from sphinx.util.compat import Directive
78 78
79 79 matplotlib.use('Agg')
80 80
81 81 # Our own
82 82 from IPython import Config, InteractiveShell
83 83 from IPython.core.profiledir import ProfileDir
84 84 from IPython.utils import io
85 85
86 86 #-----------------------------------------------------------------------------
87 87 # Globals
88 88 #-----------------------------------------------------------------------------
89 89 # for tokenizing blocks
90 90 COMMENT, INPUT, OUTPUT = range(3)
91 91
92 92 #-----------------------------------------------------------------------------
93 93 # Functions and class declarations
94 94 #-----------------------------------------------------------------------------
95 95 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
96 96 """
97 97 part is a string of ipython text, comprised of at most one
98 98 input, one ouput, comments, and blank lines. The block parser
99 99 parses the text into a list of::
100 100
101 101 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
102 102
103 103 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
104 104 data is, depending on the type of token::
105 105
106 106 COMMENT : the comment string
107 107
108 108 INPUT: the (DECORATOR, INPUT_LINE, REST) where
109 109 DECORATOR: the input decorator (or None)
110 110 INPUT_LINE: the input as string (possibly multi-line)
111 111 REST : any stdout generated by the input line (not OUTPUT)
112 112
113 113
114 114 OUTPUT: the output string, possibly multi-line
115 115 """
116 116
117 117 block = []
118 118 lines = part.split('\n')
119 119 N = len(lines)
120 120 i = 0
121 121 decorator = None
122 122 while 1:
123 123
124 124 if i==N:
125 125 # nothing left to parse -- the last line
126 126 break
127 127
128 128 line = lines[i]
129 129 i += 1
130 130 line_stripped = line.strip()
131 131 if line_stripped.startswith('#'):
132 132 block.append((COMMENT, line))
133 133 continue
134 134
135 135 if line_stripped.startswith('@'):
136 136 # we're assuming at most one decorator -- may need to
137 137 # rethink
138 138 decorator = line_stripped
139 139 continue
140 140
141 141 # does this look like an input line?
142 142 matchin = rgxin.match(line)
143 143 if matchin:
144 144 lineno, inputline = int(matchin.group(1)), matchin.group(2)
145 145
146 146 # the ....: continuation string
147 147 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
148 148 Nc = len(continuation)
149 149 # input lines can continue on for more than one line, if
150 150 # we have a '\' line continuation char or a function call
151 151 # echo line 'print'. The input line can only be
152 152 # terminated by the end of the block or an output line, so
153 153 # we parse out the rest of the input line if it is
154 154 # multiline as well as any echo text
155 155
156 156 rest = []
157 157 while i<N:
158 158
159 159 # look ahead; if the next line is blank, or a comment, or
160 160 # an output line, we're done
161 161
162 162 nextline = lines[i]
163 163 matchout = rgxout.match(nextline)
164 164 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
165 165 if matchout or nextline.startswith('#'):
166 166 break
167 167 elif nextline.startswith(continuation):
168 168 inputline += '\n' + nextline[Nc:]
169 169 else:
170 170 rest.append(nextline)
171 171 i+= 1
172 172
173 173 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
174 174 continue
175 175
176 176 # if it looks like an output line grab all the text to the end
177 177 # of the block
178 178 matchout = rgxout.match(line)
179 179 if matchout:
180 180 lineno, output = int(matchout.group(1)), matchout.group(2)
181 181 if i<N-1:
182 182 output = '\n'.join([output] + lines[i:])
183 183
184 184 block.append((OUTPUT, output))
185 185 break
186 186
187 187 return block
188 188
189 189 class EmbeddedSphinxShell(object):
190 190 """An embedded IPython instance to run inside Sphinx"""
191 191
192 192 def __init__(self):
193 193
194 194 self.cout = cStringIO.StringIO()
195 195
196 196
197 197 # Create config object for IPython
198 198 config = Config()
199 199 config.Global.display_banner = False
200 200 config.Global.exec_lines = ['import numpy as np',
201 201 'from pylab import *'
202 202 ]
203 203 config.InteractiveShell.autocall = False
204 204 config.InteractiveShell.autoindent = False
205 205 config.InteractiveShell.colors = 'NoColor'
206 206
207 207 # create a profile so instance history isn't saved
208 208 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
209 209 profname = 'auto_profile_sphinx_build'
210 210 pdir = os.path.join(tmp_profile_dir,profname)
211 211 profile = ProfileDir.create_profile_dir(pdir)
212 212
213 213 # Create and initialize ipython, but don't start its mainloop
214 214 IP = InteractiveShell.instance(config=config, profile_dir=profile)
215 215 # io.stdout redirect must be done *after* instantiating InteractiveShell
216 216 io.stdout = self.cout
217 217 io.stderr = self.cout
218 218
219 219 # For debugging, so we can see normal output, use this:
220 220 #from IPython.utils.io import Tee
221 221 #io.stdout = Tee(self.cout, channel='stdout') # dbg
222 222 #io.stderr = Tee(self.cout, channel='stderr') # dbg
223 223
224 224 # Store a few parts of IPython we'll need.
225 225 self.IP = IP
226 226 self.user_ns = self.IP.user_ns
227 227 self.user_global_ns = self.IP.user_global_ns
228 228
229 229 self.input = ''
230 230 self.output = ''
231 231
232 232 self.is_verbatim = False
233 233 self.is_doctest = False
234 234 self.is_suppress = False
235 235
236 236 # on the first call to the savefig decorator, we'll import
237 237 # pyplot as plt so we can make a call to the plt.gcf().savefig
238 238 self._pyplot_imported = False
239 239
240 240 def clear_cout(self):
241 241 self.cout.seek(0)
242 242 self.cout.truncate(0)
243 243
244 244 def process_input_line(self, line, store_history=True):
245 245 """process the input, capturing stdout"""
246 246 #print "input='%s'"%self.input
247 247 stdout = sys.stdout
248 248 splitter = self.IP.input_splitter
249 249 try:
250 250 sys.stdout = self.cout
251 251 splitter.push(line)
252 252 more = splitter.push_accepts_more()
253 253 if not more:
254 254 source_raw = splitter.source_raw_reset()[1]
255 255 self.IP.run_cell(source_raw, store_history=store_history)
256 256 finally:
257 257 sys.stdout = stdout
258 258
259 259 def process_image(self, decorator):
260 260 """
261 261 # build out an image directive like
262 262 # .. image:: somefile.png
263 263 # :width 4in
264 264 #
265 265 # from an input like
266 266 # savefig somefile.png width=4in
267 267 """
268 268 savefig_dir = self.savefig_dir
269 269 source_dir = self.source_dir
270 270 saveargs = decorator.split(' ')
271 271 filename = saveargs[1]
272 272 # insert relative path to image file in source
273 273 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
274 274 source_dir)
275 275
276 276 imagerows = ['.. image:: %s'%outfile]
277 277
278 278 for kwarg in saveargs[2:]:
279 279 arg, val = kwarg.split('=')
280 280 arg = arg.strip()
281 281 val = val.strip()
282 282 imagerows.append(' :%s: %s'%(arg, val))
283 283
284 284 image_file = os.path.basename(outfile) # only return file name
285 285 image_directive = '\n'.join(imagerows)
286 286 return image_file, image_directive
287 287
288 288
289 289 # Callbacks for each type of token
290 290 def process_input(self, data, input_prompt, lineno):
291 291 """Process data block for INPUT token."""
292 292 decorator, input, rest = data
293 293 image_file = None
294 294 image_directive = None
295 295 #print 'INPUT:', data # dbg
296 296 is_verbatim = decorator=='@verbatim' or self.is_verbatim
297 297 is_doctest = decorator=='@doctest' or self.is_doctest
298 298 is_suppress = decorator=='@suppress' or self.is_suppress
299 299 is_savefig = decorator is not None and \
300 300 decorator.startswith('@savefig')
301 301
302 302 input_lines = input.split('\n')
303 if len(input_lines) > 1:
304 if input_lines[-1] != "":
305 input_lines.append('') # make sure there's a blank line
306 # so splitter buffer gets reset
303 307
304 308 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
305 309 Nc = len(continuation)
306 310
307 311 if is_savefig:
308 312 image_file, image_directive = self.process_image(decorator)
309 313
310 314 ret = []
311 315 is_semicolon = False
312 316 store_history = True
313 317
314 318 for i, line in enumerate(input_lines):
315 319 if line.endswith(';'):
316 320 is_semicolon = True
317 if is_semicolon or is_suppress:
321 if is_suppress:
318 322 store_history = False
319 323
320 324 if i==0:
321 325 # process the first input line
322 326 if is_verbatim:
323 327 self.process_input_line('')
324 328 self.IP.execution_count += 1 # increment it anyway
325 329 else:
326 330 # only submit the line in non-verbatim mode
327 331 self.process_input_line(line, store_history=store_history)
328 332 formatted_line = '%s %s'%(input_prompt, line)
329 333 else:
330 334 # process a continuation line
331 335 if not is_verbatim:
332 336 self.process_input_line(line, store_history=store_history)
333 337
334 338 formatted_line = '%s %s'%(continuation, line)
335 339
336 340 if not is_suppress:
337 341 ret.append(formatted_line)
338 342
339 if not is_suppress:
340 if len(rest.strip()):
341 if is_verbatim:
342 # the "rest" is the standard output of the
343 # input, which needs to be added in
344 # verbatim mode
345 ret.append(rest)
343 if not is_suppress and len(rest.strip()) and is_verbatim:
344 # the "rest" is the standard output of the
345 # input, which needs to be added in
346 # verbatim mode
347 ret.append(rest)
346 348
347 349 self.cout.seek(0)
348 350 output = self.cout.read()
349 351 if not is_suppress and not is_semicolon:
350 352 ret.append(output)
353 elif is_semicolon: # get spacing right
354 ret.append('')
351 355
352 356 self.cout.truncate(0)
353 357 return (ret, input_lines, output, is_doctest, image_file,
354 358 image_directive)
355 359 #print 'OUTPUT', output # dbg
356 360
357 361 def process_output(self, data, output_prompt,
358 362 input_lines, output, is_doctest, image_file):
359 363 """Process data block for OUTPUT token."""
360 364 if is_doctest:
361 365 submitted = data.strip()
362 366 found = output
363 367 if found is not None:
364 368 found = found.strip()
365 369
366 370 # XXX - fperez: in 0.11, 'output' never comes with the prompt
367 371 # in it, just the actual output text. So I think all this code
368 372 # can be nuked...
369 373
370 374 # the above comment does not appear to be accurate... (minrk)
371 375
372 376 ind = found.find(output_prompt)
373 377 if ind<0:
374 378 e='output prompt="%s" does not match out line=%s' % \
375 379 (output_prompt, found)
376 380 raise RuntimeError(e)
377 381 found = found[len(output_prompt):].strip()
378 382
379 383 if found!=submitted:
380 384 e = ('doctest failure for input_lines="%s" with '
381 385 'found_output="%s" and submitted output="%s"' %
382 386 (input_lines, found, submitted) )
383 387 raise RuntimeError(e)
384 388 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
385 389
386 390 def process_comment(self, data):
387 391 """Process data fPblock for COMMENT token."""
388 392 if not self.is_suppress:
389 393 return [data]
390 394
391 395 def save_image(self, image_file):
392 396 """
393 397 Saves the image file to disk.
394 398 """
395 399 self.ensure_pyplot()
396 400 command = 'plt.gcf().savefig("%s")'%image_file
397 401 #print 'SAVEFIG', command # dbg
398 402 self.process_input_line('bookmark ipy_thisdir', store_history=False)
399 403 self.process_input_line('cd -b ipy_savedir', store_history=False)
400 404 self.process_input_line(command, store_history=False)
401 405 self.process_input_line('cd -b ipy_thisdir', store_history=False)
402 406 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
403 407 self.clear_cout()
404 408
405 409
406 410 def process_block(self, block):
407 411 """
408 412 process block from the block_parser and return a list of processed lines
409 413 """
410 414 ret = []
411 415 output = None
412 416 input_lines = None
413 417 lineno = self.IP.execution_count
414 418
415 419 input_prompt = self.promptin%lineno
416 420 output_prompt = self.promptout%lineno
417 421 image_file = None
418 422 image_directive = None
419 423
420 424 for token, data in block:
421 425 if token==COMMENT:
422 426 out_data = self.process_comment(data)
423 427 elif token==INPUT:
424 428 (out_data, input_lines, output, is_doctest, image_file,
425 429 image_directive) = \
426 430 self.process_input(data, input_prompt, lineno)
427 431 elif token==OUTPUT:
428 432 out_data = \
429 433 self.process_output(data, output_prompt,
430 434 input_lines, output, is_doctest,
431 435 image_file)
432 436 if out_data:
433 437 ret.extend(out_data)
434 438
435 439 # save the image files
436 440 if image_file is not None:
437 441 self.save_image(image_file)
438 442
439 443 return ret, image_directive
440 444
441 445 def ensure_pyplot(self):
442 446 if self._pyplot_imported:
443 447 return
444 448 self.process_input_line('import matplotlib.pyplot as plt',
445 449 store_history=False)
446 450
447 451 def process_pure_python(self, content):
448 452 """
449 453 content is a list of strings. it is unedited directive conent
450 454
451 455 This runs it line by line in the InteractiveShell, prepends
452 456 prompts as needed capturing stderr and stdout, then returns
453 457 the content as a list as if it were ipython code
454 458 """
455 459 output = []
456 460 savefig = False # keep up with this to clear figure
457 461 multiline = False # to handle line continuation
458 462 multiline_start = None
459 463 fmtin = self.promptin
460 464
461 465 ct = 0
462 466
463 467 for lineno, line in enumerate(content):
464 468
465 469 line_stripped = line.strip()
466 470 if not len(line):
467 471 output.append(line)
468 472 continue
469 473
470 474 # handle decorators
471 475 if line_stripped.startswith('@'):
472 476 output.extend([line])
473 477 if 'savefig' in line:
474 478 savefig = True # and need to clear figure
475 479 continue
476 480
477 481 # handle comments
478 482 if line_stripped.startswith('#'):
479 483 output.extend([line])
480 484 continue
481 485
482 486 # deal with lines checking for multiline
483 487 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
484 488 if not multiline:
485 489 modified = u"%s %s" % (fmtin % ct, line_stripped)
486 490 output.append(modified)
487 491 ct += 1
488 492 try:
489 493 ast.parse(line_stripped)
490 494 output.append(u'')
491 495 except Exception: # on a multiline
492 496 multiline = True
493 497 multiline_start = lineno
494 498 if line_stripped.startswith('def '):
495 499 is_function = True
496 500 else: # still on a multiline
497 501 modified = u'%s %s' % (continuation, line)
498 502 output.append(modified)
499 503 try:
500 504 mod = ast.parse(
501 505 '\n'.join(content[multiline_start:lineno+1]))
502 506 if isinstance(mod.body[0], ast.FunctionDef):
503 507 # check to see if we have the whole function
504 508 for element in mod.body[0].body:
505 509 if isinstance(element, ast.Return):
506 510 multiline = False
507 511 else:
508 512 output.append(u'')
509 513 multiline = False
510 514 except Exception:
511 515 pass
512 516
513 517 if savefig: # clear figure if plotted
514 518 self.ensure_pyplot()
515 519 self.process_input_line('plt.clf()', store_history=False)
516 520 self.clear_cout()
517 521 savefig = False
518 522
519 523 return output
520 524
521 525 class IpythonDirective(Directive):
522 526
523 527 has_content = True
524 528 required_arguments = 0
525 529 optional_arguments = 4 # python, suppress, verbatim, doctest
526 530 final_argumuent_whitespace = True
527 531 option_spec = { 'python': directives.unchanged,
528 532 'suppress' : directives.flag,
529 533 'verbatim' : directives.flag,
530 534 'doctest' : directives.flag,
531 535 }
532 536
533 537 shell = EmbeddedSphinxShell()
534 538
535 539 def get_config_options(self):
536 540 # contains sphinx configuration variables
537 541 config = self.state.document.settings.env.config
538 542
539 543 # get config variables to set figure output directory
540 544 confdir = self.state.document.settings.env.app.confdir
541 545 savefig_dir = config.ipython_savefig_dir
542 546 source_dir = os.path.dirname(self.state.document.current_source)
543 547 if savefig_dir is None:
544 548 savefig_dir = config.html_static_path
545 549 if isinstance(savefig_dir, list):
546 550 savefig_dir = savefig_dir[0] # safe to assume only one path?
547 551 savefig_dir = os.path.join(confdir, savefig_dir)
548 552
549 553 # get regex and prompt stuff
550 554 rgxin = config.ipython_rgxin
551 555 rgxout = config.ipython_rgxout
552 556 promptin = config.ipython_promptin
553 557 promptout = config.ipython_promptout
554 558
555 559 return savefig_dir, source_dir, rgxin, rgxout, promptin, promptout
556 560
557 561 def setup(self):
558 562 # get config values
559 563 (savefig_dir, source_dir, rgxin,
560 564 rgxout, promptin, promptout) = self.get_config_options()
561 565
562 566 # and attach to shell so we don't have to pass them around
563 567 self.shell.rgxin = rgxin
564 568 self.shell.rgxout = rgxout
565 569 self.shell.promptin = promptin
566 570 self.shell.promptout = promptout
567 571 self.shell.savefig_dir = savefig_dir
568 572 self.shell.source_dir = source_dir
569 573
570 574 # setup bookmark for saving figures directory
571 575
572 576 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
573 577 store_history=False)
574 578 self.shell.clear_cout()
575 579
576 580 return rgxin, rgxout, promptin, promptout
577 581
578 582
579 583 def teardown(self):
580 584 # delete last bookmark
581 585 self.shell.process_input_line('bookmark -d ipy_savedir',
582 586 store_history=False)
583 587 self.shell.clear_cout()
584 588
585 589 def run(self):
586 590 debug = False
587 591
588 592 #TODO, any reason block_parser can't be a method of embeddable shell
589 593 # then we wouldn't have to carry these around
590 594 rgxin, rgxout, promptin, promptout = self.setup()
591 595
592 596 options = self.options
593 597 self.shell.is_suppress = 'suppress' in options
594 598 self.shell.is_doctest = 'doctest' in options
595 599 self.shell.is_verbatim = 'verbatim' in options
596 600
597 601
598 602 # handle pure python code
599 603 if 'python' in self.arguments:
600 604 content = self.content
601 605 self.content = self.shell.process_pure_python(content)
602 606
603 607 parts = '\n'.join(self.content).split('\n\n')
604 608
605 609 lines = ['.. code-block:: ipython','']
606 610 figures = []
607 611
608 612 for part in parts:
609 613
610 614 block = block_parser(part, rgxin, rgxout, promptin, promptout)
611 615
612 616 if len(block):
613 617 rows, figure = self.shell.process_block(block)
614 618 for row in rows:
615 619 lines.extend([' %s'%line for line in row.split('\n')])
616 620
617 621 if figure is not None:
618 622 figures.append(figure)
619 623
620 624 #text = '\n'.join(lines)
621 625 #figs = '\n'.join(figures)
622 626
623 627 for figure in figures:
624 628 lines.append('')
625 629 lines.extend(figure.split('\n'))
626 630 lines.append('')
627 631
628 632 #print lines
629 633 if len(lines)>2:
630 634 if debug:
631 635 print '\n'.join(lines)
632 636 else: #NOTE: this raises some errors, what's it for?
633 637 #print 'INSERTING %d lines'%len(lines)
634 638 self.state_machine.insert_input(
635 639 lines, self.state_machine.input_lines.source(0))
636 640
637 641 text = '\n'.join(lines)
638 642 txtnode = nodes.literal_block(text, text)
639 643 txtnode['language'] = 'ipython'
640 644 #imgnode = nodes.image(figs)
641 645
642 646 # cleanup
643 647 self.teardown()
644 648
645 649 return []#, imgnode]
646 650
647 651 # Enable as a proper Sphinx directive
648 652 def setup(app):
649 653 setup.app = app
650 654
651 655 app.add_directive('ipython', IpythonDirective)
652 656 app.add_config_value('ipython_savefig_dir', None, True)
653 657 app.add_config_value('ipython_rgxin',
654 658 re.compile('In \[(\d+)\]:\s?(.*)\s*'), True)
655 659 app.add_config_value('ipython_rgxout',
656 660 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), True)
657 661 app.add_config_value('ipython_promptin', 'In [%d]:', True)
658 662 app.add_config_value('ipython_promptout', 'Out[%d]:', True)
659 663
660 664
661 665 # Simple smoke test, needs to be converted to a proper automatic test.
662 666 def test():
663 667
664 668 examples = [
665 669 r"""
666 670 In [9]: pwd
667 671 Out[9]: '/home/jdhunter/py4science/book'
668 672
669 673 In [10]: cd bookdata/
670 674 /home/jdhunter/py4science/book/bookdata
671 675
672 676 In [2]: from pylab import *
673 677
674 678 In [2]: ion()
675 679
676 680 In [3]: im = imread('stinkbug.png')
677 681
678 682 @savefig mystinkbug.png width=4in
679 683 In [4]: imshow(im)
680 684 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
681 685
682 686 """,
683 687 r"""
684 688
685 689 In [1]: x = 'hello world'
686 690
687 691 # string methods can be
688 692 # used to alter the string
689 693 @doctest
690 694 In [2]: x.upper()
691 695 Out[2]: 'HELLO WORLD'
692 696
693 697 @verbatim
694 698 In [3]: x.st<TAB>
695 699 x.startswith x.strip
696 700 """,
697 701 r"""
698 702
699 703 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
700 704 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
701 705
702 706 In [131]: print url.split('&')
703 707 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
704 708
705 709 In [60]: import urllib
706 710
707 711 """,
708 712 r"""\
709 713
710 714 In [133]: import numpy.random
711 715
712 716 @suppress
713 717 In [134]: numpy.random.seed(2358)
714 718
715 719 @doctest
716 720 In [135]: numpy.random.rand(10,2)
717 721 Out[135]:
718 722 array([[ 0.64524308, 0.59943846],
719 723 [ 0.47102322, 0.8715456 ],
720 724 [ 0.29370834, 0.74776844],
721 725 [ 0.99539577, 0.1313423 ],
722 726 [ 0.16250302, 0.21103583],
723 727 [ 0.81626524, 0.1312433 ],
724 728 [ 0.67338089, 0.72302393],
725 729 [ 0.7566368 , 0.07033696],
726 730 [ 0.22591016, 0.77731835],
727 731 [ 0.0072729 , 0.34273127]])
728 732
729 733 """,
730 734
731 735 r"""
732 736 In [106]: print x
733 737 jdh
734 738
735 739 In [109]: for i in range(10):
736 740 .....: print i
737 741 .....:
738 742 .....:
739 743 0
740 744 1
741 745 2
742 746 3
743 747 4
744 748 5
745 749 6
746 750 7
747 751 8
748 752 9
749 753 """,
750 754
751 755 r"""
752 756
753 757 In [144]: from pylab import *
754 758
755 759 In [145]: ion()
756 760
757 761 # use a semicolon to suppress the output
758 762 @savefig test_hist.png width=4in
759 763 In [151]: hist(np.random.randn(10000), 100);
760 764
761 765
762 766 @savefig test_plot.png width=4in
763 767 In [151]: plot(np.random.randn(10000), 'o');
764 768 """,
765 769
766 770 r"""
767 771 # use a semicolon to suppress the output
768 772 In [151]: plt.clf()
769 773
770 774 @savefig plot_simple.png width=4in
771 775 In [151]: plot([1,2,3])
772 776
773 777 @savefig hist_simple.png width=4in
774 778 In [151]: hist(np.random.randn(10000), 100);
775 779
776 780 """,
777 781 r"""
778 782 # update the current fig
779 783 In [151]: ylabel('number')
780 784
781 785 In [152]: title('normal distribution')
782 786
783 787
784 788 @savefig hist_with_text.png
785 789 In [153]: grid(True)
786 790
787 791 """,
788 792 ]
789 793 # skip local-file depending first example:
790 794 examples = examples[1:]
791 795
792 796 #ipython_directive.DEBUG = True # dbg
793 797 #options = dict(suppress=True) # dbg
794 798 options = dict()
795 799 for example in examples:
796 800 content = example.split('\n')
797 801 ipython_directive('debug', arguments=None, options=options,
798 802 content=content, lineno=0,
799 803 content_offset=None, block_text=None,
800 804 state=None, state_machine=None,
801 805 )
802 806
803 807 # Run test suite as a script
804 808 if __name__=='__main__':
805 809 if not os.path.isdir('_static'):
806 810 os.mkdir('_static')
807 811 test()
808 812 print 'All OK? Check figures in _static/'
General Comments 0
You need to be logged in to leave comments. Login now