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