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