##// END OF EJS Templates
Add 'float' option to @doctest pseudo-decorator.
chebee7i -
Show More
@@ -1,871 +1,971 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Sphinx directive to support embedded IPython code.
2 """Sphinx directive to support embedded IPython code.
3
3
4 This directive allows pasting of entire interactive IPython sessions, prompts
4 This directive allows pasting of entire interactive IPython sessions, prompts
5 and all, and their code will actually get re-executed at doc build time, with
5 and all, and their code will actually get re-executed at doc build time, with
6 all prompts renumbered sequentially. It also allows you to input code as a pure
6 all prompts renumbered sequentially. It also allows you to input code as a pure
7 python input by giving the argument python to the directive. The output looks
7 python input by giving the argument python to the directive. The output looks
8 like an interactive ipython section.
8 like an interactive ipython section.
9
9
10 To enable this directive, simply list it in your Sphinx ``conf.py`` file
10 To enable this directive, simply list it in your Sphinx ``conf.py`` file
11 (making sure the directory where you placed it is visible to sphinx, as is
11 (making sure the directory where you placed it is visible to sphinx, as is
12 needed for all Sphinx directives). For example, to enable syntax highlighting
12 needed for all Sphinx directives). For example, to enable syntax highlighting
13 and the IPython directive::
13 and the IPython directive::
14
14
15 extensions = ['IPython.sphinxext.ipython_console_highlighting',
15 extensions = ['IPython.sphinxext.ipython_console_highlighting',
16 'IPython.sphinxext.ipython_directive']
16 'IPython.sphinxext.ipython_directive']
17
17
18 The IPython directive outputs code-blocks with the language 'ipython'. So
18 The IPython directive outputs code-blocks with the language 'ipython'. So
19 if you do not have the syntax highlighting extension enabled as well, then
19 if you do not have the syntax highlighting extension enabled as well, then
20 all rendered code-blocks will be uncolored. By default this directive assumes
20 all rendered code-blocks will be uncolored. By default this directive assumes
21 that your prompts are unchanged IPython ones, but this can be customized.
21 that your prompts are unchanged IPython ones, but this can be customized.
22 The configurable options that can be placed in conf.py are:
22 The configurable options that can be placed in conf.py are:
23
23
24 ipython_savefig_dir:
24 ipython_savefig_dir:
25 The directory in which to save the figures. This is relative to the
25 The directory in which to save the figures. This is relative to the
26 Sphinx source directory. The default is `html_static_path`.
26 Sphinx source directory. The default is `html_static_path`.
27 ipython_rgxin:
27 ipython_rgxin:
28 The compiled regular expression to denote the start of IPython input
28 The compiled regular expression to denote the start of IPython input
29 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
29 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
30 shouldn't need to change this.
30 shouldn't need to change this.
31 ipython_rgxout:
31 ipython_rgxout:
32 The compiled regular expression to denote the start of IPython output
32 The compiled regular expression to denote the start of IPython output
33 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
33 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
34 shouldn't need to change this.
34 shouldn't need to change this.
35 ipython_promptin:
35 ipython_promptin:
36 The string to represent the IPython input prompt in the generated ReST.
36 The string to represent the IPython input prompt in the generated ReST.
37 The default is 'In [%d]:'. This expects that the line numbers are used
37 The default is 'In [%d]:'. This expects that the line numbers are used
38 in the prompt.
38 in the prompt.
39 ipython_promptout:
39 ipython_promptout:
40 The string to represent the IPython prompt in the generated ReST. The
40 The string to represent the IPython prompt in the generated ReST. The
41 default is 'Out [%d]:'. This expects that the line numbers are used
41 default is 'Out [%d]:'. This expects that the line numbers are used
42 in the prompt.
42 in the prompt.
43 ipython_mplbackend:
43 ipython_mplbackend:
44 The string which specifies if the embedded Sphinx shell should import
44 The string which specifies if the embedded Sphinx shell should import
45 Matplotlib and set the backend for each code-block. If `None`, or equal
45 Matplotlib and set the backend for each code-block. If `None`, or equal
46 to '' or 'None', then `matplotlib` will not be automatically imported. If
46 to '' or 'None', then `matplotlib` will not be automatically imported. If
47 not `None`, then the value should specify a backend that is passed to
47 not `None`, then the value should specify a backend that is passed to
48 `matplotlib.use()`. The default value is 'agg'.
48 `matplotlib.use()`. The default value is 'agg'.
49 ipython_execlines:
49 ipython_execlines:
50 A list of strings to be exec'd for each embedded Sphinx shell. Typical
50 A list of strings to be exec'd for each embedded Sphinx shell. Typical
51 usage is to make certain packages always available. If None, then
51 usage is to make certain packages always available. If None, then
52 `['import numpy as np', 'from pylab import *']` is used. Set this to an
52 `['import numpy as np', 'from pylab import *']` is used. Set this to an
53 empty list if you wish to have no imports always available.
53 empty list if you wish to have no imports always available.
54
54
55 As an example, to use the IPython directive when `matplotlib` is not available,
55 As an example, to use the IPython directive when `matplotlib` is not available,
56 one sets the backend to `None`::
56 one sets the backend to `None`::
57
57
58 ipython_mplbacked = None
58 ipython_mplbacked = None
59
59
60 An example usage of the directive is:
60 An example usage of the directive is:
61
61
62 .. code-block:: rst
62 .. code-block:: rst
63
63
64 .. ipython::
64 .. ipython::
65
65
66 In [1]: x = 1
66 In [1]: x = 1
67
67
68 In [2]: y = x**2
68 In [2]: y = x**2
69
69
70 In [3]: print(y)
70 In [3]: print(y)
71
71
72
73 See http://matplotlib.org/sampledoc/ipython_directive.html for more additional
72 See http://matplotlib.org/sampledoc/ipython_directive.html for more additional
74 documentation.
73 documentation.
75
74
76 ToDo
75 ToDo
77 ----
76 ----
78
77
79 - Turn the ad-hoc test() function into a real test suite.
78 - Turn the ad-hoc test() function into a real test suite.
80 - Break up ipython-specific functionality from matplotlib stuff into better
79 - Break up ipython-specific functionality from matplotlib stuff into better
81 separated code.
80 separated code.
82
81
83 Authors
82 Authors
84 -------
83 -------
85
84
86 - John D Hunter: orignal author.
85 - John D Hunter: orignal author.
87 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
86 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
88 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
87 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
89 - Skipper Seabold, refactoring, cleanups, pure python addition
88 - Skipper Seabold, refactoring, cleanups, pure python addition
90 """
89 """
91 from __future__ import print_function
90 from __future__ import print_function
92
91
93 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
94 # Imports
93 # Imports
95 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
96
95
97 # Stdlib
96 # Stdlib
98 import os
97 import os
99 import re
98 import re
100 import sys
99 import sys
101 import tempfile
100 import tempfile
102 import ast
101 import ast
103
102
104 # To keep compatibility with various python versions
103 # To keep compatibility with various python versions
105 try:
104 try:
106 from hashlib import md5
105 from hashlib import md5
107 except ImportError:
106 except ImportError:
108 from md5 import md5
107 from md5 import md5
109
108
110 # Third-party
109 # Third-party
111 import sphinx
110 import sphinx
112 from docutils.parsers.rst import directives
111 from docutils.parsers.rst import directives
113 from docutils import nodes
112 from docutils import nodes
114 from sphinx.util.compat import Directive
113 from sphinx.util.compat import Directive
115
114
116 # Our own
115 # Our own
117 from IPython import Config, InteractiveShell
116 from IPython import Config, InteractiveShell
118 from IPython.core.profiledir import ProfileDir
117 from IPython.core.profiledir import ProfileDir
119 from IPython.utils import io
118 from IPython.utils import io
120 from IPython.utils.py3compat import PY3
119 from IPython.utils.py3compat import PY3
121
120
122 if PY3:
121 if PY3:
123 from io import StringIO
122 from io import StringIO
124 else:
123 else:
125 from StringIO import StringIO
124 from StringIO import StringIO
126
125
127 #-----------------------------------------------------------------------------
126 #-----------------------------------------------------------------------------
128 # Globals
127 # Globals
129 #-----------------------------------------------------------------------------
128 #-----------------------------------------------------------------------------
130 # for tokenizing blocks
129 # for tokenizing blocks
131 COMMENT, INPUT, OUTPUT = range(3)
130 COMMENT, INPUT, OUTPUT = range(3)
132
131
133 #-----------------------------------------------------------------------------
132 #-----------------------------------------------------------------------------
134 # Functions and class declarations
133 # Functions and class declarations
135 #-----------------------------------------------------------------------------
134 #-----------------------------------------------------------------------------
135 def str_to_array(s):
136 """
137 Simplistic converter of strings from repr to float NumPy arrays.
138
139 """
140 import numpy as np
141
142 # Handle infs (assumes default printoptions for NumPy)
143 s = s.replace(u'inf', u'np.inf')
144 s = s.replace(u'nan', u'np.nan')
145
146 if s.startswith(u'array'):
147 # Remove array( and )
148 s = s[6:-1]
149
150 if s.startswith(u'['):
151 a = np.array(eval(s), dtype=float)
152 else:
153 # Assume its a regular float. Force 1D so we can index into it.
154 a = np.atleast_1d(float(s))
155 return a
156
136 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
157 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
137 """
158 """
138 part is a string of ipython text, comprised of at most one
159 part is a string of ipython text, comprised of at most one
139 input, one ouput, comments, and blank lines. The block parser
160 input, one ouput, comments, and blank lines. The block parser
140 parses the text into a list of::
161 parses the text into a list of::
141
162
142 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
163 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
143
164
144 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
165 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
145 data is, depending on the type of token::
166 data is, depending on the type of token::
146
167
147 COMMENT : the comment string
168 COMMENT : the comment string
148
169
149 INPUT: the (DECORATOR, INPUT_LINE, REST) where
170 INPUT: the (DECORATOR, INPUT_LINE, REST) where
150 DECORATOR: the input decorator (or None)
171 DECORATOR: the input decorator (or None)
151 INPUT_LINE: the input as string (possibly multi-line)
172 INPUT_LINE: the input as string (possibly multi-line)
152 REST : any stdout generated by the input line (not OUTPUT)
173 REST : any stdout generated by the input line (not OUTPUT)
153
174
154
175
155 OUTPUT: the output string, possibly multi-line
176 OUTPUT: the output string, possibly multi-line
156
177
157 """
178 """
158 block = []
179 block = []
159 lines = part.split('\n')
180 lines = part.split('\n')
160 N = len(lines)
181 N = len(lines)
161 i = 0
182 i = 0
162 decorator = None
183 decorator = None
163 while 1:
184 while 1:
164
185
165 if i==N:
186 if i==N:
166 # nothing left to parse -- the last line
187 # nothing left to parse -- the last line
167 break
188 break
168
189
169 line = lines[i]
190 line = lines[i]
170 i += 1
191 i += 1
171 line_stripped = line.strip()
192 line_stripped = line.strip()
172 if line_stripped.startswith('#'):
193 if line_stripped.startswith('#'):
173 block.append((COMMENT, line))
194 block.append((COMMENT, line))
174 continue
195 continue
175
196
176 if line_stripped.startswith('@'):
197 if line_stripped.startswith('@'):
177 # we're assuming at most one decorator -- may need to
198 # we're assuming at most one decorator -- may need to
178 # rethink
199 # rethink
179 decorator = line_stripped
200 decorator = line_stripped
180 continue
201 continue
181
202
182 # does this look like an input line?
203 # does this look like an input line?
183 matchin = rgxin.match(line)
204 matchin = rgxin.match(line)
184 if matchin:
205 if matchin:
185 lineno, inputline = int(matchin.group(1)), matchin.group(2)
206 lineno, inputline = int(matchin.group(1)), matchin.group(2)
186
207
187 # the ....: continuation string
208 # the ....: continuation string
188 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
209 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
189 Nc = len(continuation)
210 Nc = len(continuation)
190 # input lines can continue on for more than one line, if
211 # input lines can continue on for more than one line, if
191 # we have a '\' line continuation char or a function call
212 # we have a '\' line continuation char or a function call
192 # echo line 'print'. The input line can only be
213 # echo line 'print'. The input line can only be
193 # terminated by the end of the block or an output line, so
214 # terminated by the end of the block or an output line, so
194 # we parse out the rest of the input line if it is
215 # we parse out the rest of the input line if it is
195 # multiline as well as any echo text
216 # multiline as well as any echo text
196
217
197 rest = []
218 rest = []
198 while i<N:
219 while i<N:
199
220
200 # look ahead; if the next line is blank, or a comment, or
221 # look ahead; if the next line is blank, or a comment, or
201 # an output line, we're done
222 # an output line, we're done
202
223
203 nextline = lines[i]
224 nextline = lines[i]
204 matchout = rgxout.match(nextline)
225 matchout = rgxout.match(nextline)
205 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
226 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
206 if matchout or nextline.startswith('#'):
227 if matchout or nextline.startswith('#'):
207 break
228 break
208 elif nextline.startswith(continuation):
229 elif nextline.startswith(continuation):
209 inputline += '\n' + nextline[Nc:]
230 inputline += '\n' + nextline[Nc:]
210 else:
231 else:
211 rest.append(nextline)
232 rest.append(nextline)
212 i+= 1
233 i+= 1
213
234
214 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
235 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
215 continue
236 continue
216
237
217 # if it looks like an output line grab all the text to the end
238 # if it looks like an output line grab all the text to the end
218 # of the block
239 # of the block
219 matchout = rgxout.match(line)
240 matchout = rgxout.match(line)
220 if matchout:
241 if matchout:
221 lineno, output = int(matchout.group(1)), matchout.group(2)
242 lineno, output = int(matchout.group(1)), matchout.group(2)
222 if i<N-1:
243 if i<N-1:
223 output = '\n'.join([output] + lines[i:])
244 output = '\n'.join([output] + lines[i:])
224
245
225 block.append((OUTPUT, output))
246 block.append((OUTPUT, output))
226 break
247 break
227
248
228 return block
249 return block
229
250
230 class EmbeddedSphinxShell(object):
251 class EmbeddedSphinxShell(object):
231 """An embedded IPython instance to run inside Sphinx"""
252 """An embedded IPython instance to run inside Sphinx"""
232
253
233 def __init__(self, exec_lines=None):
254 def __init__(self, exec_lines=None):
234
255
235 self.cout = StringIO()
256 self.cout = StringIO()
236
257
237 if exec_lines is None:
258 if exec_lines is None:
238 exec_lines = ['import numpy as np', 'from pylab import *']
259 exec_lines = ['import numpy as np', 'from pylab import *']
239
260
240 # Create config object for IPython
261 # Create config object for IPython
241 config = Config()
262 config = Config()
242 config.InteractiveShell.autocall = False
263 config.InteractiveShell.autocall = False
243 config.InteractiveShell.autoindent = False
264 config.InteractiveShell.autoindent = False
244 config.InteractiveShell.colors = 'NoColor'
265 config.InteractiveShell.colors = 'NoColor'
245
266
246 # create a profile so instance history isn't saved
267 # create a profile so instance history isn't saved
247 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
268 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
248 profname = 'auto_profile_sphinx_build'
269 profname = 'auto_profile_sphinx_build'
249 pdir = os.path.join(tmp_profile_dir,profname)
270 pdir = os.path.join(tmp_profile_dir,profname)
250 profile = ProfileDir.create_profile_dir(pdir)
271 profile = ProfileDir.create_profile_dir(pdir)
251
272
252 # Create and initialize global ipython, but don't start its mainloop.
273 # Create and initialize global ipython, but don't start its mainloop.
253 # This will persist across different EmbededSphinxShell instances.
274 # This will persist across different EmbededSphinxShell instances.
254 IP = InteractiveShell.instance(config=config, profile_dir=profile)
275 IP = InteractiveShell.instance(config=config, profile_dir=profile)
255
276
256 # io.stdout redirect must be done *after* instantiating InteractiveShell
277 # io.stdout redirect must be done *after* instantiating InteractiveShell
257 io.stdout = self.cout
278 io.stdout = self.cout
258 io.stderr = self.cout
279 io.stderr = self.cout
259
280
260 # For debugging, so we can see normal output, use this:
281 # For debugging, so we can see normal output, use this:
261 #from IPython.utils.io import Tee
282 #from IPython.utils.io import Tee
262 #io.stdout = Tee(self.cout, channel='stdout') # dbg
283 #io.stdout = Tee(self.cout, channel='stdout') # dbg
263 #io.stderr = Tee(self.cout, channel='stderr') # dbg
284 #io.stderr = Tee(self.cout, channel='stderr') # dbg
264
285
265 # Store a few parts of IPython we'll need.
286 # Store a few parts of IPython we'll need.
266 self.IP = IP
287 self.IP = IP
267 self.user_ns = self.IP.user_ns
288 self.user_ns = self.IP.user_ns
268 self.user_global_ns = self.IP.user_global_ns
289 self.user_global_ns = self.IP.user_global_ns
269
290
270 self.input = ''
291 self.input = ''
271 self.output = ''
292 self.output = ''
272
293
273 self.is_verbatim = False
294 self.is_verbatim = False
274 self.is_doctest = False
295 self.is_doctest = False
275 self.is_suppress = False
296 self.is_suppress = False
276
297
277 # on the first call to the savefig decorator, we'll import
298 # on the first call to the savefig decorator, we'll import
278 # pyplot as plt so we can make a call to the plt.gcf().savefig
299 # pyplot as plt so we can make a call to the plt.gcf().savefig
279 self._pyplot_imported = False
300 self._pyplot_imported = False
280
301
281 # Prepopulate the namespace.
302 # Prepopulate the namespace.
282 for line in exec_lines:
303 for line in exec_lines:
283 self.process_input_line(line, store_history=False)
304 self.process_input_line(line, store_history=False)
284
305
285 def clear_cout(self):
306 def clear_cout(self):
286 self.cout.seek(0)
307 self.cout.seek(0)
287 self.cout.truncate(0)
308 self.cout.truncate(0)
288
309
289 def process_input_line(self, line, store_history=True):
310 def process_input_line(self, line, store_history=True):
290 """process the input, capturing stdout"""
311 """process the input, capturing stdout"""
291 #print "input='%s'"%self.input
312 #print "input='%s'"%self.input
292 stdout = sys.stdout
313 stdout = sys.stdout
293 splitter = self.IP.input_splitter
314 splitter = self.IP.input_splitter
294 try:
315 try:
295 sys.stdout = self.cout
316 sys.stdout = self.cout
296 splitter.push(line)
317 splitter.push(line)
297 more = splitter.push_accepts_more()
318 more = splitter.push_accepts_more()
298 if not more:
319 if not more:
299 source_raw = splitter.source_raw_reset()[1]
320 source_raw = splitter.source_raw_reset()[1]
300 self.IP.run_cell(source_raw, store_history=store_history)
321 self.IP.run_cell(source_raw, store_history=store_history)
301 finally:
322 finally:
302 sys.stdout = stdout
323 sys.stdout = stdout
303
324
304 def process_image(self, decorator):
325 def process_image(self, decorator):
305 """
326 """
306 # build out an image directive like
327 # build out an image directive like
307 # .. image:: somefile.png
328 # .. image:: somefile.png
308 # :width 4in
329 # :width 4in
309 #
330 #
310 # from an input like
331 # from an input like
311 # savefig somefile.png width=4in
332 # savefig somefile.png width=4in
312 """
333 """
313 savefig_dir = self.savefig_dir
334 savefig_dir = self.savefig_dir
314 source_dir = self.source_dir
335 source_dir = self.source_dir
315 saveargs = decorator.split(' ')
336 saveargs = decorator.split(' ')
316 filename = saveargs[1]
337 filename = saveargs[1]
317 # insert relative path to image file in source
338 # insert relative path to image file in source
318 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
339 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
319 source_dir)
340 source_dir)
320
341
321 imagerows = ['.. image:: %s'%outfile]
342 imagerows = ['.. image:: %s'%outfile]
322
343
323 for kwarg in saveargs[2:]:
344 for kwarg in saveargs[2:]:
324 arg, val = kwarg.split('=')
345 arg, val = kwarg.split('=')
325 arg = arg.strip()
346 arg = arg.strip()
326 val = val.strip()
347 val = val.strip()
327 imagerows.append(' :%s: %s'%(arg, val))
348 imagerows.append(' :%s: %s'%(arg, val))
328
349
329 image_file = os.path.basename(outfile) # only return file name
350 image_file = os.path.basename(outfile) # only return file name
330 image_directive = '\n'.join(imagerows)
351 image_directive = '\n'.join(imagerows)
331 return image_file, image_directive
352 return image_file, image_directive
332
353
333
354
334 # Callbacks for each type of token
355 # Callbacks for each type of token
335 def process_input(self, data, input_prompt, lineno):
356 def process_input(self, data, input_prompt, lineno):
336 """Process data block for INPUT token."""
357 """Process data block for INPUT token."""
337 decorator, input, rest = data
358 decorator, input, rest = data
338 image_file = None
359 image_file = None
339 image_directive = None
360 image_directive = None
340 #print 'INPUT:', data # dbg
361 #print 'INPUT:', data # dbg
341 is_verbatim = decorator=='@verbatim' or self.is_verbatim
362 is_verbatim = decorator=='@verbatim' or self.is_verbatim
342 is_doctest = decorator=='@doctest' or self.is_doctest
363 is_doctest = (decorator is not None and \
364 decorator.startswith('@doctest')) or self.is_doctest
343 is_suppress = decorator=='@suppress' or self.is_suppress
365 is_suppress = decorator=='@suppress' or self.is_suppress
344 is_savefig = decorator is not None and \
366 is_savefig = decorator is not None and \
345 decorator.startswith('@savefig')
367 decorator.startswith('@savefig')
346
368
347 input_lines = input.split('\n')
369 input_lines = input.split('\n')
348 if len(input_lines) > 1:
370 if len(input_lines) > 1:
349 if input_lines[-1] != "":
371 if input_lines[-1] != "":
350 input_lines.append('') # make sure there's a blank line
372 input_lines.append('') # make sure there's a blank line
351 # so splitter buffer gets reset
373 # so splitter buffer gets reset
352
374
353 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
375 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
354 Nc = len(continuation)
376 Nc = len(continuation)
355
377
356 if is_savefig:
378 if is_savefig:
357 image_file, image_directive = self.process_image(decorator)
379 image_file, image_directive = self.process_image(decorator)
358
380
359 ret = []
381 ret = []
360 is_semicolon = False
382 is_semicolon = False
361
383
362 for i, line in enumerate(input_lines):
384 for i, line in enumerate(input_lines):
363 if line.endswith(';'):
385 if line.endswith(';'):
364 is_semicolon = True
386 is_semicolon = True
365
387
366 if i==0:
388 if i==0:
367 # process the first input line
389 # process the first input line
368 if is_verbatim:
390 if is_verbatim:
369 self.process_input_line('')
391 self.process_input_line('')
370 self.IP.execution_count += 1 # increment it anyway
392 self.IP.execution_count += 1 # increment it anyway
371 else:
393 else:
372 # only submit the line in non-verbatim mode
394 # only submit the line in non-verbatim mode
373 self.process_input_line(line, store_history=True)
395 self.process_input_line(line, store_history=True)
374 formatted_line = '%s %s'%(input_prompt, line)
396 formatted_line = '%s %s'%(input_prompt, line)
375 else:
397 else:
376 # process a continuation line
398 # process a continuation line
377 if not is_verbatim:
399 if not is_verbatim:
378 self.process_input_line(line, store_history=True)
400 self.process_input_line(line, store_history=True)
379
401
380 formatted_line = '%s %s'%(continuation, line)
402 formatted_line = '%s %s'%(continuation, line)
381
403
382 if not is_suppress:
404 if not is_suppress:
383 ret.append(formatted_line)
405 ret.append(formatted_line)
384
406
385 if not is_suppress and len(rest.strip()) and is_verbatim:
407 if not is_suppress and len(rest.strip()) and is_verbatim:
386 # the "rest" is the standard output of the
408 # the "rest" is the standard output of the
387 # input, which needs to be added in
409 # input, which needs to be added in
388 # verbatim mode
410 # verbatim mode
389 ret.append(rest)
411 ret.append(rest)
390
412
391 self.cout.seek(0)
413 self.cout.seek(0)
392 output = self.cout.read()
414 output = self.cout.read()
393 if not is_suppress and not is_semicolon:
415 if not is_suppress and not is_semicolon:
394 ret.append(output)
416 ret.append(output)
395 elif is_semicolon: # get spacing right
417 elif is_semicolon: # get spacing right
396 ret.append('')
418 ret.append('')
397
419
398 self.cout.truncate(0)
420 self.cout.truncate(0)
399 return (ret, input_lines, output, is_doctest, image_file,
421 return (ret, input_lines, output, is_doctest, decorator, image_file,
400 image_directive)
422 image_directive)
401 #print 'OUTPUT', output # dbg
423 #print 'OUTPUT', output # dbg
402
424
403 def process_output(self, data, output_prompt,
425 def process_output(self, data, output_prompt,
404 input_lines, output, is_doctest, image_file):
426 input_lines, output, is_doctest, decorator, image_file):
405 """Process data block for OUTPUT token."""
427 """Process data block for OUTPUT token."""
406 if is_doctest:
428 if is_doctest and output is not None:
407 submitted = data.strip()
408 found = output
409 if found is not None:
410 found = found.strip()
411
412 # XXX - fperez: in 0.11, 'output' never comes with the prompt
413 # in it, just the actual output text. So I think all this code
414 # can be nuked...
415
416 # the above comment does not appear to be accurate... (minrk)
417
429
418 ind = found.find(output_prompt)
430 found = output
419 if ind<0:
431 found = found.strip()
420 e='output prompt="%s" does not match out line=%s' % \
432 submitted = data.strip()
421 (output_prompt, found)
422 raise RuntimeError(e)
423 found = found[len(output_prompt):].strip()
424
433
425 if found!=submitted:
434 # Make sure the output contains the output prompt.
426 e = ('doctest failure for input_lines="%s" with '
435 ind = found.find(output_prompt)
427 'found_output="%s" and submitted output="%s"' %
436 if ind < 0:
428 (input_lines, found, submitted) )
437 e = ('output prompt="{0}" does '
438 'not match out line={1}'.format(output_prompt, found))
439 raise RuntimeError(e)
440 found = found[len(output_prompt):].strip()
441
442 # Handle the actual doctest comparison.
443 if decorator.strip() == '@doctest':
444 # Standard doctest
445 if found != submitted:
446 e = ('doctest failure for input_lines="{0}" with '
447 'found_output="{1}" and submitted '
448 'output="{2}"'.format(input_lines, found, submitted) )
429 raise RuntimeError(e)
449 raise RuntimeError(e)
430 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
450 else:
451 self.specialized_doctest(decorator, input_lines,
452 found, submitted)
431
453
432 def process_comment(self, data):
454 def process_comment(self, data):
433 """Process data fPblock for COMMENT token."""
455 """Process data fPblock for COMMENT token."""
434 if not self.is_suppress:
456 if not self.is_suppress:
435 return [data]
457 return [data]
436
458
437 def save_image(self, image_file):
459 def save_image(self, image_file):
438 """
460 """
439 Saves the image file to disk.
461 Saves the image file to disk.
440 """
462 """
441 self.ensure_pyplot()
463 self.ensure_pyplot()
442 command = 'plt.gcf().savefig("%s")'%image_file
464 command = 'plt.gcf().savefig("%s")'%image_file
443 #print 'SAVEFIG', command # dbg
465 #print 'SAVEFIG', command # dbg
444 self.process_input_line('bookmark ipy_thisdir', store_history=False)
466 self.process_input_line('bookmark ipy_thisdir', store_history=False)
445 self.process_input_line('cd -b ipy_savedir', store_history=False)
467 self.process_input_line('cd -b ipy_savedir', store_history=False)
446 self.process_input_line(command, store_history=False)
468 self.process_input_line(command, store_history=False)
447 self.process_input_line('cd -b ipy_thisdir', store_history=False)
469 self.process_input_line('cd -b ipy_thisdir', store_history=False)
448 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
470 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
449 self.clear_cout()
471 self.clear_cout()
450
472
451
452 def process_block(self, block):
473 def process_block(self, block):
453 """
474 """
454 process block from the block_parser and return a list of processed lines
475 process block from the block_parser and return a list of processed lines
455 """
476 """
456 ret = []
477 ret = []
457 output = None
478 output = None
458 input_lines = None
479 input_lines = None
459 lineno = self.IP.execution_count
480 lineno = self.IP.execution_count
460
481
461 input_prompt = self.promptin%lineno
482 input_prompt = self.promptin%lineno
462 output_prompt = self.promptout%lineno
483 output_prompt = self.promptout%lineno
463 image_file = None
484 image_file = None
464 image_directive = None
485 image_directive = None
465
486
466 for token, data in block:
487 for token, data in block:
467 if token==COMMENT:
488 if token==COMMENT:
468 out_data = self.process_comment(data)
489 out_data = self.process_comment(data)
469 elif token==INPUT:
490 elif token==INPUT:
470 (out_data, input_lines, output, is_doctest, image_file,
491 (out_data, input_lines, output, is_doctest, decorator,
471 image_directive) = \
492 image_file, image_directive) = \
472 self.process_input(data, input_prompt, lineno)
493 self.process_input(data, input_prompt, lineno)
473 elif token==OUTPUT:
494 elif token==OUTPUT:
474 out_data = \
495 out_data = \
475 self.process_output(data, output_prompt,
496 self.process_output(data, output_prompt,
476 input_lines, output, is_doctest,
497 input_lines, output, is_doctest,
477 image_file)
498 decorator, image_file)
478 if out_data:
499 if out_data:
479 ret.extend(out_data)
500 ret.extend(out_data)
480
501
481 # save the image files
502 # save the image files
482 if image_file is not None:
503 if image_file is not None:
483 self.save_image(image_file)
504 self.save_image(image_file)
484
505
485 return ret, image_directive
506 return ret, image_directive
486
507
487 def ensure_pyplot(self):
508 def ensure_pyplot(self):
488 if self._pyplot_imported:
509 if self._pyplot_imported:
489 return
510 return
490 self.process_input_line('import matplotlib.pyplot as plt',
511 self.process_input_line('import matplotlib.pyplot as plt',
491 store_history=False)
512 store_history=False)
513 self._pyplot_imported = True
492
514
493 def process_pure_python(self, content):
515 def process_pure_python(self, content):
494 """
516 """
495 content is a list of strings. it is unedited directive conent
517 content is a list of strings. it is unedited directive content
496
518
497 This runs it line by line in the InteractiveShell, prepends
519 This runs it line by line in the InteractiveShell, prepends
498 prompts as needed capturing stderr and stdout, then returns
520 prompts as needed capturing stderr and stdout, then returns
499 the content as a list as if it were ipython code
521 the content as a list as if it were ipython code
500 """
522 """
501 output = []
523 output = []
502 savefig = False # keep up with this to clear figure
524 savefig = False # keep up with this to clear figure
503 multiline = False # to handle line continuation
525 multiline = False # to handle line continuation
504 multiline_start = None
526 multiline_start = None
505 fmtin = self.promptin
527 fmtin = self.promptin
506
528
507 ct = 0
529 ct = 0
508
530
509 for lineno, line in enumerate(content):
531 for lineno, line in enumerate(content):
510
532
511 line_stripped = line.strip()
533 line_stripped = line.strip()
512 if not len(line):
534 if not len(line):
513 output.append(line)
535 output.append(line)
514 continue
536 continue
515
537
516 # handle decorators
538 # handle decorators
517 if line_stripped.startswith('@'):
539 if line_stripped.startswith('@'):
518 output.extend([line])
540 output.extend([line])
519 if 'savefig' in line:
541 if 'savefig' in line:
520 savefig = True # and need to clear figure
542 savefig = True # and need to clear figure
521 continue
543 continue
522
544
523 # handle comments
545 # handle comments
524 if line_stripped.startswith('#'):
546 if line_stripped.startswith('#'):
525 output.extend([line])
547 output.extend([line])
526 continue
548 continue
527
549
528 # deal with lines checking for multiline
550 # deal with lines checking for multiline
529 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
551 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
530 if not multiline:
552 if not multiline:
531 modified = u"%s %s" % (fmtin % ct, line_stripped)
553 modified = u"%s %s" % (fmtin % ct, line_stripped)
532 output.append(modified)
554 output.append(modified)
533 ct += 1
555 ct += 1
534 try:
556 try:
535 ast.parse(line_stripped)
557 ast.parse(line_stripped)
536 output.append(u'')
558 output.append(u'')
537 except Exception: # on a multiline
559 except Exception: # on a multiline
538 multiline = True
560 multiline = True
539 multiline_start = lineno
561 multiline_start = lineno
540 else: # still on a multiline
562 else: # still on a multiline
541 modified = u'%s %s' % (continuation, line)
563 modified = u'%s %s' % (continuation, line)
542 output.append(modified)
564 output.append(modified)
543
565
544 # if the next line is indented, it should be part of multiline
566 # if the next line is indented, it should be part of multiline
545 if len(content) > lineno + 1:
567 if len(content) > lineno + 1:
546 nextline = content[lineno + 1]
568 nextline = content[lineno + 1]
547 if len(nextline) - len(nextline.lstrip()) > 3:
569 if len(nextline) - len(nextline.lstrip()) > 3:
548 continue
570 continue
549 try:
571 try:
550 mod = ast.parse(
572 mod = ast.parse(
551 '\n'.join(content[multiline_start:lineno+1]))
573 '\n'.join(content[multiline_start:lineno+1]))
552 if isinstance(mod.body[0], ast.FunctionDef):
574 if isinstance(mod.body[0], ast.FunctionDef):
553 # check to see if we have the whole function
575 # check to see if we have the whole function
554 for element in mod.body[0].body:
576 for element in mod.body[0].body:
555 if isinstance(element, ast.Return):
577 if isinstance(element, ast.Return):
556 multiline = False
578 multiline = False
557 else:
579 else:
558 output.append(u'')
580 output.append(u'')
559 multiline = False
581 multiline = False
560 except Exception:
582 except Exception:
561 pass
583 pass
562
584
563 if savefig: # clear figure if plotted
585 if savefig: # clear figure if plotted
564 self.ensure_pyplot()
586 self.ensure_pyplot()
565 self.process_input_line('plt.clf()', store_history=False)
587 self.process_input_line('plt.clf()', store_history=False)
566 self.clear_cout()
588 self.clear_cout()
567 savefig = False
589 savefig = False
568
590
569 return output
591 return output
570
592
593 def specialized_doctest(self, decorator, input_lines, found, submitted):
594 """
595 Perform a specialized doctest.
596
597 """
598 # Requires NumPy
599 import numpy as np
600
601 valid_types = set(['float'])
602
603 args = decorator.split()
604
605 doctest_type = args[1]
606 if doctest_type not in valid_types:
607 e = "Invalid option to @doctest: {0}".format(doctest_type)
608 raise Exception(e)
609
610 if len(args) == 2:
611 rtol = 1e-05
612 atol = 1e-08
613 else:
614 # Both must be specified if any are specified.
615 try:
616 rtol = float(args[2])
617 atol = float(args[3])
618 except IndexError:
619 e = ("Both `rtol` and `atol` must be specified "
620 "if either are specified: {0}".format(args))
621 raise IndexError(e)
622
623 try:
624 submitted = str_to_array(submitted)
625 found = str_to_array(found)
626 except:
627 # For example, if the array is huge and there are ellipsis in it.
628 error = True
629 else:
630 found_isnan = np.isnan(found)
631 submitted_isnan = np.isnan(submitted)
632 error = not np.allclose(found_isnan, submitted_isnan)
633 error |= not np.allclose(found[~found_isnan],
634 submitted[~submitted_isnan],
635 rtol=rtol, atol=atol)
636
637 if error:
638 e = ('doctest float comparison failure for input_lines="{0}" with '
639 'found_output="{1}" and submitted '
640 'output="{2}"'.format(input_lines, found, submitted) )
641 raise RuntimeError(e)
642
643
571 class IPythonDirective(Directive):
644 class IPythonDirective(Directive):
572
645
573 has_content = True
646 has_content = True
574 required_arguments = 0
647 required_arguments = 0
575 optional_arguments = 4 # python, suppress, verbatim, doctest
648 optional_arguments = 4 # python, suppress, verbatim, doctest
576 final_argumuent_whitespace = True
649 final_argumuent_whitespace = True
577 option_spec = { 'python': directives.unchanged,
650 option_spec = { 'python': directives.unchanged,
578 'suppress' : directives.flag,
651 'suppress' : directives.flag,
579 'verbatim' : directives.flag,
652 'verbatim' : directives.flag,
580 'doctest' : directives.flag,
653 'doctest' : directives.flag,
581 }
654 }
582
655
583 shell = None
656 shell = None
584
657
585 seen_docs = set()
658 seen_docs = set()
586
659
587 def get_config_options(self):
660 def get_config_options(self):
588 # contains sphinx configuration variables
661 # contains sphinx configuration variables
589 config = self.state.document.settings.env.config
662 config = self.state.document.settings.env.config
590
663
591 # get config variables to set figure output directory
664 # get config variables to set figure output directory
592 confdir = self.state.document.settings.env.app.confdir
665 confdir = self.state.document.settings.env.app.confdir
593 savefig_dir = config.ipython_savefig_dir
666 savefig_dir = config.ipython_savefig_dir
594 source_dir = os.path.dirname(self.state.document.current_source)
667 source_dir = os.path.dirname(self.state.document.current_source)
595 if savefig_dir is None:
668 if savefig_dir is None:
596 savefig_dir = config.html_static_path
669 savefig_dir = config.html_static_path
597 if isinstance(savefig_dir, list):
670 if isinstance(savefig_dir, list):
598 savefig_dir = savefig_dir[0] # safe to assume only one path?
671 savefig_dir = savefig_dir[0] # safe to assume only one path?
599 savefig_dir = os.path.join(confdir, savefig_dir)
672 savefig_dir = os.path.join(confdir, savefig_dir)
600
673
601 # get regex and prompt stuff
674 # get regex and prompt stuff
602 rgxin = config.ipython_rgxin
675 rgxin = config.ipython_rgxin
603 rgxout = config.ipython_rgxout
676 rgxout = config.ipython_rgxout
604 promptin = config.ipython_promptin
677 promptin = config.ipython_promptin
605 promptout = config.ipython_promptout
678 promptout = config.ipython_promptout
606 mplbackend = config.ipython_mplbackend
679 mplbackend = config.ipython_mplbackend
607 exec_lines = config.ipython_execlines
680 exec_lines = config.ipython_execlines
608
681
609 return (savefig_dir, source_dir, rgxin, rgxout,
682 return (savefig_dir, source_dir, rgxin, rgxout,
610 promptin, promptout, mplbackend, exec_lines)
683 promptin, promptout, mplbackend, exec_lines)
611
684
612 def setup(self):
685 def setup(self):
613 # Get configuration values.
686 # Get configuration values.
614 (savefig_dir, source_dir, rgxin, rgxout, promptin,
687 (savefig_dir, source_dir, rgxin, rgxout, promptin,
615 promptout, mplbackend, exec_lines) = self.get_config_options()
688 promptout, mplbackend, exec_lines) = self.get_config_options()
616
689
617 if self.shell is None:
690 if self.shell is None:
618
691
619 if mplbackend:
692 if mplbackend:
620 import matplotlib
693 import matplotlib
621 # Repeated calls to use() will not hurt us since `mplbackend`
694 # Repeated calls to use() will not hurt us since `mplbackend`
622 # is the same each time.
695 # is the same each time.
623 matplotlib.use(mplbackend)
696 matplotlib.use(mplbackend)
624
697
625 # Must be called after (potentially) importing matplotlib and
698 # Must be called after (potentially) importing matplotlib and
626 # setting its backend since exec_lines might import pylab.
699 # setting its backend since exec_lines might import pylab.
627 self.shell = EmbeddedSphinxShell(exec_lines)
700 self.shell = EmbeddedSphinxShell(exec_lines)
628
701
629 # reset the execution count if we haven't processed this doc
702 # reset the execution count if we haven't processed this doc
630 #NOTE: this may be borked if there are multiple seen_doc tmp files
703 #NOTE: this may be borked if there are multiple seen_doc tmp files
631 #check time stamp?
704 #check time stamp?
632 if not self.state.document.current_source in self.seen_docs:
705 if not self.state.document.current_source in self.seen_docs:
633 self.shell.IP.history_manager.reset()
706 self.shell.IP.history_manager.reset()
634 self.shell.IP.execution_count = 1
707 self.shell.IP.execution_count = 1
635 self.seen_docs.add(self.state.document.current_source)
708 self.seen_docs.add(self.state.document.current_source)
636
709
637 # and attach to shell so we don't have to pass them around
710 # and attach to shell so we don't have to pass them around
638 self.shell.rgxin = rgxin
711 self.shell.rgxin = rgxin
639 self.shell.rgxout = rgxout
712 self.shell.rgxout = rgxout
640 self.shell.promptin = promptin
713 self.shell.promptin = promptin
641 self.shell.promptout = promptout
714 self.shell.promptout = promptout
642 self.shell.savefig_dir = savefig_dir
715 self.shell.savefig_dir = savefig_dir
643 self.shell.source_dir = source_dir
716 self.shell.source_dir = source_dir
644
717
645 # setup bookmark for saving figures directory
718 # setup bookmark for saving figures directory
646 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
719 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
647 store_history=False)
720 store_history=False)
648 self.shell.clear_cout()
721 self.shell.clear_cout()
649
722
650 return rgxin, rgxout, promptin, promptout
723 return rgxin, rgxout, promptin, promptout
651
724
652
725
653 def teardown(self):
726 def teardown(self):
654 # delete last bookmark
727 # delete last bookmark
655 self.shell.process_input_line('bookmark -d ipy_savedir',
728 self.shell.process_input_line('bookmark -d ipy_savedir',
656 store_history=False)
729 store_history=False)
657 self.shell.clear_cout()
730 self.shell.clear_cout()
658
731
659 def run(self):
732 def run(self):
660 debug = False
733 debug = False
661
734
662 #TODO, any reason block_parser can't be a method of embeddable shell
735 #TODO, any reason block_parser can't be a method of embeddable shell
663 # then we wouldn't have to carry these around
736 # then we wouldn't have to carry these around
664 rgxin, rgxout, promptin, promptout = self.setup()
737 rgxin, rgxout, promptin, promptout = self.setup()
665
738
666 options = self.options
739 options = self.options
667 self.shell.is_suppress = 'suppress' in options
740 self.shell.is_suppress = 'suppress' in options
668 self.shell.is_doctest = 'doctest' in options
741 self.shell.is_doctest = 'doctest' in options
669 self.shell.is_verbatim = 'verbatim' in options
742 self.shell.is_verbatim = 'verbatim' in options
670
743
671 # handle pure python code
744 # handle pure python code
672 if 'python' in self.arguments:
745 if 'python' in self.arguments:
673 content = self.content
746 content = self.content
674 self.content = self.shell.process_pure_python(content)
747 self.content = self.shell.process_pure_python(content)
675
748
676 parts = '\n'.join(self.content).split('\n\n')
749 parts = '\n'.join(self.content).split('\n\n')
677
750
678 lines = ['.. code-block:: ipython','']
751 lines = ['.. code-block:: ipython','']
679 figures = []
752 figures = []
680
753
681 for part in parts:
754 for part in parts:
682 block = block_parser(part, rgxin, rgxout, promptin, promptout)
755 block = block_parser(part, rgxin, rgxout, promptin, promptout)
683 if len(block):
756 if len(block):
684 rows, figure = self.shell.process_block(block)
757 rows, figure = self.shell.process_block(block)
685 for row in rows:
758 for row in rows:
686 lines.extend([' %s'%line for line in row.split('\n')])
759 lines.extend([' %s'%line for line in row.split('\n')])
687
760
688 if figure is not None:
761 if figure is not None:
689 figures.append(figure)
762 figures.append(figure)
690
763
691 for figure in figures:
764 for figure in figures:
692 lines.append('')
765 lines.append('')
693 lines.extend(figure.split('\n'))
766 lines.extend(figure.split('\n'))
694 lines.append('')
767 lines.append('')
695
768
696 if len(lines)>2:
769 if len(lines)>2:
697 if debug:
770 if debug:
698 print('\n'.join(lines))
771 print('\n'.join(lines))
699 else:
772 else:
700 # This is what makes the lines appear in the final output.
773 # This is what makes the lines appear in the final output.
701 self.state_machine.insert_input(
774 self.state_machine.insert_input(
702 lines, self.state_machine.input_lines.source(0))
775 lines, self.state_machine.input_lines.source(0))
703
776
704 # cleanup
777 # cleanup
705 self.teardown()
778 self.teardown()
706
779
707 return []#, imgnode]
780 return []#, imgnode]
708
781
709 # Enable as a proper Sphinx directive
782 # Enable as a proper Sphinx directive
710 def setup(app):
783 def setup(app):
711 setup.app = app
784 setup.app = app
712
785
713 app.add_directive('ipython', IPythonDirective)
786 app.add_directive('ipython', IPythonDirective)
714 app.add_config_value('ipython_savefig_dir', None, 'env')
787 app.add_config_value('ipython_savefig_dir', None, 'env')
715 app.add_config_value('ipython_rgxin',
788 app.add_config_value('ipython_rgxin',
716 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
789 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
717 app.add_config_value('ipython_rgxout',
790 app.add_config_value('ipython_rgxout',
718 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
791 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
719 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
792 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
720 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
793 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
721 app.add_config_value('ipython_mplbackend', 'agg', 'env')
794 app.add_config_value('ipython_mplbackend', 'agg', 'env')
722 app.add_config_value('ipython_execlines', None, 'env')
795 app.add_config_value('ipython_execlines', None, 'env')
723
796
724 # Simple smoke test, needs to be converted to a proper automatic test.
797 # Simple smoke test, needs to be converted to a proper automatic test.
725 def test():
798 def test():
726
799
727 examples = [
800 examples = [
728 r"""
801 r"""
729 In [9]: pwd
802 In [9]: pwd
730 Out[9]: '/home/jdhunter/py4science/book'
803 Out[9]: '/home/jdhunter/py4science/book'
731
804
732 In [10]: cd bookdata/
805 In [10]: cd bookdata/
733 /home/jdhunter/py4science/book/bookdata
806 /home/jdhunter/py4science/book/bookdata
734
807
735 In [2]: from pylab import *
808 In [2]: from pylab import *
736
809
737 In [2]: ion()
810 In [2]: ion()
738
811
739 In [3]: im = imread('stinkbug.png')
812 In [3]: im = imread('stinkbug.png')
740
813
741 @savefig mystinkbug.png width=4in
814 @savefig mystinkbug.png width=4in
742 In [4]: imshow(im)
815 In [4]: imshow(im)
743 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
816 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
744
817
745 """,
818 """,
746 r"""
819 r"""
747
820
748 In [1]: x = 'hello world'
821 In [1]: x = 'hello world'
749
822
750 # string methods can be
823 # string methods can be
751 # used to alter the string
824 # used to alter the string
752 @doctest
825 @doctest
753 In [2]: x.upper()
826 In [2]: x.upper()
754 Out[2]: 'HELLO WORLD'
827 Out[2]: 'HELLO WORLD'
755
828
756 @verbatim
829 @verbatim
757 In [3]: x.st<TAB>
830 In [3]: x.st<TAB>
758 x.startswith x.strip
831 x.startswith x.strip
759 """,
832 """,
760 r"""
833 r"""
761
834
762 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
835 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
763 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
836 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
764
837
765 In [131]: print url.split('&')
838 In [131]: print url.split('&')
766 ['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']
839 ['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']
767
840
768 In [60]: import urllib
841 In [60]: import urllib
769
842
770 """,
843 """,
771 r"""\
844 r"""\
772
845
773 In [133]: import numpy.random
846 In [133]: import numpy.random
774
847
775 @suppress
848 @suppress
776 In [134]: numpy.random.seed(2358)
849 In [134]: numpy.random.seed(2358)
777
850
778 @doctest
851 @doctest
779 In [135]: numpy.random.rand(10,2)
852 In [135]: numpy.random.rand(10,2)
780 Out[135]:
853 Out[135]:
781 array([[ 0.64524308, 0.59943846],
854 array([[ 0.64524308, 0.59943846],
782 [ 0.47102322, 0.8715456 ],
855 [ 0.47102322, 0.8715456 ],
783 [ 0.29370834, 0.74776844],
856 [ 0.29370834, 0.74776844],
784 [ 0.99539577, 0.1313423 ],
857 [ 0.99539577, 0.1313423 ],
785 [ 0.16250302, 0.21103583],
858 [ 0.16250302, 0.21103583],
786 [ 0.81626524, 0.1312433 ],
859 [ 0.81626524, 0.1312433 ],
787 [ 0.67338089, 0.72302393],
860 [ 0.67338089, 0.72302393],
788 [ 0.7566368 , 0.07033696],
861 [ 0.7566368 , 0.07033696],
789 [ 0.22591016, 0.77731835],
862 [ 0.22591016, 0.77731835],
790 [ 0.0072729 , 0.34273127]])
863 [ 0.0072729 , 0.34273127]])
791
864
792 """,
865 """,
793
866
794 r"""
867 r"""
795 In [106]: print x
868 In [106]: print x
796 jdh
869 jdh
797
870
798 In [109]: for i in range(10):
871 In [109]: for i in range(10):
799 .....: print i
872 .....: print i
800 .....:
873 .....:
801 .....:
874 .....:
802 0
875 0
803 1
876 1
804 2
877 2
805 3
878 3
806 4
879 4
807 5
880 5
808 6
881 6
809 7
882 7
810 8
883 8
811 9
884 9
812 """,
885 """,
813
886
814 r"""
887 r"""
815
888
816 In [144]: from pylab import *
889 In [144]: from pylab import *
817
890
818 In [145]: ion()
891 In [145]: ion()
819
892
820 # use a semicolon to suppress the output
893 # use a semicolon to suppress the output
821 @savefig test_hist.png width=4in
894 @savefig test_hist.png width=4in
822 In [151]: hist(np.random.randn(10000), 100);
895 In [151]: hist(np.random.randn(10000), 100);
823
896
824
897
825 @savefig test_plot.png width=4in
898 @savefig test_plot.png width=4in
826 In [151]: plot(np.random.randn(10000), 'o');
899 In [151]: plot(np.random.randn(10000), 'o');
827 """,
900 """,
828
901
829 r"""
902 r"""
830 # use a semicolon to suppress the output
903 # use a semicolon to suppress the output
831 In [151]: plt.clf()
904 In [151]: plt.clf()
832
905
833 @savefig plot_simple.png width=4in
906 @savefig plot_simple.png width=4in
834 In [151]: plot([1,2,3])
907 In [151]: plot([1,2,3])
835
908
836 @savefig hist_simple.png width=4in
909 @savefig hist_simple.png width=4in
837 In [151]: hist(np.random.randn(10000), 100);
910 In [151]: hist(np.random.randn(10000), 100);
838
911
839 """,
912 """,
840 r"""
913 r"""
841 # update the current fig
914 # update the current fig
842 In [151]: ylabel('number')
915 In [151]: ylabel('number')
843
916
844 In [152]: title('normal distribution')
917 In [152]: title('normal distribution')
845
918
846
919
847 @savefig hist_with_text.png
920 @savefig hist_with_text.png
848 In [153]: grid(True)
921 In [153]: grid(True)
849
922
923 @doctest float
924 In [154]: 0.1 + 0.2
925 Out[154]: 0.3
926
927 @doctest float
928 In [155]: np.arange(16).reshape(4,4)
929 Out[155]:
930 array([[ 0, 1, 2, 3],
931 [ 4, 5, 6, 7],
932 [ 8, 9, 10, 11],
933 [12, 13, 14, 15]])
934
935 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
936
937 In [2]: x[0,0] = np.inf
938
939 In [3]: x[0,1] = np.nan
940
941 @doctest float
942 In [4]: x
943 Out[4]:
944 array([[ inf, nan, 2., 3.],
945 [ 4., 5., 6., 7.],
946 [ 8., 9., 10., 11.],
947 [ 12., 13., 14., 15.]])
948
949
850 """,
950 """,
851 ]
951 ]
852 # skip local-file depending first example:
952 # skip local-file depending first example:
853 examples = examples[1:]
953 examples = examples[1:]
854
954
855 #ipython_directive.DEBUG = True # dbg
955 #ipython_directive.DEBUG = True # dbg
856 #options = dict(suppress=True) # dbg
956 #options = dict(suppress=True) # dbg
857 options = dict()
957 options = dict()
858 for example in examples:
958 for example in examples:
859 content = example.split('\n')
959 content = example.split('\n')
860 IPythonDirective('debug', arguments=None, options=options,
960 IPythonDirective('debug', arguments=None, options=options,
861 content=content, lineno=0,
961 content=content, lineno=0,
862 content_offset=None, block_text=None,
962 content_offset=None, block_text=None,
863 state=None, state_machine=None,
963 state=None, state_machine=None,
864 )
964 )
865
965
866 # Run test suite as a script
966 # Run test suite as a script
867 if __name__=='__main__':
967 if __name__=='__main__':
868 if not os.path.isdir('_static'):
968 if not os.path.isdir('_static'):
869 os.mkdir('_static')
969 os.mkdir('_static')
870 test()
970 test()
871 print('All OK? Check figures in _static/')
971 print('All OK? Check figures in _static/')
General Comments 0
You need to be logged in to leave comments. Login now