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