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