##// END OF EJS Templates
Add a more informative error message for IPython directive....
chebee7i -
Show More
@@ -1,1162 +1,1191 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Sphinx directive to support embedded IPython code.
3 Sphinx directive to support embedded IPython code.
4
4
5 This directive allows pasting of entire interactive IPython sessions, prompts
5 This directive allows pasting of entire interactive IPython sessions, prompts
6 and all, and their code will actually get re-executed at doc build time, with
6 and all, and their code will actually get re-executed at doc build time, with
7 all prompts renumbered sequentially. It also allows you to input code as a pure
7 all prompts renumbered sequentially. It also allows you to input code as a pure
8 python input by giving the argument python to the directive. The output looks
8 python input by giving the argument python to the directive. The output looks
9 like an interactive ipython section.
9 like an interactive ipython section.
10
10
11 To enable this directive, simply list it in your Sphinx ``conf.py`` file
11 To enable this directive, simply list it in your Sphinx ``conf.py`` file
12 (making sure the directory where you placed it is visible to sphinx, as is
12 (making sure the directory where you placed it is visible to sphinx, as is
13 needed for all Sphinx directives). For example, to enable syntax highlighting
13 needed for all Sphinx directives). For example, to enable syntax highlighting
14 and the IPython directive::
14 and the IPython directive::
15
15
16 extensions = ['IPython.sphinxext.ipython_console_highlighting',
16 extensions = ['IPython.sphinxext.ipython_console_highlighting',
17 'IPython.sphinxext.ipython_directive']
17 'IPython.sphinxext.ipython_directive']
18
18
19 The IPython directive outputs code-blocks with the language 'ipython'. So
19 The IPython directive outputs code-blocks with the language 'ipython'. So
20 if you do not have the syntax highlighting extension enabled as well, then
20 if you do not have the syntax highlighting extension enabled as well, then
21 all rendered code-blocks will be uncolored. By default this directive assumes
21 all rendered code-blocks will be uncolored. By default this directive assumes
22 that your prompts are unchanged IPython ones, but this can be customized.
22 that your prompts are unchanged IPython ones, but this can be customized.
23 The configurable options that can be placed in conf.py are:
23 The configurable options that can be placed in conf.py are:
24
24
25 ipython_savefig_dir:
25 ipython_savefig_dir:
26 The directory in which to save the figures. This is relative to the
26 The directory in which to save the figures. This is relative to the
27 Sphinx source directory. The default is `html_static_path`.
27 Sphinx source directory. The default is `html_static_path`.
28 ipython_rgxin:
28 ipython_rgxin:
29 The compiled regular expression to denote the start of IPython input
29 The compiled regular expression to denote the start of IPython input
30 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
30 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
31 shouldn't need to change this.
31 shouldn't need to change this.
32 ipython_rgxout:
32 ipython_rgxout:
33 The compiled regular expression to denote the start of IPython output
33 The compiled regular expression to denote the start of IPython output
34 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
34 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
35 shouldn't need to change this.
35 shouldn't need to change this.
36 ipython_promptin:
36 ipython_promptin:
37 The string to represent the IPython input prompt in the generated ReST.
37 The string to represent the IPython input prompt in the generated ReST.
38 The default is 'In [%d]:'. This expects that the line numbers are used
38 The default is 'In [%d]:'. This expects that the line numbers are used
39 in the prompt.
39 in the prompt.
40 ipython_promptout:
40 ipython_promptout:
41 The string to represent the IPython prompt in the generated ReST. The
41 The string to represent the IPython prompt in the generated ReST. The
42 default is 'Out [%d]:'. This expects that the line numbers are used
42 default is 'Out [%d]:'. This expects that the line numbers are used
43 in the prompt.
43 in the prompt.
44 ipython_mplbackend:
44 ipython_mplbackend:
45 The string which specifies if the embedded Sphinx shell should import
45 The string which specifies if the embedded Sphinx shell should import
46 Matplotlib and set the backend. The value specifies a backend that is
46 Matplotlib and set the backend. The value specifies a backend that is
47 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
47 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
48 executed. If not specified in conf.py, then the default value of 'agg' is
48 executed. If not specified in conf.py, then the default value of 'agg' is
49 used. To use the IPython directive without matplotlib as a dependency, set
49 used. To use the IPython directive without matplotlib as a dependency, set
50 the value to `None`. It may end up that matplotlib is still imported
50 the value to `None`. It may end up that matplotlib is still imported
51 if the user specifies so in `ipython_execlines` or makes use of the
51 if the user specifies so in `ipython_execlines` or makes use of the
52 @savefig pseudo decorator.
52 @savefig pseudo decorator.
53 ipython_execlines:
53 ipython_execlines:
54 A list of strings to be exec'd in the embedded Sphinx shell. Typical
54 A list of strings to be exec'd in the embedded Sphinx shell. Typical
55 usage is to make certain packages always available. Set this to an empty
55 usage is to make certain packages always available. Set this to an empty
56 list if you wish to have no imports always available. If specified in
56 list if you wish to have no imports always available. If specified in
57 conf.py as `None`, then it has the effect of making no imports available.
57 conf.py as `None`, then it has the effect of making no imports available.
58 If omitted from conf.py altogether, then the default value of
58 If omitted from conf.py altogether, then the default value of
59 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
59 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
60 ipython_holdcount
60 ipython_holdcount
61 When the @suppress pseudo-decorator is used, the execution count can be
61 When the @suppress pseudo-decorator is used, the execution count can be
62 incremented or not. The default behavior is to hold the execution count,
62 incremented or not. The default behavior is to hold the execution count,
63 corresponding to a value of `True`. Set this to `False` to increment
63 corresponding to a value of `True`. Set this to `False` to increment
64 the execution count after each suppressed command.
64 the execution count after each suppressed command.
65
65
66 As an example, to use the IPython directive when `matplotlib` is not available,
66 As an example, to use the IPython directive when `matplotlib` is not available,
67 one sets the backend to `None`::
67 one sets the backend to `None`::
68
68
69 ipython_mplbackend = None
69 ipython_mplbackend = None
70
70
71 An example usage of the directive is:
71 An example usage of the directive is:
72
72
73 .. code-block:: rst
73 .. code-block:: rst
74
74
75 .. ipython::
75 .. ipython::
76
76
77 In [1]: x = 1
77 In [1]: x = 1
78
78
79 In [2]: y = x**2
79 In [2]: y = x**2
80
80
81 In [3]: print(y)
81 In [3]: print(y)
82
82
83 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
83 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
84 documentation.
84 documentation.
85
85
86 Pseudo-Decorators
86 Pseudo-Decorators
87 =================
87 =================
88
88
89 Note: Only one decorator is supported per input. If more than one decorator
89 Note: Only one decorator is supported per input. If more than one decorator
90 is specified, then only the last one is used.
90 is specified, then only the last one is used.
91
91
92 In addition to the Pseudo-Decorators/options described at the above link,
92 In addition to the Pseudo-Decorators/options described at the above link,
93 several enhancements have been made. The directive will emit a message to the
93 several enhancements have been made. The directive will emit a message to the
94 console at build-time if code-execution resulted in an exception or warning.
94 console at build-time if code-execution resulted in an exception or warning.
95 You can suppress these on a per-block basis by specifying the :okexcept:
95 You can suppress these on a per-block basis by specifying the :okexcept:
96 or :okwarning: options:
96 or :okwarning: options:
97
97
98 .. code-block:: rst
98 .. code-block:: rst
99
99
100 .. ipython::
100 .. ipython::
101 :okexcept:
101 :okexcept:
102 :okwarning:
102 :okwarning:
103
103
104 In [1]: 1/0
104 In [1]: 1/0
105 In [2]: # raise warning.
105 In [2]: # raise warning.
106
106
107 ToDo
107 ToDo
108 ----
108 ----
109
109
110 - Turn the ad-hoc test() function into a real test suite.
110 - Turn the ad-hoc test() function into a real test suite.
111 - Break up ipython-specific functionality from matplotlib stuff into better
111 - Break up ipython-specific functionality from matplotlib stuff into better
112 separated code.
112 separated code.
113
113
114 Authors
114 Authors
115 -------
115 -------
116
116
117 - John D Hunter: orignal author.
117 - John D Hunter: orignal author.
118 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
118 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
119 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
119 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
120 - Skipper Seabold, refactoring, cleanups, pure python addition
120 - Skipper Seabold, refactoring, cleanups, pure python addition
121 """
121 """
122 from __future__ import print_function
122 from __future__ import print_function
123
123
124 #-----------------------------------------------------------------------------
124 #-----------------------------------------------------------------------------
125 # Imports
125 # Imports
126 #-----------------------------------------------------------------------------
126 #-----------------------------------------------------------------------------
127
127
128 # Stdlib
128 # Stdlib
129 import atexit
129 import atexit
130 import os
130 import os
131 import re
131 import re
132 import sys
132 import sys
133 import tempfile
133 import tempfile
134 import ast
134 import ast
135 import warnings
135 import warnings
136 import shutil
136 import shutil
137
137
138 # To keep compatibility with various python versions
138 # To keep compatibility with various python versions
139 try:
139 try:
140 from hashlib import md5
140 from hashlib import md5
141 except ImportError:
141 except ImportError:
142 from md5 import md5
142 from md5 import md5
143
143
144 # Third-party
144 # Third-party
145 import sphinx
145 import sphinx
146 from docutils.parsers.rst import directives
146 from docutils.parsers.rst import directives
147 from docutils import nodes
147 from docutils import nodes
148 from sphinx.util.compat import Directive
148 from sphinx.util.compat import Directive
149
149
150 # Our own
150 # Our own
151 from traitlets.config import Config
151 from traitlets.config import Config
152 from IPython import InteractiveShell
152 from IPython import InteractiveShell
153 from IPython.core.profiledir import ProfileDir
153 from IPython.core.profiledir import ProfileDir
154 from IPython.utils import io
154 from IPython.utils import io
155 from IPython.utils.py3compat import PY3
155 from IPython.utils.py3compat import PY3
156
156
157 if PY3:
157 if PY3:
158 from io import StringIO
158 from io import StringIO
159 else:
159 else:
160 from StringIO import StringIO
160 from StringIO import StringIO
161
161
162 #-----------------------------------------------------------------------------
162 #-----------------------------------------------------------------------------
163 # Globals
163 # Globals
164 #-----------------------------------------------------------------------------
164 #-----------------------------------------------------------------------------
165 # for tokenizing blocks
165 # for tokenizing blocks
166 COMMENT, INPUT, OUTPUT = range(3)
166 COMMENT, INPUT, OUTPUT = range(3)
167
167
168 #-----------------------------------------------------------------------------
168 #-----------------------------------------------------------------------------
169 # Functions and class declarations
169 # Functions and class declarations
170 #-----------------------------------------------------------------------------
170 #-----------------------------------------------------------------------------
171
171
172 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
172 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
173 """
173 """
174 part is a string of ipython text, comprised of at most one
174 part is a string of ipython text, comprised of at most one
175 input, one ouput, comments, and blank lines. The block parser
175 input, one output, comments, and blank lines. The block parser
176 parses the text into a list of::
176 parses the text into a list of::
177
177
178 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
178 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
179
179
180 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
180 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
181 data is, depending on the type of token::
181 data is, depending on the type of token::
182
182
183 COMMENT : the comment string
183 COMMENT : the comment string
184
184
185 INPUT: the (DECORATOR, INPUT_LINE, REST) where
185 INPUT: the (DECORATOR, INPUT_LINE, REST) where
186 DECORATOR: the input decorator (or None)
186 DECORATOR: the input decorator (or None)
187 INPUT_LINE: the input as string (possibly multi-line)
187 INPUT_LINE: the input as string (possibly multi-line)
188 REST : any stdout generated by the input line (not OUTPUT)
188 REST : any stdout generated by the input line (not OUTPUT)
189
189
190 OUTPUT: the output string, possibly multi-line
190 OUTPUT: the output string, possibly multi-line
191
191
192 """
192 """
193 block = []
193 block = []
194 lines = part.split('\n')
194 lines = part.split('\n')
195 N = len(lines)
195 N = len(lines)
196 i = 0
196 i = 0
197 decorator = None
197 decorator = None
198 while 1:
198 while 1:
199
199
200 if i==N:
200 if i==N:
201 # nothing left to parse -- the last line
201 # nothing left to parse -- the last line
202 break
202 break
203
203
204 line = lines[i]
204 line = lines[i]
205 i += 1
205 i += 1
206 line_stripped = line.strip()
206 line_stripped = line.strip()
207 if line_stripped.startswith('#'):
207 if line_stripped.startswith('#'):
208 block.append((COMMENT, line))
208 block.append((COMMENT, line))
209 continue
209 continue
210
210
211 if line_stripped.startswith('@'):
211 if line_stripped.startswith('@'):
212 # Here is where we assume there is, at most, one decorator.
212 # Here is where we assume there is, at most, one decorator.
213 # Might need to rethink this.
213 # Might need to rethink this.
214 decorator = line_stripped
214 decorator = line_stripped
215 continue
215 continue
216
216
217 # does this look like an input line?
217 # does this look like an input line?
218 matchin = rgxin.match(line)
218 matchin = rgxin.match(line)
219 if matchin:
219 if matchin:
220 lineno, inputline = int(matchin.group(1)), matchin.group(2)
220 lineno, inputline = int(matchin.group(1)), matchin.group(2)
221
221
222 # the ....: continuation string
222 # the ....: continuation string
223 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
223 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
224 Nc = len(continuation)
224 Nc = len(continuation)
225 # input lines can continue on for more than one line, if
225 # input lines can continue on for more than one line, if
226 # we have a '\' line continuation char or a function call
226 # we have a '\' line continuation char or a function call
227 # echo line 'print'. The input line can only be
227 # echo line 'print'. The input line can only be
228 # terminated by the end of the block or an output line, so
228 # terminated by the end of the block or an output line, so
229 # we parse out the rest of the input line if it is
229 # we parse out the rest of the input line if it is
230 # multiline as well as any echo text
230 # multiline as well as any echo text
231
231
232 rest = []
232 rest = []
233 while i<N:
233 while i<N:
234
234
235 # look ahead; if the next line is blank, or a comment, or
235 # look ahead; if the next line is blank, or a comment, or
236 # an output line, we're done
236 # an output line, we're done
237
237
238 nextline = lines[i]
238 nextline = lines[i]
239 matchout = rgxout.match(nextline)
239 matchout = rgxout.match(nextline)
240 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
240 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
241 if matchout or nextline.startswith('#'):
241 if matchout or nextline.startswith('#'):
242 break
242 break
243 elif nextline.startswith(continuation):
243 elif nextline.startswith(continuation):
244 # The default ipython_rgx* treat the space following the colon as optional.
244 # The default ipython_rgx* treat the space following the colon as optional.
245 # However, If the space is there we must consume it or code
245 # However, If the space is there we must consume it or code
246 # employing the cython_magic extension will fail to execute.
246 # employing the cython_magic extension will fail to execute.
247 #
247 #
248 # This works with the default ipython_rgx* patterns,
248 # This works with the default ipython_rgx* patterns,
249 # If you modify them, YMMV.
249 # If you modify them, YMMV.
250 nextline = nextline[Nc:]
250 nextline = nextline[Nc:]
251 if nextline and nextline[0] == ' ':
251 if nextline and nextline[0] == ' ':
252 nextline = nextline[1:]
252 nextline = nextline[1:]
253
253
254 inputline += '\n' + nextline
254 inputline += '\n' + nextline
255 else:
255 else:
256 rest.append(nextline)
256 rest.append(nextline)
257 i+= 1
257 i+= 1
258
258
259 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
259 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
260 continue
260 continue
261
261
262 # if it looks like an output line grab all the text to the end
262 # if it looks like an output line grab all the text to the end
263 # of the block
263 # of the block
264 matchout = rgxout.match(line)
264 matchout = rgxout.match(line)
265 if matchout:
265 if matchout:
266 lineno, output = int(matchout.group(1)), matchout.group(2)
266 lineno, output = int(matchout.group(1)), matchout.group(2)
267 if i<N-1:
267 if i<N-1:
268 output = '\n'.join([output] + lines[i:])
268 output = '\n'.join([output] + lines[i:])
269
269
270 block.append((OUTPUT, output))
270 block.append((OUTPUT, output))
271 break
271 break
272
272
273 return block
273 return block
274
274
275
275
276 class EmbeddedSphinxShell(object):
276 class EmbeddedSphinxShell(object):
277 """An embedded IPython instance to run inside Sphinx"""
277 """An embedded IPython instance to run inside Sphinx"""
278
278
279 def __init__(self, exec_lines=None):
279 def __init__(self, exec_lines=None):
280
280
281 self.cout = StringIO()
281 self.cout = StringIO()
282
282
283 if exec_lines is None:
283 if exec_lines is None:
284 exec_lines = []
284 exec_lines = []
285
285
286 # Create config object for IPython
286 # Create config object for IPython
287 config = Config()
287 config = Config()
288 config.InteractiveShell.autocall = False
288 config.InteractiveShell.autocall = False
289 config.InteractiveShell.autoindent = False
289 config.InteractiveShell.autoindent = False
290 config.InteractiveShell.colors = 'NoColor'
290 config.InteractiveShell.colors = 'NoColor'
291
291
292 # create a profile so instance history isn't saved
292 # create a profile so instance history isn't saved
293 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
293 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
294 profname = 'auto_profile_sphinx_build'
294 profname = 'auto_profile_sphinx_build'
295 pdir = os.path.join(tmp_profile_dir,profname)
295 pdir = os.path.join(tmp_profile_dir,profname)
296 profile = ProfileDir.create_profile_dir(pdir)
296 profile = ProfileDir.create_profile_dir(pdir)
297
297
298 # Create and initialize global ipython, but don't start its mainloop.
298 # Create and initialize global ipython, but don't start its mainloop.
299 # This will persist across different EmbededSphinxShell instances.
299 # This will persist across different EmbededSphinxShell instances.
300 atexit.register(self.cleanup)
301 IP = InteractiveShell.instance(config=config, profile_dir=profile)
300 IP = InteractiveShell.instance(config=config, profile_dir=profile)
301 atexit.register(self.cleanup)
302
302
303 # io.stdout redirect must be done after instantiating InteractiveShell
303 # io.stdout redirect must be done after instantiating InteractiveShell
304 io.stdout = self.cout
304 io.stdout = self.cout
305 io.stderr = self.cout
305 io.stderr = self.cout
306
306
307 # For debugging, so we can see normal output, use this:
307 # For debugging, so we can see normal output, use this:
308 #from IPython.utils.io import Tee
308 #from IPython.utils.io import Tee
309 #io.stdout = Tee(self.cout, channel='stdout') # dbg
309 #io.stdout = Tee(self.cout, channel='stdout') # dbg
310 #io.stderr = Tee(self.cout, channel='stderr') # dbg
310 #io.stderr = Tee(self.cout, channel='stderr') # dbg
311
311
312 # Store a few parts of IPython we'll need.
312 # Store a few parts of IPython we'll need.
313 self.IP = IP
313 self.IP = IP
314 self.user_ns = self.IP.user_ns
314 self.user_ns = self.IP.user_ns
315 self.user_global_ns = self.IP.user_global_ns
315 self.user_global_ns = self.IP.user_global_ns
316
316
317 self.input = ''
317 self.input = ''
318 self.output = ''
318 self.output = ''
319 self.tmp_profile_dir = tmp_profile_dir
319 self.tmp_profile_dir = tmp_profile_dir
320
320
321 self.is_verbatim = False
321 self.is_verbatim = False
322 self.is_doctest = False
322 self.is_doctest = False
323 self.is_suppress = False
323 self.is_suppress = False
324
324
325 # Optionally, provide more detailed information to shell.
325 # Optionally, provide more detailed information to shell.
326 # this is assigned by the SetUp method of IPythonDirective
326 # this is assigned by the SetUp method of IPythonDirective
327 # to point at itself.
327 # to point at itself.
328 #
328 #
329 # So, you can access handy things at self.directive.state
329 # So, you can access handy things at self.directive.state
330 self.directive = None
330 self.directive = None
331
331
332 # on the first call to the savefig decorator, we'll import
332 # on the first call to the savefig decorator, we'll import
333 # pyplot as plt so we can make a call to the plt.gcf().savefig
333 # pyplot as plt so we can make a call to the plt.gcf().savefig
334 self._pyplot_imported = False
334 self._pyplot_imported = False
335
335
336 # Prepopulate the namespace.
336 # Prepopulate the namespace.
337 for line in exec_lines:
337 for line in exec_lines:
338 self.process_input_line(line, store_history=False)
338 self.process_input_line(line, store_history=False)
339
339
340 def cleanup(self):
340 def cleanup(self):
341 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
341 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
342
342
343 def clear_cout(self):
343 def clear_cout(self):
344 self.cout.seek(0)
344 self.cout.seek(0)
345 self.cout.truncate(0)
345 self.cout.truncate(0)
346
346
347 def process_input_line(self, line, store_history=True):
347 def process_input_line(self, line, store_history=True):
348 """process the input, capturing stdout"""
348 """process the input, capturing stdout"""
349
349
350 stdout = sys.stdout
350 stdout = sys.stdout
351 splitter = self.IP.input_splitter
351 splitter = self.IP.input_splitter
352 try:
352 try:
353 sys.stdout = self.cout
353 sys.stdout = self.cout
354 splitter.push(line)
354 splitter.push(line)
355 more = splitter.push_accepts_more()
355 more = splitter.push_accepts_more()
356 if not more:
356 if not more:
357 source_raw = splitter.raw_reset()
357 source_raw = splitter.raw_reset()
358 self.IP.run_cell(source_raw, store_history=store_history)
358 self.IP.run_cell(source_raw, store_history=store_history)
359 finally:
359 finally:
360 sys.stdout = stdout
360 sys.stdout = stdout
361
361
362 def process_image(self, decorator):
362 def process_image(self, decorator):
363 """
363 """
364 # build out an image directive like
364 # build out an image directive like
365 # .. image:: somefile.png
365 # .. image:: somefile.png
366 # :width 4in
366 # :width 4in
367 #
367 #
368 # from an input like
368 # from an input like
369 # savefig somefile.png width=4in
369 # savefig somefile.png width=4in
370 """
370 """
371 savefig_dir = self.savefig_dir
371 savefig_dir = self.savefig_dir
372 source_dir = self.source_dir
372 source_dir = self.source_dir
373 saveargs = decorator.split(' ')
373 saveargs = decorator.split(' ')
374 filename = saveargs[1]
374 filename = saveargs[1]
375 # insert relative path to image file in source
375 # insert relative path to image file in source
376 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
376 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
377 source_dir)
377 source_dir)
378
378
379 imagerows = ['.. image:: %s'%outfile]
379 imagerows = ['.. image:: %s'%outfile]
380
380
381 for kwarg in saveargs[2:]:
381 for kwarg in saveargs[2:]:
382 arg, val = kwarg.split('=')
382 arg, val = kwarg.split('=')
383 arg = arg.strip()
383 arg = arg.strip()
384 val = val.strip()
384 val = val.strip()
385 imagerows.append(' :%s: %s'%(arg, val))
385 imagerows.append(' :%s: %s'%(arg, val))
386
386
387 image_file = os.path.basename(outfile) # only return file name
387 image_file = os.path.basename(outfile) # only return file name
388 image_directive = '\n'.join(imagerows)
388 image_directive = '\n'.join(imagerows)
389 return image_file, image_directive
389 return image_file, image_directive
390
390
391 # Callbacks for each type of token
391 # Callbacks for each type of token
392 def process_input(self, data, input_prompt, lineno):
392 def process_input(self, data, input_prompt, lineno):
393 """
393 """
394 Process data block for INPUT token.
394 Process data block for INPUT token.
395
395
396 """
396 """
397 decorator, input, rest = data
397 decorator, input, rest = data
398 image_file = None
398 image_file = None
399 image_directive = None
399 image_directive = None
400
400
401 is_verbatim = decorator=='@verbatim' or self.is_verbatim
401 is_verbatim = decorator=='@verbatim' or self.is_verbatim
402 is_doctest = (decorator is not None and \
402 is_doctest = (decorator is not None and \
403 decorator.startswith('@doctest')) or self.is_doctest
403 decorator.startswith('@doctest')) or self.is_doctest
404 is_suppress = decorator=='@suppress' or self.is_suppress
404 is_suppress = decorator=='@suppress' or self.is_suppress
405 is_okexcept = decorator=='@okexcept' or self.is_okexcept
405 is_okexcept = decorator=='@okexcept' or self.is_okexcept
406 is_okwarning = decorator=='@okwarning' or self.is_okwarning
406 is_okwarning = decorator=='@okwarning' or self.is_okwarning
407 is_savefig = decorator is not None and \
407 is_savefig = decorator is not None and \
408 decorator.startswith('@savefig')
408 decorator.startswith('@savefig')
409
409
410 input_lines = input.split('\n')
410 input_lines = input.split('\n')
411 if len(input_lines) > 1:
411 if len(input_lines) > 1:
412 if input_lines[-1] != "":
412 if input_lines[-1] != "":
413 input_lines.append('') # make sure there's a blank line
413 input_lines.append('') # make sure there's a blank line
414 # so splitter buffer gets reset
414 # so splitter buffer gets reset
415
415
416 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
416 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
417
417
418 if is_savefig:
418 if is_savefig:
419 image_file, image_directive = self.process_image(decorator)
419 image_file, image_directive = self.process_image(decorator)
420
420
421 ret = []
421 ret = []
422 is_semicolon = False
422 is_semicolon = False
423
423
424 # Hold the execution count, if requested to do so.
424 # Hold the execution count, if requested to do so.
425 if is_suppress and self.hold_count:
425 if is_suppress and self.hold_count:
426 store_history = False
426 store_history = False
427 else:
427 else:
428 store_history = True
428 store_history = True
429
429
430 # Note: catch_warnings is not thread safe
430 # Note: catch_warnings is not thread safe
431 with warnings.catch_warnings(record=True) as ws:
431 with warnings.catch_warnings(record=True) as ws:
432 for i, line in enumerate(input_lines):
432 for i, line in enumerate(input_lines):
433 if line.endswith(';'):
433 if line.endswith(';'):
434 is_semicolon = True
434 is_semicolon = True
435
435
436 if i == 0:
436 if i == 0:
437 # process the first input line
437 # process the first input line
438 if is_verbatim:
438 if is_verbatim:
439 self.process_input_line('')
439 self.process_input_line('')
440 self.IP.execution_count += 1 # increment it anyway
440 self.IP.execution_count += 1 # increment it anyway
441 else:
441 else:
442 # only submit the line in non-verbatim mode
442 # only submit the line in non-verbatim mode
443 self.process_input_line(line, store_history=store_history)
443 self.process_input_line(line, store_history=store_history)
444 formatted_line = '%s %s'%(input_prompt, line)
444 formatted_line = '%s %s'%(input_prompt, line)
445 else:
445 else:
446 # process a continuation line
446 # process a continuation line
447 if not is_verbatim:
447 if not is_verbatim:
448 self.process_input_line(line, store_history=store_history)
448 self.process_input_line(line, store_history=store_history)
449
449
450 formatted_line = '%s %s'%(continuation, line)
450 formatted_line = '%s %s'%(continuation, line)
451
451
452 if not is_suppress:
452 if not is_suppress:
453 ret.append(formatted_line)
453 ret.append(formatted_line)
454
454
455 if not is_suppress and len(rest.strip()) and is_verbatim:
455 if not is_suppress and len(rest.strip()) and is_verbatim:
456 # The "rest" is the standard output of the input. This needs to be
456 # The "rest" is the standard output of the input. This needs to be
457 # added when in verbatim mode. If there is no "rest", then we don't
457 # added when in verbatim mode. If there is no "rest", then we don't
458 # add it, as the new line will be added by the processed output.
458 # add it, as the new line will be added by the processed output.
459 ret.append(rest)
459 ret.append(rest)
460
460
461 # Fetch the processed output. (This is not the submitted output.)
461 # Fetch the processed output. (This is not the submitted output.)
462 self.cout.seek(0)
462 self.cout.seek(0)
463 processed_output = self.cout.read()
463 processed_output = self.cout.read()
464 if not is_suppress and not is_semicolon:
464 if not is_suppress and not is_semicolon:
465 #
465 #
466 # In IPythonDirective.run, the elements of `ret` are eventually
466 # In IPythonDirective.run, the elements of `ret` are eventually
467 # combined such that '' entries correspond to newlines. So if
467 # combined such that '' entries correspond to newlines. So if
468 # `processed_output` is equal to '', then the adding it to `ret`
468 # `processed_output` is equal to '', then the adding it to `ret`
469 # ensures that there is a blank line between consecutive inputs
469 # ensures that there is a blank line between consecutive inputs
470 # that have no outputs, as in:
470 # that have no outputs, as in:
471 #
471 #
472 # In [1]: x = 4
472 # In [1]: x = 4
473 #
473 #
474 # In [2]: x = 5
474 # In [2]: x = 5
475 #
475 #
476 # When there is processed output, it has a '\n' at the tail end. So
476 # When there is processed output, it has a '\n' at the tail end. So
477 # adding the output to `ret` will provide the necessary spacing
477 # adding the output to `ret` will provide the necessary spacing
478 # between consecutive input/output blocks, as in:
478 # between consecutive input/output blocks, as in:
479 #
479 #
480 # In [1]: x
480 # In [1]: x
481 # Out[1]: 5
481 # Out[1]: 5
482 #
482 #
483 # In [2]: x
483 # In [2]: x
484 # Out[2]: 5
484 # Out[2]: 5
485 #
485 #
486 # When there is stdout from the input, it also has a '\n' at the
486 # When there is stdout from the input, it also has a '\n' at the
487 # tail end, and so this ensures proper spacing as well. E.g.:
487 # tail end, and so this ensures proper spacing as well. E.g.:
488 #
488 #
489 # In [1]: print x
489 # In [1]: print x
490 # 5
490 # 5
491 #
491 #
492 # In [2]: x = 5
492 # In [2]: x = 5
493 #
493 #
494 # When in verbatim mode, `processed_output` is empty (because
494 # When in verbatim mode, `processed_output` is empty (because
495 # nothing was passed to IP. Sometimes the submitted code block has
495 # nothing was passed to IP. Sometimes the submitted code block has
496 # an Out[] portion and sometimes it does not. When it does not, we
496 # an Out[] portion and sometimes it does not. When it does not, we
497 # need to ensure proper spacing, so we have to add '' to `ret`.
497 # need to ensure proper spacing, so we have to add '' to `ret`.
498 # However, if there is an Out[] in the submitted code, then we do
498 # However, if there is an Out[] in the submitted code, then we do
499 # not want to add a newline as `process_output` has stuff to add.
499 # not want to add a newline as `process_output` has stuff to add.
500 # The difficulty is that `process_input` doesn't know if
500 # The difficulty is that `process_input` doesn't know if
501 # `process_output` will be called---so it doesn't know if there is
501 # `process_output` will be called---so it doesn't know if there is
502 # Out[] in the code block. The requires that we include a hack in
502 # Out[] in the code block. The requires that we include a hack in
503 # `process_block`. See the comments there.
503 # `process_block`. See the comments there.
504 #
504 #
505 ret.append(processed_output)
505 ret.append(processed_output)
506 elif is_semicolon:
506 elif is_semicolon:
507 # Make sure there is a newline after the semicolon.
507 # Make sure there is a newline after the semicolon.
508 ret.append('')
508 ret.append('')
509
509
510 # context information
510 # context information
511 filename = "Unknown"
511 filename = "Unknown"
512 lineno = 0
512 lineno = 0
513 if self.directive.state:
513 if self.directive.state:
514 filename = self.directive.state.document.current_source
514 filename = self.directive.state.document.current_source
515 lineno = self.directive.state.document.current_line
515 lineno = self.directive.state.document.current_line
516
516
517 # output any exceptions raised during execution to stdout
517 # output any exceptions raised during execution to stdout
518 # unless :okexcept: has been specified.
518 # unless :okexcept: has been specified.
519 if not is_okexcept and "Traceback" in processed_output:
519 if not is_okexcept and "Traceback" in processed_output:
520 s = "\nException in %s at block ending on line %s\n" % (filename, lineno)
520 s = "\nException in %s at block ending on line %s\n" % (filename, lineno)
521 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
521 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
522 sys.stdout.write('\n\n>>>' + ('-' * 73))
522 sys.stdout.write('\n\n>>>' + ('-' * 73))
523 sys.stdout.write(s)
523 sys.stdout.write(s)
524 sys.stdout.write(processed_output)
524 sys.stdout.write(processed_output)
525 sys.stdout.write('<<<' + ('-' * 73) + '\n\n')
525 sys.stdout.write('<<<' + ('-' * 73) + '\n\n')
526
526
527 # output any warning raised during execution to stdout
527 # output any warning raised during execution to stdout
528 # unless :okwarning: has been specified.
528 # unless :okwarning: has been specified.
529 if not is_okwarning:
529 if not is_okwarning:
530 for w in ws:
530 for w in ws:
531 s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno)
531 s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno)
532 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
532 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
533 sys.stdout.write('\n\n>>>' + ('-' * 73))
533 sys.stdout.write('\n\n>>>' + ('-' * 73))
534 sys.stdout.write(s)
534 sys.stdout.write(s)
535 sys.stdout.write(('-' * 76) + '\n')
535 sys.stdout.write(('-' * 76) + '\n')
536 s=warnings.formatwarning(w.message, w.category,
536 s=warnings.formatwarning(w.message, w.category,
537 w.filename, w.lineno, w.line)
537 w.filename, w.lineno, w.line)
538 sys.stdout.write(s)
538 sys.stdout.write(s)
539 sys.stdout.write('<<<' + ('-' * 73) + '\n')
539 sys.stdout.write('<<<' + ('-' * 73) + '\n')
540
540
541 self.cout.truncate(0)
541 self.cout.truncate(0)
542
542
543 return (ret, input_lines, processed_output,
543 return (ret, input_lines, processed_output,
544 is_doctest, decorator, image_file, image_directive)
544 is_doctest, decorator, image_file, image_directive)
545
545
546
546
547 def process_output(self, data, output_prompt, input_lines, output,
547 def process_output(self, data, output_prompt, input_lines, output,
548 is_doctest, decorator, image_file):
548 is_doctest, decorator, image_file):
549 """
549 """
550 Process data block for OUTPUT token.
550 Process data block for OUTPUT token.
551
551
552 """
552 """
553 # Recall: `data` is the submitted output, and `output` is the processed
553 # Recall: `data` is the submitted output, and `output` is the processed
554 # output from `input_lines`.
554 # output from `input_lines`.
555
555
556 TAB = ' ' * 4
556 TAB = ' ' * 4
557
557
558 if is_doctest and output is not None:
558 if is_doctest and output is not None:
559
559
560 found = output # This is the processed output
560 found = output # This is the processed output
561 found = found.strip()
561 found = found.strip()
562 submitted = data.strip()
562 submitted = data.strip()
563
563
564 if self.directive is None:
564 if self.directive is None:
565 source = 'Unavailable'
565 source = 'Unavailable'
566 content = 'Unavailable'
566 content = 'Unavailable'
567 else:
567 else:
568 source = self.directive.state.document.current_source
568 source = self.directive.state.document.current_source
569 content = self.directive.content
569 content = self.directive.content
570 # Add tabs and join into a single string.
570 # Add tabs and join into a single string.
571 content = '\n'.join([TAB + line for line in content])
571 content = '\n'.join([TAB + line for line in content])
572
572
573 # Make sure the output contains the output prompt.
573 # Make sure the output contains the output prompt.
574 ind = found.find(output_prompt)
574 ind = found.find(output_prompt)
575 if ind < 0:
575 if ind < 0:
576 e = ('output does not contain output prompt\n\n'
576 e = ('output does not contain output prompt\n\n'
577 'Document source: {0}\n\n'
577 'Document source: {0}\n\n'
578 'Raw content: \n{1}\n\n'
578 'Raw content: \n{1}\n\n'
579 'Input line(s):\n{TAB}{2}\n\n'
579 'Input line(s):\n{TAB}{2}\n\n'
580 'Output line(s):\n{TAB}{3}\n\n')
580 'Output line(s):\n{TAB}{3}\n\n')
581 e = e.format(source, content, '\n'.join(input_lines),
581 e = e.format(source, content, '\n'.join(input_lines),
582 repr(found), TAB=TAB)
582 repr(found), TAB=TAB)
583 raise RuntimeError(e)
583 raise RuntimeError(e)
584 found = found[len(output_prompt):].strip()
584 found = found[len(output_prompt):].strip()
585
585
586 # Handle the actual doctest comparison.
586 # Handle the actual doctest comparison.
587 if decorator.strip() == '@doctest':
587 if decorator.strip() == '@doctest':
588 # Standard doctest
588 # Standard doctest
589 if found != submitted:
589 if found != submitted:
590 e = ('doctest failure\n\n'
590 e = ('doctest failure\n\n'
591 'Document source: {0}\n\n'
591 'Document source: {0}\n\n'
592 'Raw content: \n{1}\n\n'
592 'Raw content: \n{1}\n\n'
593 'On input line(s):\n{TAB}{2}\n\n'
593 'On input line(s):\n{TAB}{2}\n\n'
594 'we found output:\n{TAB}{3}\n\n'
594 'we found output:\n{TAB}{3}\n\n'
595 'instead of the expected:\n{TAB}{4}\n\n')
595 'instead of the expected:\n{TAB}{4}\n\n')
596 e = e.format(source, content, '\n'.join(input_lines),
596 e = e.format(source, content, '\n'.join(input_lines),
597 repr(found), repr(submitted), TAB=TAB)
597 repr(found), repr(submitted), TAB=TAB)
598 raise RuntimeError(e)
598 raise RuntimeError(e)
599 else:
599 else:
600 self.custom_doctest(decorator, input_lines, found, submitted)
600 self.custom_doctest(decorator, input_lines, found, submitted)
601
601
602 # When in verbatim mode, this holds additional submitted output
602 # When in verbatim mode, this holds additional submitted output
603 # to be written in the final Sphinx output.
603 # to be written in the final Sphinx output.
604 # https://github.com/ipython/ipython/issues/5776
604 # https://github.com/ipython/ipython/issues/5776
605 out_data = []
605 out_data = []
606
606
607 is_verbatim = decorator=='@verbatim' or self.is_verbatim
607 is_verbatim = decorator=='@verbatim' or self.is_verbatim
608 if is_verbatim and data.strip():
608 if is_verbatim and data.strip():
609 # Note that `ret` in `process_block` has '' as its last element if
609 # Note that `ret` in `process_block` has '' as its last element if
610 # the code block was in verbatim mode. So if there is no submitted
610 # the code block was in verbatim mode. So if there is no submitted
611 # output, then we will have proper spacing only if we do not add
611 # output, then we will have proper spacing only if we do not add
612 # an additional '' to `out_data`. This is why we condition on
612 # an additional '' to `out_data`. This is why we condition on
613 # `and data.strip()`.
613 # `and data.strip()`.
614
614
615 # The submitted output has no output prompt. If we want the
615 # The submitted output has no output prompt. If we want the
616 # prompt and the code to appear, we need to join them now
616 # prompt and the code to appear, we need to join them now
617 # instead of adding them separately---as this would create an
617 # instead of adding them separately---as this would create an
618 # undesired newline. How we do this ultimately depends on the
618 # undesired newline. How we do this ultimately depends on the
619 # format of the output regex. I'll do what works for the default
619 # format of the output regex. I'll do what works for the default
620 # prompt for now, and we might have to adjust if it doesn't work
620 # prompt for now, and we might have to adjust if it doesn't work
621 # in other cases. Finally, the submitted output does not have
621 # in other cases. Finally, the submitted output does not have
622 # a trailing newline, so we must add it manually.
622 # a trailing newline, so we must add it manually.
623 out_data.append("{0} {1}\n".format(output_prompt, data))
623 out_data.append("{0} {1}\n".format(output_prompt, data))
624
624
625 return out_data
625 return out_data
626
626
627 def process_comment(self, data):
627 def process_comment(self, data):
628 """Process data fPblock for COMMENT token."""
628 """Process data fPblock for COMMENT token."""
629 if not self.is_suppress:
629 if not self.is_suppress:
630 return [data]
630 return [data]
631
631
632 def save_image(self, image_file):
632 def save_image(self, image_file):
633 """
633 """
634 Saves the image file to disk.
634 Saves the image file to disk.
635 """
635 """
636 self.ensure_pyplot()
636 self.ensure_pyplot()
637 command = 'plt.gcf().savefig("%s")'%image_file
637 command = 'plt.gcf().savefig("%s")'%image_file
638 #print 'SAVEFIG', command # dbg
638 #print 'SAVEFIG', command # dbg
639 self.process_input_line('bookmark ipy_thisdir', store_history=False)
639 self.process_input_line('bookmark ipy_thisdir', store_history=False)
640 self.process_input_line('cd -b ipy_savedir', store_history=False)
640 self.process_input_line('cd -b ipy_savedir', store_history=False)
641 self.process_input_line(command, store_history=False)
641 self.process_input_line(command, store_history=False)
642 self.process_input_line('cd -b ipy_thisdir', store_history=False)
642 self.process_input_line('cd -b ipy_thisdir', store_history=False)
643 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
643 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
644 self.clear_cout()
644 self.clear_cout()
645
645
646 def process_block(self, block):
646 def process_block(self, block):
647 """
647 """
648 process block from the block_parser and return a list of processed lines
648 process block from the block_parser and return a list of processed lines
649 """
649 """
650 ret = []
650 ret = []
651 output = None
651 output = None
652 input_lines = None
652 input_lines = None
653 lineno = self.IP.execution_count
653 lineno = self.IP.execution_count
654
654
655 input_prompt = self.promptin % lineno
655 input_prompt = self.promptin % lineno
656 output_prompt = self.promptout % lineno
656 output_prompt = self.promptout % lineno
657 image_file = None
657 image_file = None
658 image_directive = None
658 image_directive = None
659
659
660 found_input = False
660 for token, data in block:
661 for token, data in block:
661 if token == COMMENT:
662 if token == COMMENT:
662 out_data = self.process_comment(data)
663 out_data = self.process_comment(data)
663 elif token == INPUT:
664 elif token == INPUT:
665 found_input = True
664 (out_data, input_lines, output, is_doctest,
666 (out_data, input_lines, output, is_doctest,
665 decorator, image_file, image_directive) = \
667 decorator, image_file, image_directive) = \
666 self.process_input(data, input_prompt, lineno)
668 self.process_input(data, input_prompt, lineno)
667 elif token == OUTPUT:
669 elif token == OUTPUT:
670 if not found_input:
671
672 TAB = ' ' * 4
673 linenumber = 0
674 source = 'Unavailable'
675 content = 'Unavailable'
676 if self.directive:
677 linenumber = self.directive.state.document.current_line
678 source = self.directive.state.document.current_source
679 content = self.directive.content
680 # Add tabs and join into a single string.
681 content = '\n'.join([TAB + line for line in content])
682
683 e = ('\n\nInvalid block: Block contains an output prompt '
684 'without an input prompt.\n\n'
685 'Document source: {0}\n\n'
686 'Content begins at line {1}: \n\n{2}\n\n'
687 'Problematic block within content: \n\n{TAB}{3}\n\n')
688 e = e.format(source, linenumber, content, block, TAB=TAB)
689
690 # Write, rather than include in exception, since Sphinx
691 # will truncate tracebacks.
692 sys.stdout.write(e)
693 raise RuntimeError('An invalid block was detected.')
694
668 out_data = \
695 out_data = \
669 self.process_output(data, output_prompt, input_lines,
696 self.process_output(data, output_prompt, input_lines,
670 output, is_doctest, decorator,
697 output, is_doctest, decorator,
671 image_file)
698 image_file)
672 if out_data:
699 if out_data:
673 # Then there was user submitted output in verbatim mode.
700 # Then there was user submitted output in verbatim mode.
674 # We need to remove the last element of `ret` that was
701 # We need to remove the last element of `ret` that was
675 # added in `process_input`, as it is '' and would introduce
702 # added in `process_input`, as it is '' and would introduce
676 # an undesirable newline.
703 # an undesirable newline.
677 assert(ret[-1] == '')
704 assert(ret[-1] == '')
678 del ret[-1]
705 del ret[-1]
679
706
680 if out_data:
707 if out_data:
681 ret.extend(out_data)
708 ret.extend(out_data)
682
709
683 # save the image files
710 # save the image files
684 if image_file is not None:
711 if image_file is not None:
685 self.save_image(image_file)
712 self.save_image(image_file)
686
713
687 return ret, image_directive
714 return ret, image_directive
688
715
689 def ensure_pyplot(self):
716 def ensure_pyplot(self):
690 """
717 """
691 Ensures that pyplot has been imported into the embedded IPython shell.
718 Ensures that pyplot has been imported into the embedded IPython shell.
692
719
693 Also, makes sure to set the backend appropriately if not set already.
720 Also, makes sure to set the backend appropriately if not set already.
694
721
695 """
722 """
696 # We are here if the @figure pseudo decorator was used. Thus, it's
723 # We are here if the @figure pseudo decorator was used. Thus, it's
697 # possible that we could be here even if python_mplbackend were set to
724 # possible that we could be here even if python_mplbackend were set to
698 # `None`. That's also strange and perhaps worthy of raising an
725 # `None`. That's also strange and perhaps worthy of raising an
699 # exception, but for now, we just set the backend to 'agg'.
726 # exception, but for now, we just set the backend to 'agg'.
700
727
701 if not self._pyplot_imported:
728 if not self._pyplot_imported:
702 if 'matplotlib.backends' not in sys.modules:
729 if 'matplotlib.backends' not in sys.modules:
703 # Then ipython_matplotlib was set to None but there was a
730 # Then ipython_matplotlib was set to None but there was a
704 # call to the @figure decorator (and ipython_execlines did
731 # call to the @figure decorator (and ipython_execlines did
705 # not set a backend).
732 # not set a backend).
706 #raise Exception("No backend was set, but @figure was used!")
733 #raise Exception("No backend was set, but @figure was used!")
707 import matplotlib
734 import matplotlib
708 matplotlib.use('agg')
735 matplotlib.use('agg')
709
736
710 # Always import pyplot into embedded shell.
737 # Always import pyplot into embedded shell.
711 self.process_input_line('import matplotlib.pyplot as plt',
738 self.process_input_line('import matplotlib.pyplot as plt',
712 store_history=False)
739 store_history=False)
713 self._pyplot_imported = True
740 self._pyplot_imported = True
714
741
715 def process_pure_python(self, content):
742 def process_pure_python(self, content):
716 """
743 """
717 content is a list of strings. it is unedited directive content
744 content is a list of strings. it is unedited directive content
718
745
719 This runs it line by line in the InteractiveShell, prepends
746 This runs it line by line in the InteractiveShell, prepends
720 prompts as needed capturing stderr and stdout, then returns
747 prompts as needed capturing stderr and stdout, then returns
721 the content as a list as if it were ipython code
748 the content as a list as if it were ipython code
722 """
749 """
723 output = []
750 output = []
724 savefig = False # keep up with this to clear figure
751 savefig = False # keep up with this to clear figure
725 multiline = False # to handle line continuation
752 multiline = False # to handle line continuation
726 multiline_start = None
753 multiline_start = None
727 fmtin = self.promptin
754 fmtin = self.promptin
728
755
729 ct = 0
756 ct = 0
730
757
731 for lineno, line in enumerate(content):
758 for lineno, line in enumerate(content):
732
759
733 line_stripped = line.strip()
760 line_stripped = line.strip()
734 if not len(line):
761 if not len(line):
735 output.append(line)
762 output.append(line)
736 continue
763 continue
737
764
738 # handle decorators
765 # handle decorators
739 if line_stripped.startswith('@'):
766 if line_stripped.startswith('@'):
740 output.extend([line])
767 output.extend([line])
741 if 'savefig' in line:
768 if 'savefig' in line:
742 savefig = True # and need to clear figure
769 savefig = True # and need to clear figure
743 continue
770 continue
744
771
745 # handle comments
772 # handle comments
746 if line_stripped.startswith('#'):
773 if line_stripped.startswith('#'):
747 output.extend([line])
774 output.extend([line])
748 continue
775 continue
749
776
750 # deal with lines checking for multiline
777 # deal with lines checking for multiline
751 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
778 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
752 if not multiline:
779 if not multiline:
753 modified = u"%s %s" % (fmtin % ct, line_stripped)
780 modified = u"%s %s" % (fmtin % ct, line_stripped)
754 output.append(modified)
781 output.append(modified)
755 ct += 1
782 ct += 1
756 try:
783 try:
757 ast.parse(line_stripped)
784 ast.parse(line_stripped)
758 output.append(u'')
785 output.append(u'')
759 except Exception: # on a multiline
786 except Exception: # on a multiline
760 multiline = True
787 multiline = True
761 multiline_start = lineno
788 multiline_start = lineno
762 else: # still on a multiline
789 else: # still on a multiline
763 modified = u'%s %s' % (continuation, line)
790 modified = u'%s %s' % (continuation, line)
764 output.append(modified)
791 output.append(modified)
765
792
766 # if the next line is indented, it should be part of multiline
793 # if the next line is indented, it should be part of multiline
767 if len(content) > lineno + 1:
794 if len(content) > lineno + 1:
768 nextline = content[lineno + 1]
795 nextline = content[lineno + 1]
769 if len(nextline) - len(nextline.lstrip()) > 3:
796 if len(nextline) - len(nextline.lstrip()) > 3:
770 continue
797 continue
771 try:
798 try:
772 mod = ast.parse(
799 mod = ast.parse(
773 '\n'.join(content[multiline_start:lineno+1]))
800 '\n'.join(content[multiline_start:lineno+1]))
774 if isinstance(mod.body[0], ast.FunctionDef):
801 if isinstance(mod.body[0], ast.FunctionDef):
775 # check to see if we have the whole function
802 # check to see if we have the whole function
776 for element in mod.body[0].body:
803 for element in mod.body[0].body:
777 if isinstance(element, ast.Return):
804 if isinstance(element, ast.Return):
778 multiline = False
805 multiline = False
779 else:
806 else:
780 output.append(u'')
807 output.append(u'')
781 multiline = False
808 multiline = False
782 except Exception:
809 except Exception:
783 pass
810 pass
784
811
785 if savefig: # clear figure if plotted
812 if savefig: # clear figure if plotted
786 self.ensure_pyplot()
813 self.ensure_pyplot()
787 self.process_input_line('plt.clf()', store_history=False)
814 self.process_input_line('plt.clf()', store_history=False)
788 self.clear_cout()
815 self.clear_cout()
789 savefig = False
816 savefig = False
790
817
791 return output
818 return output
792
819
793 def custom_doctest(self, decorator, input_lines, found, submitted):
820 def custom_doctest(self, decorator, input_lines, found, submitted):
794 """
821 """
795 Perform a specialized doctest.
822 Perform a specialized doctest.
796
823
797 """
824 """
798 from .custom_doctests import doctests
825 from .custom_doctests import doctests
799
826
800 args = decorator.split()
827 args = decorator.split()
801 doctest_type = args[1]
828 doctest_type = args[1]
802 if doctest_type in doctests:
829 if doctest_type in doctests:
803 doctests[doctest_type](self, args, input_lines, found, submitted)
830 doctests[doctest_type](self, args, input_lines, found, submitted)
804 else:
831 else:
805 e = "Invalid option to @doctest: {0}".format(doctest_type)
832 e = "Invalid option to @doctest: {0}".format(doctest_type)
806 raise Exception(e)
833 raise Exception(e)
807
834
808
835
809 class IPythonDirective(Directive):
836 class IPythonDirective(Directive):
810
837
811 has_content = True
838 has_content = True
812 required_arguments = 0
839 required_arguments = 0
813 optional_arguments = 4 # python, suppress, verbatim, doctest
840 optional_arguments = 4 # python, suppress, verbatim, doctest
814 final_argumuent_whitespace = True
841 final_argumuent_whitespace = True
815 option_spec = { 'python': directives.unchanged,
842 option_spec = { 'python': directives.unchanged,
816 'suppress' : directives.flag,
843 'suppress' : directives.flag,
817 'verbatim' : directives.flag,
844 'verbatim' : directives.flag,
818 'doctest' : directives.flag,
845 'doctest' : directives.flag,
819 'okexcept': directives.flag,
846 'okexcept': directives.flag,
820 'okwarning': directives.flag
847 'okwarning': directives.flag
821 }
848 }
822
849
823 shell = None
850 shell = None
824
851
825 seen_docs = set()
852 seen_docs = set()
826
853
827 def get_config_options(self):
854 def get_config_options(self):
828 # contains sphinx configuration variables
855 # contains sphinx configuration variables
829 config = self.state.document.settings.env.config
856 config = self.state.document.settings.env.config
830
857
831 # get config variables to set figure output directory
858 # get config variables to set figure output directory
832 confdir = self.state.document.settings.env.app.confdir
859 confdir = self.state.document.settings.env.app.confdir
833 savefig_dir = config.ipython_savefig_dir
860 savefig_dir = config.ipython_savefig_dir
834 source_dir = os.path.dirname(self.state.document.current_source)
861 source_dir = os.path.dirname(self.state.document.current_source)
835 if savefig_dir is None:
862 if savefig_dir is None:
836 savefig_dir = config.html_static_path
863 savefig_dir = config.html_static_path
837 if isinstance(savefig_dir, list):
864 if isinstance(savefig_dir, list):
838 savefig_dir = savefig_dir[0] # safe to assume only one path?
865 savefig_dir = savefig_dir[0] # safe to assume only one path?
839 savefig_dir = os.path.join(confdir, savefig_dir)
866 savefig_dir = os.path.join(confdir, savefig_dir)
840
867
841 # get regex and prompt stuff
868 # get regex and prompt stuff
842 rgxin = config.ipython_rgxin
869 rgxin = config.ipython_rgxin
843 rgxout = config.ipython_rgxout
870 rgxout = config.ipython_rgxout
844 promptin = config.ipython_promptin
871 promptin = config.ipython_promptin
845 promptout = config.ipython_promptout
872 promptout = config.ipython_promptout
846 mplbackend = config.ipython_mplbackend
873 mplbackend = config.ipython_mplbackend
847 exec_lines = config.ipython_execlines
874 exec_lines = config.ipython_execlines
848 hold_count = config.ipython_holdcount
875 hold_count = config.ipython_holdcount
849
876
850 return (savefig_dir, source_dir, rgxin, rgxout,
877 return (savefig_dir, source_dir, rgxin, rgxout,
851 promptin, promptout, mplbackend, exec_lines, hold_count)
878 promptin, promptout, mplbackend, exec_lines, hold_count)
852
879
853 def setup(self):
880 def setup(self):
854 # Get configuration values.
881 # Get configuration values.
855 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
882 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
856 mplbackend, exec_lines, hold_count) = self.get_config_options()
883 mplbackend, exec_lines, hold_count) = self.get_config_options()
857
884
858 if self.shell is None:
885 if self.shell is None:
859 # We will be here many times. However, when the
886 # We will be here many times. However, when the
860 # EmbeddedSphinxShell is created, its interactive shell member
887 # EmbeddedSphinxShell is created, its interactive shell member
861 # is the same for each instance.
888 # is the same for each instance.
862
889
863 if mplbackend:
890 if mplbackend:
864 import matplotlib
891 import matplotlib
865 # Repeated calls to use() will not hurt us since `mplbackend`
892 # Repeated calls to use() will not hurt us since `mplbackend`
866 # is the same each time.
893 # is the same each time.
867 matplotlib.use(mplbackend)
894 matplotlib.use(mplbackend)
868
895
869 # Must be called after (potentially) importing matplotlib and
896 # Must be called after (potentially) importing matplotlib and
870 # setting its backend since exec_lines might import pylab.
897 # setting its backend since exec_lines might import pylab.
871 self.shell = EmbeddedSphinxShell(exec_lines)
898 self.shell = EmbeddedSphinxShell(exec_lines)
872
899
873 # Store IPython directive to enable better error messages
900 # Store IPython directive to enable better error messages
874 self.shell.directive = self
901 self.shell.directive = self
875
902
876 # reset the execution count if we haven't processed this doc
903 # reset the execution count if we haven't processed this doc
877 #NOTE: this may be borked if there are multiple seen_doc tmp files
904 #NOTE: this may be borked if there are multiple seen_doc tmp files
878 #check time stamp?
905 #check time stamp?
879 if not self.state.document.current_source in self.seen_docs:
906 if not self.state.document.current_source in self.seen_docs:
880 self.shell.IP.history_manager.reset()
907 self.shell.IP.history_manager.reset()
881 self.shell.IP.execution_count = 1
908 self.shell.IP.execution_count = 1
882 self.shell.IP.prompt_manager.width = 0
909 self.shell.IP.prompt_manager.width = 0
883 self.seen_docs.add(self.state.document.current_source)
910 self.seen_docs.add(self.state.document.current_source)
884
911
885 # and attach to shell so we don't have to pass them around
912 # and attach to shell so we don't have to pass them around
886 self.shell.rgxin = rgxin
913 self.shell.rgxin = rgxin
887 self.shell.rgxout = rgxout
914 self.shell.rgxout = rgxout
888 self.shell.promptin = promptin
915 self.shell.promptin = promptin
889 self.shell.promptout = promptout
916 self.shell.promptout = promptout
890 self.shell.savefig_dir = savefig_dir
917 self.shell.savefig_dir = savefig_dir
891 self.shell.source_dir = source_dir
918 self.shell.source_dir = source_dir
892 self.shell.hold_count = hold_count
919 self.shell.hold_count = hold_count
893
920
894 # setup bookmark for saving figures directory
921 # setup bookmark for saving figures directory
895 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
922 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
896 store_history=False)
923 store_history=False)
897 self.shell.clear_cout()
924 self.shell.clear_cout()
898
925
899 return rgxin, rgxout, promptin, promptout
926 return rgxin, rgxout, promptin, promptout
900
927
901 def teardown(self):
928 def teardown(self):
902 # delete last bookmark
929 # delete last bookmark
903 self.shell.process_input_line('bookmark -d ipy_savedir',
930 self.shell.process_input_line('bookmark -d ipy_savedir',
904 store_history=False)
931 store_history=False)
905 self.shell.clear_cout()
932 self.shell.clear_cout()
906
933
907 def run(self):
934 def run(self):
908 debug = False
935 debug = False
909
936
910 #TODO, any reason block_parser can't be a method of embeddable shell
937 #TODO, any reason block_parser can't be a method of embeddable shell
911 # then we wouldn't have to carry these around
938 # then we wouldn't have to carry these around
912 rgxin, rgxout, promptin, promptout = self.setup()
939 rgxin, rgxout, promptin, promptout = self.setup()
913
940
914 options = self.options
941 options = self.options
915 self.shell.is_suppress = 'suppress' in options
942 self.shell.is_suppress = 'suppress' in options
916 self.shell.is_doctest = 'doctest' in options
943 self.shell.is_doctest = 'doctest' in options
917 self.shell.is_verbatim = 'verbatim' in options
944 self.shell.is_verbatim = 'verbatim' in options
918 self.shell.is_okexcept = 'okexcept' in options
945 self.shell.is_okexcept = 'okexcept' in options
919 self.shell.is_okwarning = 'okwarning' in options
946 self.shell.is_okwarning = 'okwarning' in options
920
947
921 # handle pure python code
948 # handle pure python code
922 if 'python' in self.arguments:
949 if 'python' in self.arguments:
923 content = self.content
950 content = self.content
924 self.content = self.shell.process_pure_python(content)
951 self.content = self.shell.process_pure_python(content)
925
952
953 # parts consists of all text within the ipython-block.
954 # Each part is an input/output block.
926 parts = '\n'.join(self.content).split('\n\n')
955 parts = '\n'.join(self.content).split('\n\n')
927
956
928 lines = ['.. code-block:: ipython', '']
957 lines = ['.. code-block:: ipython', '']
929 figures = []
958 figures = []
930
959
931 for part in parts:
960 for part in parts:
932 block = block_parser(part, rgxin, rgxout, promptin, promptout)
961 block = block_parser(part, rgxin, rgxout, promptin, promptout)
933 if len(block):
962 if len(block):
934 rows, figure = self.shell.process_block(block)
963 rows, figure = self.shell.process_block(block)
935 for row in rows:
964 for row in rows:
936 lines.extend([' {0}'.format(line)
965 lines.extend([' {0}'.format(line)
937 for line in row.split('\n')])
966 for line in row.split('\n')])
938
967
939 if figure is not None:
968 if figure is not None:
940 figures.append(figure)
969 figures.append(figure)
941
970
942 for figure in figures:
971 for figure in figures:
943 lines.append('')
972 lines.append('')
944 lines.extend(figure.split('\n'))
973 lines.extend(figure.split('\n'))
945 lines.append('')
974 lines.append('')
946
975
947 if len(lines) > 2:
976 if len(lines) > 2:
948 if debug:
977 if debug:
949 print('\n'.join(lines))
978 print('\n'.join(lines))
950 else:
979 else:
951 # This has to do with input, not output. But if we comment
980 # This has to do with input, not output. But if we comment
952 # these lines out, then no IPython code will appear in the
981 # these lines out, then no IPython code will appear in the
953 # final output.
982 # final output.
954 self.state_machine.insert_input(
983 self.state_machine.insert_input(
955 lines, self.state_machine.input_lines.source(0))
984 lines, self.state_machine.input_lines.source(0))
956
985
957 # cleanup
986 # cleanup
958 self.teardown()
987 self.teardown()
959
988
960 return []
989 return []
961
990
962 # Enable as a proper Sphinx directive
991 # Enable as a proper Sphinx directive
963 def setup(app):
992 def setup(app):
964 setup.app = app
993 setup.app = app
965
994
966 app.add_directive('ipython', IPythonDirective)
995 app.add_directive('ipython', IPythonDirective)
967 app.add_config_value('ipython_savefig_dir', None, 'env')
996 app.add_config_value('ipython_savefig_dir', None, 'env')
968 app.add_config_value('ipython_rgxin',
997 app.add_config_value('ipython_rgxin',
969 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
998 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
970 app.add_config_value('ipython_rgxout',
999 app.add_config_value('ipython_rgxout',
971 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
1000 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
972 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
1001 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
973 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
1002 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
974
1003
975 # We could just let matplotlib pick whatever is specified as the default
1004 # We could just let matplotlib pick whatever is specified as the default
976 # backend in the matplotlibrc file, but this would cause issues if the
1005 # backend in the matplotlibrc file, but this would cause issues if the
977 # backend didn't work in headless environments. For this reason, 'agg'
1006 # backend didn't work in headless environments. For this reason, 'agg'
978 # is a good default backend choice.
1007 # is a good default backend choice.
979 app.add_config_value('ipython_mplbackend', 'agg', 'env')
1008 app.add_config_value('ipython_mplbackend', 'agg', 'env')
980
1009
981 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
1010 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
982 # __init__ method will treat it as [].
1011 # __init__ method will treat it as [].
983 execlines = ['import numpy as np', 'import matplotlib.pyplot as plt']
1012 execlines = ['import numpy as np', 'import matplotlib.pyplot as plt']
984 app.add_config_value('ipython_execlines', execlines, 'env')
1013 app.add_config_value('ipython_execlines', execlines, 'env')
985
1014
986 app.add_config_value('ipython_holdcount', True, 'env')
1015 app.add_config_value('ipython_holdcount', True, 'env')
987
1016
988 # Simple smoke test, needs to be converted to a proper automatic test.
1017 # Simple smoke test, needs to be converted to a proper automatic test.
989 def test():
1018 def test():
990
1019
991 examples = [
1020 examples = [
992 r"""
1021 r"""
993 In [9]: pwd
1022 In [9]: pwd
994 Out[9]: '/home/jdhunter/py4science/book'
1023 Out[9]: '/home/jdhunter/py4science/book'
995
1024
996 In [10]: cd bookdata/
1025 In [10]: cd bookdata/
997 /home/jdhunter/py4science/book/bookdata
1026 /home/jdhunter/py4science/book/bookdata
998
1027
999 In [2]: from pylab import *
1028 In [2]: from pylab import *
1000
1029
1001 In [2]: ion()
1030 In [2]: ion()
1002
1031
1003 In [3]: im = imread('stinkbug.png')
1032 In [3]: im = imread('stinkbug.png')
1004
1033
1005 @savefig mystinkbug.png width=4in
1034 @savefig mystinkbug.png width=4in
1006 In [4]: imshow(im)
1035 In [4]: imshow(im)
1007 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1036 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1008
1037
1009 """,
1038 """,
1010 r"""
1039 r"""
1011
1040
1012 In [1]: x = 'hello world'
1041 In [1]: x = 'hello world'
1013
1042
1014 # string methods can be
1043 # string methods can be
1015 # used to alter the string
1044 # used to alter the string
1016 @doctest
1045 @doctest
1017 In [2]: x.upper()
1046 In [2]: x.upper()
1018 Out[2]: 'HELLO WORLD'
1047 Out[2]: 'HELLO WORLD'
1019
1048
1020 @verbatim
1049 @verbatim
1021 In [3]: x.st<TAB>
1050 In [3]: x.st<TAB>
1022 x.startswith x.strip
1051 x.startswith x.strip
1023 """,
1052 """,
1024 r"""
1053 r"""
1025
1054
1026 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1055 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1027 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1056 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1028
1057
1029 In [131]: print url.split('&')
1058 In [131]: print url.split('&')
1030 ['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']
1059 ['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']
1031
1060
1032 In [60]: import urllib
1061 In [60]: import urllib
1033
1062
1034 """,
1063 """,
1035 r"""\
1064 r"""\
1036
1065
1037 In [133]: import numpy.random
1066 In [133]: import numpy.random
1038
1067
1039 @suppress
1068 @suppress
1040 In [134]: numpy.random.seed(2358)
1069 In [134]: numpy.random.seed(2358)
1041
1070
1042 @doctest
1071 @doctest
1043 In [135]: numpy.random.rand(10,2)
1072 In [135]: numpy.random.rand(10,2)
1044 Out[135]:
1073 Out[135]:
1045 array([[ 0.64524308, 0.59943846],
1074 array([[ 0.64524308, 0.59943846],
1046 [ 0.47102322, 0.8715456 ],
1075 [ 0.47102322, 0.8715456 ],
1047 [ 0.29370834, 0.74776844],
1076 [ 0.29370834, 0.74776844],
1048 [ 0.99539577, 0.1313423 ],
1077 [ 0.99539577, 0.1313423 ],
1049 [ 0.16250302, 0.21103583],
1078 [ 0.16250302, 0.21103583],
1050 [ 0.81626524, 0.1312433 ],
1079 [ 0.81626524, 0.1312433 ],
1051 [ 0.67338089, 0.72302393],
1080 [ 0.67338089, 0.72302393],
1052 [ 0.7566368 , 0.07033696],
1081 [ 0.7566368 , 0.07033696],
1053 [ 0.22591016, 0.77731835],
1082 [ 0.22591016, 0.77731835],
1054 [ 0.0072729 , 0.34273127]])
1083 [ 0.0072729 , 0.34273127]])
1055
1084
1056 """,
1085 """,
1057
1086
1058 r"""
1087 r"""
1059 In [106]: print x
1088 In [106]: print x
1060 jdh
1089 jdh
1061
1090
1062 In [109]: for i in range(10):
1091 In [109]: for i in range(10):
1063 .....: print i
1092 .....: print i
1064 .....:
1093 .....:
1065 .....:
1094 .....:
1066 0
1095 0
1067 1
1096 1
1068 2
1097 2
1069 3
1098 3
1070 4
1099 4
1071 5
1100 5
1072 6
1101 6
1073 7
1102 7
1074 8
1103 8
1075 9
1104 9
1076 """,
1105 """,
1077
1106
1078 r"""
1107 r"""
1079
1108
1080 In [144]: from pylab import *
1109 In [144]: from pylab import *
1081
1110
1082 In [145]: ion()
1111 In [145]: ion()
1083
1112
1084 # use a semicolon to suppress the output
1113 # use a semicolon to suppress the output
1085 @savefig test_hist.png width=4in
1114 @savefig test_hist.png width=4in
1086 In [151]: hist(np.random.randn(10000), 100);
1115 In [151]: hist(np.random.randn(10000), 100);
1087
1116
1088
1117
1089 @savefig test_plot.png width=4in
1118 @savefig test_plot.png width=4in
1090 In [151]: plot(np.random.randn(10000), 'o');
1119 In [151]: plot(np.random.randn(10000), 'o');
1091 """,
1120 """,
1092
1121
1093 r"""
1122 r"""
1094 # use a semicolon to suppress the output
1123 # use a semicolon to suppress the output
1095 In [151]: plt.clf()
1124 In [151]: plt.clf()
1096
1125
1097 @savefig plot_simple.png width=4in
1126 @savefig plot_simple.png width=4in
1098 In [151]: plot([1,2,3])
1127 In [151]: plot([1,2,3])
1099
1128
1100 @savefig hist_simple.png width=4in
1129 @savefig hist_simple.png width=4in
1101 In [151]: hist(np.random.randn(10000), 100);
1130 In [151]: hist(np.random.randn(10000), 100);
1102
1131
1103 """,
1132 """,
1104 r"""
1133 r"""
1105 # update the current fig
1134 # update the current fig
1106 In [151]: ylabel('number')
1135 In [151]: ylabel('number')
1107
1136
1108 In [152]: title('normal distribution')
1137 In [152]: title('normal distribution')
1109
1138
1110
1139
1111 @savefig hist_with_text.png
1140 @savefig hist_with_text.png
1112 In [153]: grid(True)
1141 In [153]: grid(True)
1113
1142
1114 @doctest float
1143 @doctest float
1115 In [154]: 0.1 + 0.2
1144 In [154]: 0.1 + 0.2
1116 Out[154]: 0.3
1145 Out[154]: 0.3
1117
1146
1118 @doctest float
1147 @doctest float
1119 In [155]: np.arange(16).reshape(4,4)
1148 In [155]: np.arange(16).reshape(4,4)
1120 Out[155]:
1149 Out[155]:
1121 array([[ 0, 1, 2, 3],
1150 array([[ 0, 1, 2, 3],
1122 [ 4, 5, 6, 7],
1151 [ 4, 5, 6, 7],
1123 [ 8, 9, 10, 11],
1152 [ 8, 9, 10, 11],
1124 [12, 13, 14, 15]])
1153 [12, 13, 14, 15]])
1125
1154
1126 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1155 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1127
1156
1128 In [2]: x[0,0] = np.inf
1157 In [2]: x[0,0] = np.inf
1129
1158
1130 In [3]: x[0,1] = np.nan
1159 In [3]: x[0,1] = np.nan
1131
1160
1132 @doctest float
1161 @doctest float
1133 In [4]: x
1162 In [4]: x
1134 Out[4]:
1163 Out[4]:
1135 array([[ inf, nan, 2., 3.],
1164 array([[ inf, nan, 2., 3.],
1136 [ 4., 5., 6., 7.],
1165 [ 4., 5., 6., 7.],
1137 [ 8., 9., 10., 11.],
1166 [ 8., 9., 10., 11.],
1138 [ 12., 13., 14., 15.]])
1167 [ 12., 13., 14., 15.]])
1139
1168
1140
1169
1141 """,
1170 """,
1142 ]
1171 ]
1143 # skip local-file depending first example:
1172 # skip local-file depending first example:
1144 examples = examples[1:]
1173 examples = examples[1:]
1145
1174
1146 #ipython_directive.DEBUG = True # dbg
1175 #ipython_directive.DEBUG = True # dbg
1147 #options = dict(suppress=True) # dbg
1176 #options = dict(suppress=True) # dbg
1148 options = dict()
1177 options = dict()
1149 for example in examples:
1178 for example in examples:
1150 content = example.split('\n')
1179 content = example.split('\n')
1151 IPythonDirective('debug', arguments=None, options=options,
1180 IPythonDirective('debug', arguments=None, options=options,
1152 content=content, lineno=0,
1181 content=content, lineno=0,
1153 content_offset=None, block_text=None,
1182 content_offset=None, block_text=None,
1154 state=None, state_machine=None,
1183 state=None, state_machine=None,
1155 )
1184 )
1156
1185
1157 # Run test suite as a script
1186 # Run test suite as a script
1158 if __name__=='__main__':
1187 if __name__=='__main__':
1159 if not os.path.isdir('_static'):
1188 if not os.path.isdir('_static'):
1160 os.mkdir('_static')
1189 os.mkdir('_static')
1161 test()
1190 test()
1162 print('All OK? Check figures in _static/')
1191 print('All OK? Check figures in _static/')
General Comments 0
You need to be logged in to leave comments. Login now