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