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