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