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