##// END OF EJS Templates
Refactor paste magics and ipdoctest
Thomas Kluyver -
Show More
@@ -1,204 +1,205 b''
1 1 """Tests for various magic functions specific to the terminal frontend.
2 2
3 3 Needs to be run by nose (to make ipython session available).
4 4 """
5 5 from __future__ import absolute_import
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Imports
9 9 #-----------------------------------------------------------------------------
10 10
11 11 import sys
12 12 from StringIO import StringIO
13 13 from unittest import TestCase
14 14
15 15 import nose.tools as nt
16 16
17 17 from IPython.testing import tools as tt
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Globals
21 21 #-----------------------------------------------------------------------------
22 22 ip = get_ipython()
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Test functions begin
26 26 #-----------------------------------------------------------------------------
27 27
28 28 def check_cpaste(code, should_fail=False):
29 29 """Execute code via 'cpaste' and ensure it was executed, unless
30 30 should_fail is set.
31 31 """
32 32 ip.user_ns['code_ran'] = False
33 33
34 34 src = StringIO()
35 35 if not hasattr(src, 'encoding'):
36 36 # IPython expects stdin to have an encoding attribute
37 37 src.encoding = None
38 38 src.write(code)
39 39 src.write('\n--\n')
40 40 src.seek(0)
41 41
42 42 stdin_save = sys.stdin
43 43 sys.stdin = src
44 44
45 45 try:
46 46 context = tt.AssertPrints if should_fail else tt.AssertNotPrints
47 47 with context("Traceback (most recent call last)"):
48 48 ip.magic('cpaste')
49 49
50 50 if not should_fail:
51 assert ip.user_ns['code_ran']
51 assert ip.user_ns['code_ran'], "%r failed" % code
52 52 finally:
53 53 sys.stdin = stdin_save
54 54
55 55 PY31 = sys.version_info[:2] == (3,1)
56 56
57 57 def test_cpaste():
58 58 """Test cpaste magic"""
59 59
60 60 def runf():
61 61 """Marker function: sets a flag when executed.
62 62 """
63 63 ip.user_ns['code_ran'] = True
64 64 return 'runf' # return string so '+ runf()' doesn't result in success
65 65
66 66 tests = {'pass': ["runf()",
67 67 "In [1]: runf()",
68 68 "In [1]: if 1:\n ...: runf()",
69 69 "> > > runf()",
70 70 ">>> runf()",
71 71 " >>> runf()",
72 72 ],
73 73
74 74 'fail': ["1 + runf()",
75 75 ]}
76 76
77 77 # I don't know why this is failing specifically on Python 3.1. I've
78 78 # checked it manually interactively, but we don't care enough about 3.1
79 79 # to spend time fiddling with the tests, so we just skip it.
80 80 if not PY31:
81 81 tests['fail'].append("++ runf()")
82 82
83 83 ip.user_ns['runf'] = runf
84 84
85 85 for code in tests['pass']:
86 86 check_cpaste(code)
87 87
88 88 for code in tests['fail']:
89 89 check_cpaste(code, should_fail=True)
90 90
91 91
92 92 class PasteTestCase(TestCase):
93 93 """Multiple tests for clipboard pasting"""
94 94
95 95 def paste(self, txt, flags='-q'):
96 96 """Paste input text, by default in quiet mode"""
97 97 ip.hooks.clipboard_get = lambda : txt
98 98 ip.magic('paste '+flags)
99 99
100 100 def setUp(self):
101 101 # Inject fake clipboard hook but save original so we can restore it later
102 102 self.original_clip = ip.hooks.clipboard_get
103 103
104 104 def tearDown(self):
105 105 # Restore original hook
106 106 ip.hooks.clipboard_get = self.original_clip
107 107
108 108 def test_paste(self):
109 109 ip.user_ns.pop('x', None)
110 110 self.paste('x = 1')
111 111 nt.assert_equal(ip.user_ns['x'], 1)
112 112 ip.user_ns.pop('x')
113 113
114 114 def test_paste_pyprompt(self):
115 115 ip.user_ns.pop('x', None)
116 116 self.paste('>>> x=2')
117 117 nt.assert_equal(ip.user_ns['x'], 2)
118 118 ip.user_ns.pop('x')
119 119
120 120 def test_paste_py_multi(self):
121 121 self.paste("""
122 122 >>> x = [1,2,3]
123 123 >>> y = []
124 124 >>> for i in x:
125 125 ... y.append(i**2)
126 126 ...
127 127 """)
128 128 nt.assert_equal(ip.user_ns['x'], [1,2,3])
129 129 nt.assert_equal(ip.user_ns['y'], [1,4,9])
130 130
131 131 def test_paste_py_multi_r(self):
132 132 "Now, test that self.paste -r works"
133 self.test_paste_py_multi()
133 134 nt.assert_equal(ip.user_ns.pop('x'), [1,2,3])
134 135 nt.assert_equal(ip.user_ns.pop('y'), [1,4,9])
135 136 nt.assert_false('x' in ip.user_ns)
136 137 ip.magic('paste -r')
137 138 nt.assert_equal(ip.user_ns['x'], [1,2,3])
138 139 nt.assert_equal(ip.user_ns['y'], [1,4,9])
139 140
140 141 def test_paste_email(self):
141 142 "Test pasting of email-quoted contents"
142 143 self.paste("""\
143 144 >> def foo(x):
144 145 >> return x + 1
145 146 >> xx = foo(1.1)""")
146 147 nt.assert_equal(ip.user_ns['xx'], 2.1)
147 148
148 149 def test_paste_email2(self):
149 150 "Email again; some programs add a space also at each quoting level"
150 151 self.paste("""\
151 152 > > def foo(x):
152 153 > > return x + 1
153 154 > > yy = foo(2.1) """)
154 155 nt.assert_equal(ip.user_ns['yy'], 3.1)
155 156
156 157 def test_paste_email_py(self):
157 158 "Email quoting of interactive input"
158 159 self.paste("""\
159 160 >> >>> def f(x):
160 161 >> ... return x+1
161 162 >> ...
162 163 >> >>> zz = f(2.5) """)
163 164 nt.assert_equal(ip.user_ns['zz'], 3.5)
164 165
165 166 def test_paste_echo(self):
166 167 "Also test self.paste echoing, by temporarily faking the writer"
167 168 w = StringIO()
168 169 writer = ip.write
169 170 ip.write = w.write
170 171 code = """
171 172 a = 100
172 173 b = 200"""
173 174 try:
174 175 self.paste(code,'')
175 176 out = w.getvalue()
176 177 finally:
177 178 ip.write = writer
178 179 nt.assert_equal(ip.user_ns['a'], 100)
179 180 nt.assert_equal(ip.user_ns['b'], 200)
180 181 nt.assert_equal(out, code+"\n## -- End pasted text --\n")
181 182
182 183 def test_paste_leading_commas(self):
183 184 "Test multiline strings with leading commas"
184 185 tm = ip.magics_manager.registry['TerminalMagics']
185 186 s = '''\
186 187 a = """
187 188 ,1,2,3
188 189 """'''
189 190 ip.user_ns.pop('foo', None)
190 191 tm.store_or_execute(s, 'foo')
191 192 nt.assert_in('foo', ip.user_ns)
192 193
193 194
194 195 def test_paste_trailing_question(self):
195 196 "Test pasting sources with trailing question marks"
196 197 tm = ip.magics_manager.registry['TerminalMagics']
197 198 s = '''\
198 199 def funcfoo():
199 200 if True: #am i true?
200 201 return 'fooresult'
201 202 '''
202 203 ip.user_ns.pop('funcfoo', None)
203 204 self.paste(s)
204 205 nt.assert_equal(ip.user_ns['funcfoo'](), 'fooresult')
@@ -1,753 +1,696 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Subclass of InteractiveShell for terminal based frontends."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 import bdb
19 19 import os
20 20 import re
21 21 import sys
22 22 import textwrap
23 23
24 24 # We need to use nested to support python 2.6, once we move to >=2.7, we can
25 25 # use the with keyword's new builtin support for nested managers
26 26 try:
27 27 from contextlib import nested
28 28 except:
29 29 from IPython.utils.nested_context import nested
30 30
31 31 from IPython.core.error import TryNext, UsageError
32 32 from IPython.core.usage import interactive_usage, default_banner
33 33 from IPython.core.inputsplitter import IPythonInputSplitter
34 34 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
35 35 from IPython.core.magic import Magics, magics_class, line_magic
36 36 from IPython.testing.skipdoctest import skip_doctest
37 37 from IPython.utils.encoding import get_stream_enc
38 38 from IPython.utils import py3compat
39 39 from IPython.utils.terminal import toggle_set_term_title, set_term_title
40 40 from IPython.utils.process import abbrev_cwd
41 41 from IPython.utils.warn import warn, error
42 42 from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes
43 43 from IPython.utils.traitlets import Integer, CBool, Unicode
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Utilities
47 47 #-----------------------------------------------------------------------------
48 48
49 49 def get_default_editor():
50 50 try:
51 51 ed = os.environ['EDITOR']
52 52 except KeyError:
53 53 if os.name == 'posix':
54 54 ed = 'vi' # the only one guaranteed to be there!
55 55 else:
56 56 ed = 'notepad' # same in Windows!
57 57 return ed
58 58
59 59
60 60 def get_pasted_lines(sentinel, l_input=py3compat.input):
61 61 """ Yield pasted lines until the user enters the given sentinel value.
62 62 """
63 63 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
64 64 % sentinel)
65 65 while True:
66 66 try:
67 67 l = l_input(':')
68 68 if l == sentinel:
69 69 return
70 70 else:
71 71 yield l
72 72 except EOFError:
73 73 print('<EOF>')
74 74 return
75 75
76 76
77 77 #------------------------------------------------------------------------
78 78 # Terminal-specific magics
79 79 #------------------------------------------------------------------------
80 80
81 81 @magics_class
82 82 class TerminalMagics(Magics):
83 83 def __init__(self, shell):
84 84 super(TerminalMagics, self).__init__(shell)
85 85 self.input_splitter = IPythonInputSplitter()
86
87 def cleanup_input(self, block):
88 """Apply all possible IPython cleanups to an input block.
89
90 This means:
91
92 - remove any global leading whitespace (dedent)
93 - remove any email quotes ('>') if they are present in *all* lines
94 - apply all static inputsplitter transforms and break into sub-blocks
95 - apply prefilter() to each sub-block that is a single line.
96
97 Parameters
98 ----------
99 block : str
100 A possibly multiline input string of code.
101
102 Returns
103 -------
104 transformed block : str
105 The input, with all transformations above applied.
106 """
107 # We have to effectively implement client-side the loop that is done by
108 # the terminal frontend, and furthermore do it on a block that can
109 # possibly contain multiple statments pasted in one go.
110
111 # First, run the input through the block splitting code. We should
112 # eventually make this a self-contained method in the inputsplitter.
113 isp = self.input_splitter
114 isp.reset()
115 b = textwrap.dedent(block)
116
117 # Remove email quotes first. These must be consistently applied to
118 # *all* lines to be removed
119 b = strip_email_quotes(b)
120
121 # Split the input into independent sub-blocks so we can later do
122 # prefiltering (which must be done *only* to single-line inputs)
123 blocks = []
124 last_block = []
125 for line in b.splitlines():
126 isp.push(line)
127 last_block.append(line)
128 if not isp.push_accepts_more():
129 blocks.append(isp.source_reset())
130 last_block = []
131 if last_block:
132 blocks.append('\n'.join(last_block))
133
134 # Now, apply prefiltering to any one-line block to match the behavior
135 # of the interactive terminal
136 final_blocks = []
137 for block in blocks:
138 lines = block.splitlines()
139 if len(lines) == 1:
140 final_blocks.append(self.shell.prefilter(lines[0]))
141 else:
142 final_blocks.append(block)
143
144 # We now have the final version of the input code as a list of blocks,
145 # with all inputsplitter transformations applied and single-line blocks
146 # run through prefilter. For further processing, turn into a single
147 # string as the rest of our apis use string inputs.
148 return '\n'.join(final_blocks)
149 86
150 87 def store_or_execute(self, block, name):
151 88 """ Execute a block, or store it in a variable, per the user's request.
152 89 """
153 90 if name:
154 91 # If storing it for further editing
155 92 self.shell.user_ns[name] = SList(block.splitlines())
156 93 print("Block assigned to '%s'" % name)
157 94 else:
158 self.shell.user_ns['pasted_block'] = block
159 b = self.shell.input_transformer_manager.transform_cell(block)
95 b = self.preclean_input(block)
96 self.shell.user_ns['pasted_block'] = b
160 97 self.shell.using_paste_magics = True
161 98 try:
162 99 self.shell.run_cell(b)
163 100 finally:
164 101 self.shell.using_paste_magics = False
102
103 def preclean_input(self, block):
104 lines = block.splitlines()
105 while lines and not lines[0].strip():
106 lines = lines[1:]
107 return strip_email_quotes('\n'.join(lines))
165 108
166 109 def rerun_pasted(self, name='pasted_block'):
167 110 """ Rerun a previously pasted command.
168 111 """
169 112 b = self.shell.user_ns.get(name)
170 113
171 114 # Sanity checks
172 115 if b is None:
173 116 raise UsageError('No previous pasted block available')
174 117 if not isinstance(b, basestring):
175 118 raise UsageError(
176 119 "Variable 'pasted_block' is not a string, can't execute")
177 120
178 121 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
179 122 self.shell.run_cell(b)
180 123
181 124 @line_magic
182 125 def autoindent(self, parameter_s = ''):
183 126 """Toggle autoindent on/off (if available)."""
184 127
185 128 self.shell.set_autoindent()
186 129 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
187 130
188 131 @skip_doctest
189 132 @line_magic
190 133 def cpaste(self, parameter_s=''):
191 134 """Paste & execute a pre-formatted code block from clipboard.
192 135
193 136 You must terminate the block with '--' (two minus-signs) or Ctrl-D
194 137 alone on the line. You can also provide your own sentinel with '%paste
195 138 -s %%' ('%%' is the new sentinel for this operation)
196 139
197 140 The block is dedented prior to execution to enable execution of method
198 141 definitions. '>' and '+' characters at the beginning of a line are
199 142 ignored, to allow pasting directly from e-mails, diff files and
200 143 doctests (the '...' continuation prompt is also stripped). The
201 144 executed block is also assigned to variable named 'pasted_block' for
202 145 later editing with '%edit pasted_block'.
203 146
204 147 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
205 148 This assigns the pasted block to variable 'foo' as string, without
206 149 dedenting or executing it (preceding >>> and + is still stripped)
207 150
208 151 '%cpaste -r' re-executes the block previously entered by cpaste.
209 152
210 153 Do not be alarmed by garbled output on Windows (it's a readline bug).
211 154 Just press enter and type -- (and press enter again) and the block
212 155 will be what was just pasted.
213 156
214 157 IPython statements (magics, shell escapes) are not supported (yet).
215 158
216 159 See also
217 160 --------
218 161 paste: automatically pull code from clipboard.
219 162
220 163 Examples
221 164 --------
222 165 ::
223 166
224 167 In [8]: %cpaste
225 168 Pasting code; enter '--' alone on the line to stop.
226 169 :>>> a = ["world!", "Hello"]
227 170 :>>> print " ".join(sorted(a))
228 171 :--
229 172 Hello world!
230 173 """
231 174 opts, name = self.parse_options(parameter_s, 'rs:', mode='string')
232 175 if 'r' in opts:
233 176 self.rerun_pasted()
234 177 return
235 178
236 179 sentinel = opts.get('s', '--')
237 180 block = '\n'.join(get_pasted_lines(sentinel))
238 181 self.store_or_execute(block, name)
239 182
240 183 @line_magic
241 184 def paste(self, parameter_s=''):
242 185 """Paste & execute a pre-formatted code block from clipboard.
243 186
244 187 The text is pulled directly from the clipboard without user
245 188 intervention and printed back on the screen before execution (unless
246 189 the -q flag is given to force quiet mode).
247 190
248 191 The block is dedented prior to execution to enable execution of method
249 192 definitions. '>' and '+' characters at the beginning of a line are
250 193 ignored, to allow pasting directly from e-mails, diff files and
251 194 doctests (the '...' continuation prompt is also stripped). The
252 195 executed block is also assigned to variable named 'pasted_block' for
253 196 later editing with '%edit pasted_block'.
254 197
255 198 You can also pass a variable name as an argument, e.g. '%paste foo'.
256 199 This assigns the pasted block to variable 'foo' as string, without
257 200 executing it (preceding >>> and + is still stripped).
258 201
259 202 Options
260 203 -------
261 204
262 205 -r: re-executes the block previously entered by cpaste.
263 206
264 207 -q: quiet mode: do not echo the pasted text back to the terminal.
265 208
266 209 IPython statements (magics, shell escapes) are not supported (yet).
267 210
268 211 See also
269 212 --------
270 213 cpaste: manually paste code into terminal until you mark its end.
271 214 """
272 215 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
273 216 if 'r' in opts:
274 217 self.rerun_pasted()
275 218 return
276 219 try:
277 220 block = self.shell.hooks.clipboard_get()
278 221 except TryNext as clipboard_exc:
279 222 message = getattr(clipboard_exc, 'args')
280 223 if message:
281 224 error(message[0])
282 225 else:
283 226 error('Could not get text from the clipboard.')
284 227 return
285 228
286 229 # By default, echo back to terminal unless quiet mode is requested
287 230 if 'q' not in opts:
288 231 write = self.shell.write
289 232 write(self.shell.pycolorize(block))
290 233 if not block.endswith('\n'):
291 234 write('\n')
292 235 write("## -- End pasted text --\n")
293 236
294 237 self.store_or_execute(block, name)
295 238
296 239 # Class-level: add a '%cls' magic only on Windows
297 240 if sys.platform == 'win32':
298 241 @line_magic
299 242 def cls(self, s):
300 243 """Clear screen.
301 244 """
302 245 os.system("cls")
303 246
304 247 #-----------------------------------------------------------------------------
305 248 # Main class
306 249 #-----------------------------------------------------------------------------
307 250
308 251 class TerminalInteractiveShell(InteractiveShell):
309 252
310 253 autoedit_syntax = CBool(False, config=True,
311 254 help="auto editing of files with syntax errors.")
312 255 banner = Unicode('')
313 256 banner1 = Unicode(default_banner, config=True,
314 257 help="""The part of the banner to be printed before the profile"""
315 258 )
316 259 banner2 = Unicode('', config=True,
317 260 help="""The part of the banner to be printed after the profile"""
318 261 )
319 262 confirm_exit = CBool(True, config=True,
320 263 help="""
321 264 Set to confirm when you try to exit IPython with an EOF (Control-D
322 265 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
323 266 you can force a direct exit without any confirmation.""",
324 267 )
325 268 # This display_banner only controls whether or not self.show_banner()
326 269 # is called when mainloop/interact are called. The default is False
327 270 # because for the terminal based application, the banner behavior
328 271 # is controlled by Global.display_banner, which IPythonApp looks at
329 272 # to determine if *it* should call show_banner() by hand or not.
330 273 display_banner = CBool(False) # This isn't configurable!
331 274 embedded = CBool(False)
332 275 embedded_active = CBool(False)
333 276 editor = Unicode(get_default_editor(), config=True,
334 277 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
335 278 )
336 279 pager = Unicode('less', config=True,
337 280 help="The shell program to be used for paging.")
338 281
339 282 screen_length = Integer(0, config=True,
340 283 help=
341 284 """Number of lines of your screen, used to control printing of very
342 285 long strings. Strings longer than this number of lines will be sent
343 286 through a pager instead of directly printed. The default value for
344 287 this is 0, which means IPython will auto-detect your screen size every
345 288 time it needs to print certain potentially long strings (this doesn't
346 289 change the behavior of the 'print' keyword, it's only triggered
347 290 internally). If for some reason this isn't working well (it needs
348 291 curses support), specify it yourself. Otherwise don't change the
349 292 default.""",
350 293 )
351 294 term_title = CBool(False, config=True,
352 295 help="Enable auto setting the terminal title."
353 296 )
354 297
355 298 # This `using_paste_magics` is used to detect whether the code is being
356 299 # executed via paste magics functions
357 300 using_paste_magics = CBool(False)
358 301
359 302 # In the terminal, GUI control is done via PyOS_InputHook
360 303 @staticmethod
361 304 def enable_gui(gui=None, app=None):
362 305 """Switch amongst GUI input hooks by name.
363 306 """
364 307 # Deferred import
365 308 from IPython.lib.inputhook import enable_gui as real_enable_gui
366 309 return real_enable_gui(gui, app)
367 310
368 311 def __init__(self, config=None, ipython_dir=None, profile_dir=None,
369 312 user_ns=None, user_module=None, custom_exceptions=((),None),
370 313 usage=None, banner1=None, banner2=None, display_banner=None,
371 314 **kwargs):
372 315
373 316 super(TerminalInteractiveShell, self).__init__(
374 317 config=config, ipython_dir=ipython_dir, profile_dir=profile_dir, user_ns=user_ns,
375 318 user_module=user_module, custom_exceptions=custom_exceptions,
376 319 **kwargs
377 320 )
378 321 # use os.system instead of utils.process.system by default,
379 322 # because piped system doesn't make sense in the Terminal:
380 323 self.system = self.system_raw
381 324
382 325 self.init_term_title()
383 326 self.init_usage(usage)
384 327 self.init_banner(banner1, banner2, display_banner)
385 328
386 329 #-------------------------------------------------------------------------
387 330 # Overrides of init stages
388 331 #-------------------------------------------------------------------------
389 332
390 333 def init_display_formatter(self):
391 334 super(TerminalInteractiveShell, self).init_display_formatter()
392 335 # terminal only supports plaintext
393 336 self.display_formatter.active_types = ['text/plain']
394 337
395 338 #-------------------------------------------------------------------------
396 339 # Things related to the terminal
397 340 #-------------------------------------------------------------------------
398 341
399 342 @property
400 343 def usable_screen_length(self):
401 344 if self.screen_length == 0:
402 345 return 0
403 346 else:
404 347 num_lines_bot = self.separate_in.count('\n')+1
405 348 return self.screen_length - num_lines_bot
406 349
407 350 def init_term_title(self):
408 351 # Enable or disable the terminal title.
409 352 if self.term_title:
410 353 toggle_set_term_title(True)
411 354 set_term_title('IPython: ' + abbrev_cwd())
412 355 else:
413 356 toggle_set_term_title(False)
414 357
415 358 #-------------------------------------------------------------------------
416 359 # Things related to aliases
417 360 #-------------------------------------------------------------------------
418 361
419 362 def init_alias(self):
420 363 # The parent class defines aliases that can be safely used with any
421 364 # frontend.
422 365 super(TerminalInteractiveShell, self).init_alias()
423 366
424 367 # Now define aliases that only make sense on the terminal, because they
425 368 # need direct access to the console in a way that we can't emulate in
426 369 # GUI or web frontend
427 370 if os.name == 'posix':
428 371 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
429 372 ('man', 'man')]
430 373 elif os.name == 'nt':
431 374 aliases = [('cls', 'cls')]
432 375
433 376
434 377 for name, cmd in aliases:
435 378 self.alias_manager.define_alias(name, cmd)
436 379
437 380 #-------------------------------------------------------------------------
438 381 # Things related to the banner and usage
439 382 #-------------------------------------------------------------------------
440 383
441 384 def _banner1_changed(self):
442 385 self.compute_banner()
443 386
444 387 def _banner2_changed(self):
445 388 self.compute_banner()
446 389
447 390 def _term_title_changed(self, name, new_value):
448 391 self.init_term_title()
449 392
450 393 def init_banner(self, banner1, banner2, display_banner):
451 394 if banner1 is not None:
452 395 self.banner1 = banner1
453 396 if banner2 is not None:
454 397 self.banner2 = banner2
455 398 if display_banner is not None:
456 399 self.display_banner = display_banner
457 400 self.compute_banner()
458 401
459 402 def show_banner(self, banner=None):
460 403 if banner is None:
461 404 banner = self.banner
462 405 self.write(banner)
463 406
464 407 def compute_banner(self):
465 408 self.banner = self.banner1
466 409 if self.profile and self.profile != 'default':
467 410 self.banner += '\nIPython profile: %s\n' % self.profile
468 411 if self.banner2:
469 412 self.banner += '\n' + self.banner2
470 413
471 414 def init_usage(self, usage=None):
472 415 if usage is None:
473 416 self.usage = interactive_usage
474 417 else:
475 418 self.usage = usage
476 419
477 420 #-------------------------------------------------------------------------
478 421 # Mainloop and code execution logic
479 422 #-------------------------------------------------------------------------
480 423
481 424 def mainloop(self, display_banner=None):
482 425 """Start the mainloop.
483 426
484 427 If an optional banner argument is given, it will override the
485 428 internally created default banner.
486 429 """
487 430
488 431 with nested(self.builtin_trap, self.display_trap):
489 432
490 433 while 1:
491 434 try:
492 435 self.interact(display_banner=display_banner)
493 436 #self.interact_with_readline()
494 437 # XXX for testing of a readline-decoupled repl loop, call
495 438 # interact_with_readline above
496 439 break
497 440 except KeyboardInterrupt:
498 441 # this should not be necessary, but KeyboardInterrupt
499 442 # handling seems rather unpredictable...
500 443 self.write("\nKeyboardInterrupt in interact()\n")
501 444
502 445 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
503 446 """Store multiple lines as a single entry in history"""
504 447
505 448 # do nothing without readline or disabled multiline
506 449 if not self.has_readline or not self.multiline_history:
507 450 return hlen_before_cell
508 451
509 452 # windows rl has no remove_history_item
510 453 if not hasattr(self.readline, "remove_history_item"):
511 454 return hlen_before_cell
512 455
513 456 # skip empty cells
514 457 if not source_raw.rstrip():
515 458 return hlen_before_cell
516 459
517 460 # nothing changed do nothing, e.g. when rl removes consecutive dups
518 461 hlen = self.readline.get_current_history_length()
519 462 if hlen == hlen_before_cell:
520 463 return hlen_before_cell
521 464
522 465 for i in range(hlen - hlen_before_cell):
523 466 self.readline.remove_history_item(hlen - i - 1)
524 467 stdin_encoding = get_stream_enc(sys.stdin, 'utf-8')
525 468 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
526 469 stdin_encoding))
527 470 return self.readline.get_current_history_length()
528 471
529 472 def interact(self, display_banner=None):
530 473 """Closely emulate the interactive Python console."""
531 474
532 475 # batch run -> do not interact
533 476 if self.exit_now:
534 477 return
535 478
536 479 if display_banner is None:
537 480 display_banner = self.display_banner
538 481
539 482 if isinstance(display_banner, basestring):
540 483 self.show_banner(display_banner)
541 484 elif display_banner:
542 485 self.show_banner()
543 486
544 487 more = False
545 488
546 489 if self.has_readline:
547 490 self.readline_startup_hook(self.pre_readline)
548 491 hlen_b4_cell = self.readline.get_current_history_length()
549 492 else:
550 493 hlen_b4_cell = 0
551 494 # exit_now is set by a call to %Exit or %Quit, through the
552 495 # ask_exit callback.
553 496
554 497 while not self.exit_now:
555 498 self.hooks.pre_prompt_hook()
556 499 if more:
557 500 try:
558 501 prompt = self.prompt_manager.render('in2')
559 502 except:
560 503 self.showtraceback()
561 504 if self.autoindent:
562 505 self.rl_do_indent = True
563 506
564 507 else:
565 508 try:
566 509 prompt = self.separate_in + self.prompt_manager.render('in')
567 510 except:
568 511 self.showtraceback()
569 512 try:
570 513 line = self.raw_input(prompt)
571 514 if self.exit_now:
572 515 # quick exit on sys.std[in|out] close
573 516 break
574 517 if self.autoindent:
575 518 self.rl_do_indent = False
576 519
577 520 except KeyboardInterrupt:
578 521 #double-guard against keyboardinterrupts during kbdint handling
579 522 try:
580 523 self.write('\nKeyboardInterrupt\n')
581 524 source_raw = self.input_splitter.source_raw_reset()[1]
582 525 hlen_b4_cell = \
583 526 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
584 527 more = False
585 528 except KeyboardInterrupt:
586 529 pass
587 530 except EOFError:
588 531 if self.autoindent:
589 532 self.rl_do_indent = False
590 533 if self.has_readline:
591 534 self.readline_startup_hook(None)
592 535 self.write('\n')
593 536 self.exit()
594 537 except bdb.BdbQuit:
595 538 warn('The Python debugger has exited with a BdbQuit exception.\n'
596 539 'Because of how pdb handles the stack, it is impossible\n'
597 540 'for IPython to properly format this particular exception.\n'
598 541 'IPython will resume normal operation.')
599 542 except:
600 543 # exceptions here are VERY RARE, but they can be triggered
601 544 # asynchronously by signal handlers, for example.
602 545 self.showtraceback()
603 546 else:
604 547 self.input_splitter.push(line)
605 548 more = self.input_splitter.push_accepts_more()
606 549 if (self.SyntaxTB.last_syntax_error and
607 550 self.autoedit_syntax):
608 551 self.edit_syntax_error()
609 552 if not more:
610 553 source_raw = self.input_splitter.source_raw_reset()[1]
611 554 self.run_cell(source_raw, store_history=True)
612 555 hlen_b4_cell = \
613 556 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
614 557
615 558 # Turn off the exit flag, so the mainloop can be restarted if desired
616 559 self.exit_now = False
617 560
618 561 def raw_input(self, prompt=''):
619 562 """Write a prompt and read a line.
620 563
621 564 The returned line does not include the trailing newline.
622 565 When the user enters the EOF key sequence, EOFError is raised.
623 566
624 567 Optional inputs:
625 568
626 569 - prompt(''): a string to be printed to prompt the user.
627 570
628 571 - continue_prompt(False): whether this line is the first one or a
629 572 continuation in a sequence of inputs.
630 573 """
631 574 # Code run by the user may have modified the readline completer state.
632 575 # We must ensure that our completer is back in place.
633 576
634 577 if self.has_readline:
635 578 self.set_readline_completer()
636 579
637 580 # raw_input expects str, but we pass it unicode sometimes
638 581 prompt = py3compat.cast_bytes_py2(prompt)
639 582
640 583 try:
641 584 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
642 585 except ValueError:
643 586 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
644 587 " or sys.stdout.close()!\nExiting IPython!\n")
645 588 self.ask_exit()
646 589 return ""
647 590
648 591 # Try to be reasonably smart about not re-indenting pasted input more
649 592 # than necessary. We do this by trimming out the auto-indent initial
650 593 # spaces, if the user's actual input started itself with whitespace.
651 594 if self.autoindent:
652 595 if num_ini_spaces(line) > self.indent_current_nsp:
653 596 line = line[self.indent_current_nsp:]
654 597 self.indent_current_nsp = 0
655 598
656 599 return line
657 600
658 601 #-------------------------------------------------------------------------
659 602 # Methods to support auto-editing of SyntaxErrors.
660 603 #-------------------------------------------------------------------------
661 604
662 605 def edit_syntax_error(self):
663 606 """The bottom half of the syntax error handler called in the main loop.
664 607
665 608 Loop until syntax error is fixed or user cancels.
666 609 """
667 610
668 611 while self.SyntaxTB.last_syntax_error:
669 612 # copy and clear last_syntax_error
670 613 err = self.SyntaxTB.clear_err_state()
671 614 if not self._should_recompile(err):
672 615 return
673 616 try:
674 617 # may set last_syntax_error again if a SyntaxError is raised
675 618 self.safe_execfile(err.filename,self.user_ns)
676 619 except:
677 620 self.showtraceback()
678 621 else:
679 622 try:
680 623 f = open(err.filename)
681 624 try:
682 625 # This should be inside a display_trap block and I
683 626 # think it is.
684 627 sys.displayhook(f.read())
685 628 finally:
686 629 f.close()
687 630 except:
688 631 self.showtraceback()
689 632
690 633 def _should_recompile(self,e):
691 634 """Utility routine for edit_syntax_error"""
692 635
693 636 if e.filename in ('<ipython console>','<input>','<string>',
694 637 '<console>','<BackgroundJob compilation>',
695 638 None):
696 639
697 640 return False
698 641 try:
699 642 if (self.autoedit_syntax and
700 643 not self.ask_yes_no('Return to editor to correct syntax error? '
701 644 '[Y/n] ','y')):
702 645 return False
703 646 except EOFError:
704 647 return False
705 648
706 649 def int0(x):
707 650 try:
708 651 return int(x)
709 652 except TypeError:
710 653 return 0
711 654 # always pass integer line and offset values to editor hook
712 655 try:
713 656 self.hooks.fix_error_editor(e.filename,
714 657 int0(e.lineno),int0(e.offset),e.msg)
715 658 except TryNext:
716 659 warn('Could not open editor')
717 660 return False
718 661 return True
719 662
720 663 #-------------------------------------------------------------------------
721 664 # Things related to exiting
722 665 #-------------------------------------------------------------------------
723 666
724 667 def ask_exit(self):
725 668 """ Ask the shell to exit. Can be overiden and used as a callback. """
726 669 self.exit_now = True
727 670
728 671 def exit(self):
729 672 """Handle interactive exit.
730 673
731 674 This method calls the ask_exit callback."""
732 675 if self.confirm_exit:
733 676 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
734 677 self.ask_exit()
735 678 else:
736 679 self.ask_exit()
737 680
738 681 #-------------------------------------------------------------------------
739 682 # Things related to magics
740 683 #-------------------------------------------------------------------------
741 684
742 685 def init_magics(self):
743 686 super(TerminalInteractiveShell, self).init_magics()
744 687 self.register_magics(TerminalMagics)
745 688
746 689 def showindentationerror(self):
747 690 super(TerminalInteractiveShell, self).showindentationerror()
748 691 if not self.using_paste_magics:
749 692 print("If you want to paste code into IPython, try the "
750 693 "%paste and %cpaste magic functions.")
751 694
752 695
753 696 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -1,807 +1,807 b''
1 1 """Nose Plugin that supports IPython doctests.
2 2
3 3 Limitations:
4 4
5 5 - When generating examples for use as doctests, make sure that you have
6 6 pretty-printing OFF. This can be done either by setting the
7 7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 8 by interactively disabling it with %Pprint. This is required so that IPython
9 9 output matches that of normal Python, which is used by doctest for internal
10 10 execution.
11 11
12 12 - Do not rely on specific prompt numbers for results (such as using
13 13 '_34==True', for example). For IPython tests run via an external process the
14 14 prompt numbers may be different, and IPython tests run as normal python code
15 15 won't even have these special _NN variables set at all.
16 16 """
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Module imports
20 20
21 21 # From the standard library
22 22 import __builtin__ as builtin_mod
23 23 import commands
24 24 import doctest
25 25 import inspect
26 26 import logging
27 27 import os
28 28 import re
29 29 import sys
30 30 import traceback
31 31 import unittest
32 32
33 33 from inspect import getmodule
34 34 from StringIO import StringIO
35 35
36 36 # We are overriding the default doctest runner, so we need to import a few
37 37 # things from doctest directly
38 38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 39 _unittest_reportflags, DocTestRunner,
40 40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 41 _exception_traceback,
42 42 linecache)
43 43
44 44 # Third-party modules
45 45 import nose.core
46 46
47 47 from nose.plugins import doctests, Plugin
48 48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49 49
50 50 # Our own imports
51 51
52 # We're temporarily using TerminalMagics.cleanup_input() until the functionality
53 # is moved into core.
54 from IPython.frontend.terminal.interactiveshell import TerminalMagics
55
56 52 #-----------------------------------------------------------------------------
57 53 # Module globals and other constants
58 54 #-----------------------------------------------------------------------------
59 55
60 56 log = logging.getLogger(__name__)
61 57
62 58
63 59 #-----------------------------------------------------------------------------
64 60 # Classes and functions
65 61 #-----------------------------------------------------------------------------
66 62
67 63 def is_extension_module(filename):
68 64 """Return whether the given filename is an extension module.
69 65
70 66 This simply checks that the extension is either .so or .pyd.
71 67 """
72 68 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
73 69
74 70
75 71 class DocTestSkip(object):
76 72 """Object wrapper for doctests to be skipped."""
77 73
78 74 ds_skip = """Doctest to skip.
79 75 >>> 1 #doctest: +SKIP
80 76 """
81 77
82 78 def __init__(self,obj):
83 79 self.obj = obj
84 80
85 81 def __getattribute__(self,key):
86 82 if key == '__doc__':
87 83 return DocTestSkip.ds_skip
88 84 else:
89 85 return getattr(object.__getattribute__(self,'obj'),key)
90 86
91 87 # Modified version of the one in the stdlib, that fixes a python bug (doctests
92 88 # not found in extension modules, http://bugs.python.org/issue3158)
93 89 class DocTestFinder(doctest.DocTestFinder):
94 90
95 91 def _from_module(self, module, object):
96 92 """
97 93 Return true if the given object is defined in the given
98 94 module.
99 95 """
100 96 if module is None:
101 97 return True
102 98 elif inspect.isfunction(object):
103 99 return module.__dict__ is object.func_globals
104 100 elif inspect.isbuiltin(object):
105 101 return module.__name__ == object.__module__
106 102 elif inspect.isclass(object):
107 103 return module.__name__ == object.__module__
108 104 elif inspect.ismethod(object):
109 105 # This one may be a bug in cython that fails to correctly set the
110 106 # __module__ attribute of methods, but since the same error is easy
111 107 # to make by extension code writers, having this safety in place
112 108 # isn't such a bad idea
113 109 return module.__name__ == object.im_class.__module__
114 110 elif inspect.getmodule(object) is not None:
115 111 return module is inspect.getmodule(object)
116 112 elif hasattr(object, '__module__'):
117 113 return module.__name__ == object.__module__
118 114 elif isinstance(object, property):
119 115 return True # [XX] no way not be sure.
120 116 else:
121 117 raise ValueError("object must be a class or function")
122 118
123 119 def _find(self, tests, obj, name, module, source_lines, globs, seen):
124 120 """
125 121 Find tests for the given object and any contained objects, and
126 122 add them to `tests`.
127 123 """
128 124 #print '_find for:', obj, name, module # dbg
129 125 if hasattr(obj,"skip_doctest"):
130 126 #print 'SKIPPING DOCTEST FOR:',obj # dbg
131 127 obj = DocTestSkip(obj)
132 128
133 129 doctest.DocTestFinder._find(self,tests, obj, name, module,
134 130 source_lines, globs, seen)
135 131
136 132 # Below we re-run pieces of the above method with manual modifications,
137 133 # because the original code is buggy and fails to correctly identify
138 134 # doctests in extension modules.
139 135
140 136 # Local shorthands
141 137 from inspect import isroutine, isclass, ismodule
142 138
143 139 # Look for tests in a module's contained objects.
144 140 if inspect.ismodule(obj) and self._recurse:
145 141 for valname, val in obj.__dict__.items():
146 142 valname1 = '%s.%s' % (name, valname)
147 143 if ( (isroutine(val) or isclass(val))
148 144 and self._from_module(module, val) ):
149 145
150 146 self._find(tests, val, valname1, module, source_lines,
151 147 globs, seen)
152 148
153 149 # Look for tests in a class's contained objects.
154 150 if inspect.isclass(obj) and self._recurse:
155 151 #print 'RECURSE into class:',obj # dbg
156 152 for valname, val in obj.__dict__.items():
157 153 # Special handling for staticmethod/classmethod.
158 154 if isinstance(val, staticmethod):
159 155 val = getattr(obj, valname)
160 156 if isinstance(val, classmethod):
161 157 val = getattr(obj, valname).im_func
162 158
163 159 # Recurse to methods, properties, and nested classes.
164 160 if ((inspect.isfunction(val) or inspect.isclass(val) or
165 161 inspect.ismethod(val) or
166 162 isinstance(val, property)) and
167 163 self._from_module(module, val)):
168 164 valname = '%s.%s' % (name, valname)
169 165 self._find(tests, val, valname, module, source_lines,
170 166 globs, seen)
171 167
172 168
173 169 class IPDoctestOutputChecker(doctest.OutputChecker):
174 170 """Second-chance checker with support for random tests.
175 171
176 172 If the default comparison doesn't pass, this checker looks in the expected
177 173 output string for flags that tell us to ignore the output.
178 174 """
179 175
180 176 random_re = re.compile(r'#\s*random\s+')
181 177
182 178 def check_output(self, want, got, optionflags):
183 179 """Check output, accepting special markers embedded in the output.
184 180
185 181 If the output didn't pass the default validation but the special string
186 182 '#random' is included, we accept it."""
187 183
188 184 # Let the original tester verify first, in case people have valid tests
189 185 # that happen to have a comment saying '#random' embedded in.
190 186 ret = doctest.OutputChecker.check_output(self, want, got,
191 187 optionflags)
192 188 if not ret and self.random_re.search(want):
193 189 #print >> sys.stderr, 'RANDOM OK:',want # dbg
194 190 return True
195 191
196 192 return ret
197 193
198 194
199 195 class DocTestCase(doctests.DocTestCase):
200 196 """Proxy for DocTestCase: provides an address() method that
201 197 returns the correct address for the doctest case. Otherwise
202 198 acts as a proxy to the test case. To provide hints for address(),
203 199 an obj may also be passed -- this will be used as the test object
204 200 for purposes of determining the test address, if it is provided.
205 201 """
206 202
207 203 # Note: this method was taken from numpy's nosetester module.
208 204
209 205 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
210 206 # its constructor that blocks non-default arguments from being passed
211 207 # down into doctest.DocTestCase
212 208
213 209 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
214 210 checker=None, obj=None, result_var='_'):
215 211 self._result_var = result_var
216 212 doctests.DocTestCase.__init__(self, test,
217 213 optionflags=optionflags,
218 214 setUp=setUp, tearDown=tearDown,
219 215 checker=checker)
220 216 # Now we must actually copy the original constructor from the stdlib
221 217 # doctest class, because we can't call it directly and a bug in nose
222 218 # means it never gets passed the right arguments.
223 219
224 220 self._dt_optionflags = optionflags
225 221 self._dt_checker = checker
226 222 self._dt_test = test
227 223 self._dt_test_globs_ori = test.globs
228 224 self._dt_setUp = setUp
229 225 self._dt_tearDown = tearDown
230 226
231 227 # XXX - store this runner once in the object!
232 228 runner = IPDocTestRunner(optionflags=optionflags,
233 229 checker=checker, verbose=False)
234 230 self._dt_runner = runner
235 231
236 232
237 233 # Each doctest should remember the directory it was loaded from, so
238 234 # things like %run work without too many contortions
239 235 self._ori_dir = os.path.dirname(test.filename)
240 236
241 237 # Modified runTest from the default stdlib
242 238 def runTest(self):
243 239 test = self._dt_test
244 240 runner = self._dt_runner
245 241
246 242 old = sys.stdout
247 243 new = StringIO()
248 244 optionflags = self._dt_optionflags
249 245
250 246 if not (optionflags & REPORTING_FLAGS):
251 247 # The option flags don't include any reporting flags,
252 248 # so add the default reporting flags
253 249 optionflags |= _unittest_reportflags
254 250
255 251 try:
256 252 # Save our current directory and switch out to the one where the
257 253 # test was originally created, in case another doctest did a
258 254 # directory change. We'll restore this in the finally clause.
259 255 curdir = os.getcwdu()
260 256 #print 'runTest in dir:', self._ori_dir # dbg
261 257 os.chdir(self._ori_dir)
262 258
263 259 runner.DIVIDER = "-"*70
264 260 failures, tries = runner.run(test,out=new.write,
265 261 clear_globs=False)
266 262 finally:
267 263 sys.stdout = old
268 264 os.chdir(curdir)
269 265
270 266 if failures:
271 267 raise self.failureException(self.format_failure(new.getvalue()))
272 268
273 269 def setUp(self):
274 270 """Modified test setup that syncs with ipython namespace"""
275 271 #print "setUp test", self._dt_test.examples # dbg
276 272 if isinstance(self._dt_test.examples[0], IPExample):
277 273 # for IPython examples *only*, we swap the globals with the ipython
278 274 # namespace, after updating it with the globals (which doctest
279 275 # fills with the necessary info from the module being tested).
280 276 self.user_ns_orig = {}
281 277 self.user_ns_orig.update(_ip.user_ns)
282 278 _ip.user_ns.update(self._dt_test.globs)
283 279 # We must remove the _ key in the namespace, so that Python's
284 280 # doctest code sets it naturally
285 281 _ip.user_ns.pop('_', None)
286 282 _ip.user_ns['__builtins__'] = builtin_mod
287 283 self._dt_test.globs = _ip.user_ns
288 284
289 285 super(DocTestCase, self).setUp()
290 286
291 287 def tearDown(self):
292 288
293 289 # Undo the test.globs reassignment we made, so that the parent class
294 290 # teardown doesn't destroy the ipython namespace
295 291 if isinstance(self._dt_test.examples[0], IPExample):
296 292 self._dt_test.globs = self._dt_test_globs_ori
297 293 _ip.user_ns.clear()
298 294 _ip.user_ns.update(self.user_ns_orig)
299 295
300 296 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
301 297 # it does look like one to me: its tearDown method tries to run
302 298 #
303 299 # delattr(__builtin__, self._result_var)
304 300 #
305 301 # without checking that the attribute really is there; it implicitly
306 302 # assumes it should have been set via displayhook. But if the
307 303 # displayhook was never called, this doesn't necessarily happen. I
308 304 # haven't been able to find a little self-contained example outside of
309 305 # ipython that would show the problem so I can report it to the nose
310 306 # team, but it does happen a lot in our code.
311 307 #
312 308 # So here, we just protect as narrowly as possible by trapping an
313 309 # attribute error whose message would be the name of self._result_var,
314 310 # and letting any other error propagate.
315 311 try:
316 312 super(DocTestCase, self).tearDown()
317 313 except AttributeError as exc:
318 314 if exc.args[0] != self._result_var:
319 315 raise
320 316
321 317
322 318 # A simple subclassing of the original with a different class name, so we can
323 319 # distinguish and treat differently IPython examples from pure python ones.
324 320 class IPExample(doctest.Example): pass
325 321
326 322
327 323 class IPExternalExample(doctest.Example):
328 324 """Doctest examples to be run in an external process."""
329 325
330 326 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
331 327 options=None):
332 328 # Parent constructor
333 329 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
334 330
335 331 # An EXTRA newline is needed to prevent pexpect hangs
336 332 self.source += '\n'
337 333
338 334
339 335 class IPDocTestParser(doctest.DocTestParser):
340 336 """
341 337 A class used to parse strings containing doctest examples.
342 338
343 339 Note: This is a version modified to properly recognize IPython input and
344 340 convert any IPython examples into valid Python ones.
345 341 """
346 342 # This regular expression is used to find doctest examples in a
347 343 # string. It defines three groups: `source` is the source code
348 344 # (including leading indentation and prompts); `indent` is the
349 345 # indentation of the first (PS1) line of the source code; and
350 346 # `want` is the expected output (including leading indentation).
351 347
352 348 # Classic Python prompts or default IPython ones
353 349 _PS1_PY = r'>>>'
354 350 _PS2_PY = r'\.\.\.'
355 351
356 352 _PS1_IP = r'In\ \[\d+\]:'
357 353 _PS2_IP = r'\ \ \ \.\.\.+:'
358 354
359 355 _RE_TPL = r'''
360 356 # Source consists of a PS1 line followed by zero or more PS2 lines.
361 357 (?P<source>
362 358 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
363 359 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
364 360 \n? # a newline
365 361 # Want consists of any non-blank lines that do not start with PS1.
366 362 (?P<want> (?:(?![ ]*$) # Not a blank line
367 363 (?![ ]*%s) # Not a line starting with PS1
368 364 (?![ ]*%s) # Not a line starting with PS2
369 365 .*$\n? # But any other line
370 366 )*)
371 367 '''
372 368
373 369 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
374 370 re.MULTILINE | re.VERBOSE)
375 371
376 372 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
377 373 re.MULTILINE | re.VERBOSE)
378 374
379 375 # Mark a test as being fully random. In this case, we simply append the
380 376 # random marker ('#random') to each individual example's output. This way
381 377 # we don't need to modify any other code.
382 378 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
383 379
384 380 # Mark tests to be executed in an external process - currently unsupported.
385 381 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
386 382
387 383 def ip2py(self,source):
388 384 """Convert input IPython source into valid Python."""
389 return TerminalMagics(_ip).cleanup_input(source)
385 block = _ip.input_transformer_manager.transform_cell(source)
386 if len(block.splitlines()) == 1:
387 return _ip.prefilter(block)
388 else:
389 return block
390 390
391 391 def parse(self, string, name='<string>'):
392 392 """
393 393 Divide the given string into examples and intervening text,
394 394 and return them as a list of alternating Examples and strings.
395 395 Line numbers for the Examples are 0-based. The optional
396 396 argument `name` is a name identifying this string, and is only
397 397 used for error messages.
398 398 """
399 399
400 400 #print 'Parse string:\n',string # dbg
401 401
402 402 string = string.expandtabs()
403 403 # If all lines begin with the same indentation, then strip it.
404 404 min_indent = self._min_indent(string)
405 405 if min_indent > 0:
406 406 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
407 407
408 408 output = []
409 409 charno, lineno = 0, 0
410 410
411 411 # We make 'all random' tests by adding the '# random' mark to every
412 412 # block of output in the test.
413 413 if self._RANDOM_TEST.search(string):
414 414 random_marker = '\n# random'
415 415 else:
416 416 random_marker = ''
417 417
418 418 # Whether to convert the input from ipython to python syntax
419 419 ip2py = False
420 420 # Find all doctest examples in the string. First, try them as Python
421 421 # examples, then as IPython ones
422 422 terms = list(self._EXAMPLE_RE_PY.finditer(string))
423 423 if terms:
424 424 # Normal Python example
425 425 #print '-'*70 # dbg
426 426 #print 'PyExample, Source:\n',string # dbg
427 427 #print '-'*70 # dbg
428 428 Example = doctest.Example
429 429 else:
430 430 # It's an ipython example. Note that IPExamples are run
431 431 # in-process, so their syntax must be turned into valid python.
432 432 # IPExternalExamples are run out-of-process (via pexpect) so they
433 433 # don't need any filtering (a real ipython will be executing them).
434 434 terms = list(self._EXAMPLE_RE_IP.finditer(string))
435 435 if self._EXTERNAL_IP.search(string):
436 436 #print '-'*70 # dbg
437 437 #print 'IPExternalExample, Source:\n',string # dbg
438 438 #print '-'*70 # dbg
439 439 Example = IPExternalExample
440 440 else:
441 441 #print '-'*70 # dbg
442 442 #print 'IPExample, Source:\n',string # dbg
443 443 #print '-'*70 # dbg
444 444 Example = IPExample
445 445 ip2py = True
446 446
447 447 for m in terms:
448 448 # Add the pre-example text to `output`.
449 449 output.append(string[charno:m.start()])
450 450 # Update lineno (lines before this example)
451 451 lineno += string.count('\n', charno, m.start())
452 452 # Extract info from the regexp match.
453 453 (source, options, want, exc_msg) = \
454 454 self._parse_example(m, name, lineno,ip2py)
455 455
456 456 # Append the random-output marker (it defaults to empty in most
457 457 # cases, it's only non-empty for 'all-random' tests):
458 458 want += random_marker
459 459
460 460 if Example is IPExternalExample:
461 461 options[doctest.NORMALIZE_WHITESPACE] = True
462 462 want += '\n'
463 463
464 464 # Create an Example, and add it to the list.
465 465 if not self._IS_BLANK_OR_COMMENT(source):
466 466 output.append(Example(source, want, exc_msg,
467 467 lineno=lineno,
468 468 indent=min_indent+len(m.group('indent')),
469 469 options=options))
470 470 # Update lineno (lines inside this example)
471 471 lineno += string.count('\n', m.start(), m.end())
472 472 # Update charno.
473 473 charno = m.end()
474 474 # Add any remaining post-example text to `output`.
475 475 output.append(string[charno:])
476 476 return output
477 477
478 478 def _parse_example(self, m, name, lineno,ip2py=False):
479 479 """
480 480 Given a regular expression match from `_EXAMPLE_RE` (`m`),
481 481 return a pair `(source, want)`, where `source` is the matched
482 482 example's source code (with prompts and indentation stripped);
483 483 and `want` is the example's expected output (with indentation
484 484 stripped).
485 485
486 486 `name` is the string's name, and `lineno` is the line number
487 487 where the example starts; both are used for error messages.
488 488
489 489 Optional:
490 490 `ip2py`: if true, filter the input via IPython to convert the syntax
491 491 into valid python.
492 492 """
493 493
494 494 # Get the example's indentation level.
495 495 indent = len(m.group('indent'))
496 496
497 497 # Divide source into lines; check that they're properly
498 498 # indented; and then strip their indentation & prompts.
499 499 source_lines = m.group('source').split('\n')
500 500
501 501 # We're using variable-length input prompts
502 502 ps1 = m.group('ps1')
503 503 ps2 = m.group('ps2')
504 504 ps1_len = len(ps1)
505 505
506 506 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
507 507 if ps2:
508 508 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
509 509
510 510 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
511 511
512 512 if ip2py:
513 513 # Convert source input from IPython into valid Python syntax
514 514 source = self.ip2py(source)
515 515
516 516 # Divide want into lines; check that it's properly indented; and
517 517 # then strip the indentation. Spaces before the last newline should
518 518 # be preserved, so plain rstrip() isn't good enough.
519 519 want = m.group('want')
520 520 want_lines = want.split('\n')
521 521 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
522 522 del want_lines[-1] # forget final newline & spaces after it
523 523 self._check_prefix(want_lines, ' '*indent, name,
524 524 lineno + len(source_lines))
525 525
526 526 # Remove ipython output prompt that might be present in the first line
527 527 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
528 528
529 529 want = '\n'.join([wl[indent:] for wl in want_lines])
530 530
531 531 # If `want` contains a traceback message, then extract it.
532 532 m = self._EXCEPTION_RE.match(want)
533 533 if m:
534 534 exc_msg = m.group('msg')
535 535 else:
536 536 exc_msg = None
537 537
538 538 # Extract options from the source.
539 539 options = self._find_options(source, name, lineno)
540 540
541 541 return source, options, want, exc_msg
542 542
543 543 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
544 544 """
545 545 Given the lines of a source string (including prompts and
546 546 leading indentation), check to make sure that every prompt is
547 547 followed by a space character. If any line is not followed by
548 548 a space character, then raise ValueError.
549 549
550 550 Note: IPython-modified version which takes the input prompt length as a
551 551 parameter, so that prompts of variable length can be dealt with.
552 552 """
553 553 space_idx = indent+ps1_len
554 554 min_len = space_idx+1
555 555 for i, line in enumerate(lines):
556 556 if len(line) >= min_len and line[space_idx] != ' ':
557 557 raise ValueError('line %r of the docstring for %s '
558 558 'lacks blank after %s: %r' %
559 559 (lineno+i+1, name,
560 560 line[indent:space_idx], line))
561 561
562 562
563 563 SKIP = doctest.register_optionflag('SKIP')
564 564
565 565
566 566 class IPDocTestRunner(doctest.DocTestRunner,object):
567 567 """Test runner that synchronizes the IPython namespace with test globals.
568 568 """
569 569
570 570 def run(self, test, compileflags=None, out=None, clear_globs=True):
571 571
572 572 # Hack: ipython needs access to the execution context of the example,
573 573 # so that it can propagate user variables loaded by %run into
574 574 # test.globs. We put them here into our modified %run as a function
575 575 # attribute. Our new %run will then only make the namespace update
576 576 # when called (rather than unconconditionally updating test.globs here
577 577 # for all examples, most of which won't be calling %run anyway).
578 578 #_ip._ipdoctest_test_globs = test.globs
579 579 #_ip._ipdoctest_test_filename = test.filename
580 580
581 581 test.globs.update(_ip.user_ns)
582 582
583 583 return super(IPDocTestRunner,self).run(test,
584 584 compileflags,out,clear_globs)
585 585
586 586
587 587 class DocFileCase(doctest.DocFileCase):
588 588 """Overrides to provide filename
589 589 """
590 590 def address(self):
591 591 return (self._dt_test.filename, None, None)
592 592
593 593
594 594 class ExtensionDoctest(doctests.Doctest):
595 595 """Nose Plugin that supports doctests in extension modules.
596 596 """
597 597 name = 'extdoctest' # call nosetests with --with-extdoctest
598 598 enabled = True
599 599
600 600 def __init__(self,exclude_patterns=None):
601 601 """Create a new ExtensionDoctest plugin.
602 602
603 603 Parameters
604 604 ----------
605 605
606 606 exclude_patterns : sequence of strings, optional
607 607 These patterns are compiled as regular expressions, subsequently used
608 608 to exclude any filename which matches them from inclusion in the test
609 609 suite (using pattern.search(), NOT pattern.match() ).
610 610 """
611 611
612 612 if exclude_patterns is None:
613 613 exclude_patterns = []
614 614 self.exclude_patterns = map(re.compile,exclude_patterns)
615 615 doctests.Doctest.__init__(self)
616 616
617 617 def options(self, parser, env=os.environ):
618 618 Plugin.options(self, parser, env)
619 619 parser.add_option('--doctest-tests', action='store_true',
620 620 dest='doctest_tests',
621 621 default=env.get('NOSE_DOCTEST_TESTS',True),
622 622 help="Also look for doctests in test modules. "
623 623 "Note that classes, methods and functions should "
624 624 "have either doctests or non-doctest tests, "
625 625 "not both. [NOSE_DOCTEST_TESTS]")
626 626 parser.add_option('--doctest-extension', action="append",
627 627 dest="doctestExtension",
628 628 help="Also look for doctests in files with "
629 629 "this extension [NOSE_DOCTEST_EXTENSION]")
630 630 # Set the default as a list, if given in env; otherwise
631 631 # an additional value set on the command line will cause
632 632 # an error.
633 633 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
634 634 if env_setting is not None:
635 635 parser.set_defaults(doctestExtension=tolist(env_setting))
636 636
637 637
638 638 def configure(self, options, config):
639 639 Plugin.configure(self, options, config)
640 640 # Pull standard doctest plugin out of config; we will do doctesting
641 641 config.plugins.plugins = [p for p in config.plugins.plugins
642 642 if p.name != 'doctest']
643 643 self.doctest_tests = options.doctest_tests
644 644 self.extension = tolist(options.doctestExtension)
645 645
646 646 self.parser = doctest.DocTestParser()
647 647 self.finder = DocTestFinder()
648 648 self.checker = IPDoctestOutputChecker()
649 649 self.globs = None
650 650 self.extraglobs = None
651 651
652 652
653 653 def loadTestsFromExtensionModule(self,filename):
654 654 bpath,mod = os.path.split(filename)
655 655 modname = os.path.splitext(mod)[0]
656 656 try:
657 657 sys.path.append(bpath)
658 658 module = __import__(modname)
659 659 tests = list(self.loadTestsFromModule(module))
660 660 finally:
661 661 sys.path.pop()
662 662 return tests
663 663
664 664 # NOTE: the method below is almost a copy of the original one in nose, with
665 665 # a few modifications to control output checking.
666 666
667 667 def loadTestsFromModule(self, module):
668 668 #print '*** ipdoctest - lTM',module # dbg
669 669
670 670 if not self.matches(module.__name__):
671 671 log.debug("Doctest doesn't want module %s", module)
672 672 return
673 673
674 674 tests = self.finder.find(module,globs=self.globs,
675 675 extraglobs=self.extraglobs)
676 676 if not tests:
677 677 return
678 678
679 679 # always use whitespace and ellipsis options
680 680 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
681 681
682 682 tests.sort()
683 683 module_file = module.__file__
684 684 if module_file[-4:] in ('.pyc', '.pyo'):
685 685 module_file = module_file[:-1]
686 686 for test in tests:
687 687 if not test.examples:
688 688 continue
689 689 if not test.filename:
690 690 test.filename = module_file
691 691
692 692 yield DocTestCase(test,
693 693 optionflags=optionflags,
694 694 checker=self.checker)
695 695
696 696
697 697 def loadTestsFromFile(self, filename):
698 698 #print "ipdoctest - from file", filename # dbg
699 699 if is_extension_module(filename):
700 700 for t in self.loadTestsFromExtensionModule(filename):
701 701 yield t
702 702 else:
703 703 if self.extension and anyp(filename.endswith, self.extension):
704 704 name = os.path.basename(filename)
705 705 dh = open(filename)
706 706 try:
707 707 doc = dh.read()
708 708 finally:
709 709 dh.close()
710 710 test = self.parser.get_doctest(
711 711 doc, globs={'__file__': filename}, name=name,
712 712 filename=filename, lineno=0)
713 713 if test.examples:
714 714 #print 'FileCase:',test.examples # dbg
715 715 yield DocFileCase(test)
716 716 else:
717 717 yield False # no tests to load
718 718
719 719 def wantFile(self,filename):
720 720 """Return whether the given filename should be scanned for tests.
721 721
722 722 Modified version that accepts extension modules as valid containers for
723 723 doctests.
724 724 """
725 725 #print '*** ipdoctest- wantFile:',filename # dbg
726 726
727 727 for pat in self.exclude_patterns:
728 728 if pat.search(filename):
729 729 # print '###>>> SKIP:',filename # dbg
730 730 return False
731 731
732 732 if is_extension_module(filename):
733 733 return True
734 734 else:
735 735 return doctests.Doctest.wantFile(self,filename)
736 736
737 737 def wantDirectory(self, directory):
738 738 """Return whether the given directory should be scanned for tests.
739 739
740 740 Modified version that supports exclusions.
741 741 """
742 742
743 743 for pat in self.exclude_patterns:
744 744 if pat.search(directory):
745 745 return False
746 746 return True
747 747
748 748
749 749 class IPythonDoctest(ExtensionDoctest):
750 750 """Nose Plugin that supports doctests in extension modules.
751 751 """
752 752 name = 'ipdoctest' # call nosetests with --with-ipdoctest
753 753 enabled = True
754 754
755 755 def makeTest(self, obj, parent):
756 756 """Look for doctests in the given object, which will be a
757 757 function, method or class.
758 758 """
759 759 #print 'Plugin analyzing:', obj, parent # dbg
760 760 # always use whitespace and ellipsis options
761 761 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
762 762
763 763 doctests = self.finder.find(obj, module=getmodule(parent))
764 764 if doctests:
765 765 for test in doctests:
766 766 if len(test.examples) == 0:
767 767 continue
768 768
769 769 yield DocTestCase(test, obj=obj,
770 770 optionflags=optionflags,
771 771 checker=self.checker)
772 772
773 773 def options(self, parser, env=os.environ):
774 774 #print "Options for nose plugin:", self.name # dbg
775 775 Plugin.options(self, parser, env)
776 776 parser.add_option('--ipdoctest-tests', action='store_true',
777 777 dest='ipdoctest_tests',
778 778 default=env.get('NOSE_IPDOCTEST_TESTS',True),
779 779 help="Also look for doctests in test modules. "
780 780 "Note that classes, methods and functions should "
781 781 "have either doctests or non-doctest tests, "
782 782 "not both. [NOSE_IPDOCTEST_TESTS]")
783 783 parser.add_option('--ipdoctest-extension', action="append",
784 784 dest="ipdoctest_extension",
785 785 help="Also look for doctests in files with "
786 786 "this extension [NOSE_IPDOCTEST_EXTENSION]")
787 787 # Set the default as a list, if given in env; otherwise
788 788 # an additional value set on the command line will cause
789 789 # an error.
790 790 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
791 791 if env_setting is not None:
792 792 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
793 793
794 794 def configure(self, options, config):
795 795 #print "Configuring nose plugin:", self.name # dbg
796 796 Plugin.configure(self, options, config)
797 797 # Pull standard doctest plugin out of config; we will do doctesting
798 798 config.plugins.plugins = [p for p in config.plugins.plugins
799 799 if p.name != 'doctest']
800 800 self.doctest_tests = options.ipdoctest_tests
801 801 self.extension = tolist(options.ipdoctest_extension)
802 802
803 803 self.parser = IPDocTestParser()
804 804 self.finder = DocTestFinder(parser=self.parser)
805 805 self.checker = IPDoctestOutputChecker()
806 806 self.globs = None
807 807 self.extraglobs = None
General Comments 0
You need to be logged in to leave comments. Login now