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