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