##// END OF EJS Templates
Vastly cleaner solution for the namespace problem!
Fernando Perez -
Show More
@@ -1,955 +1,738 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 starting ipython with the
7 7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
8 8 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 - IPython functions that produce output as a side-effect of calling a system
18 18 process (e.g. 'ls') can be doc-tested, but they must be handled in an
19 19 external IPython process. Such doctests must be tagged with:
20 20
21 21 # ipdoctest: EXTERNAL
22 22
23 23 so that the testing machinery handles them differently. Since these are run
24 24 via pexpect in an external process, they can't deal with exceptions or other
25 25 fancy featurs of regular doctests. You must limit such tests to simple
26 26 matching of the output. For this reason, I recommend you limit these kinds
27 27 of doctests to features that truly require a separate process, and use the
28 28 normal IPython ones (which have all the features of normal doctests) for
29 29 everything else. See the examples at the bottom of this file for a
30 30 comparison of what can be done with both types.
31 31 """
32 32
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Module imports
36 36
37 37 # From the standard library
38 38 import __builtin__
39 39 import commands
40 40 import doctest
41 41 import inspect
42 42 import logging
43 43 import os
44 44 import re
45 45 import sys
46 46 import traceback
47 47 import unittest
48 48
49 49 from inspect import getmodule
50 50 from StringIO import StringIO
51 51
52 52 # We are overriding the default doctest runner, so we need to import a few
53 53 # things from doctest directly
54 54 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
55 55 _unittest_reportflags, DocTestRunner,
56 56 _extract_future_flags, pdb, _OutputRedirectingPdb,
57 57 _exception_traceback,
58 58 linecache)
59 59
60 60 # Third-party modules
61 61 import nose.core
62 62
63 63 from nose.plugins import doctests, Plugin
64 64 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
65 65
66 66 # Our own imports
67 67 #from extdoctest import ExtensionDoctest, DocTestFinder
68 68 #from dttools import DocTestFinder, DocTestCase
69 69 #-----------------------------------------------------------------------------
70 70 # Module globals and other constants
71 71
72 72 log = logging.getLogger(__name__)
73 73
74 74 ###########################################################################
75 75 # *** HACK ***
76 76 # We must start our own ipython object and heavily muck with it so that all the
77 77 # modifications IPython makes to system behavior don't send the doctest
78 78 # machinery into a fit. This code should be considered a gross hack, but it
79 79 # gets the job done.
80 80
81 81 class ncdict(dict):
82 82 """Non-copying dict class.
83 83
84 84 This is a special-purpose dict subclass that overrides the .copy() method
85 85 to return the original object itself. We need it to ensure that doctests
86 86 happen in the IPython namespace, but doctest always makes a shallow copy of
87 87 the given globals for execution. Since we actually *want* this namespace
88 88 to be persistent (this is how the user's session maintains state), we
89 89 simply fool doctest by returning the original object upoon copy.
90 90 """
91 91
92 92 def copy(self):
93 93 return self
94 94
95 95
96 96 # XXX - Hack to modify the %run command so we can sync the user's namespace
97 97 # with the test globals. Once we move over to a clean magic system, this will
98 98 # be done with much less ugliness.
99 99
100 100 def _run_ns_sync(self,arg_s,runner=None):
101 101 """Modified version of %run that syncs testing namespaces.
102 102
103 103 This is strictly needed for running doctests that call %run.
104 104 """
105 105
106 106 out = _ip.IP.magic_run_ori(arg_s,runner)
107 107 _run_ns_sync.test_globs.update(_ip.user_ns)
108 108 return out
109 109
110 110
111 111 def start_ipython():
112 112 """Start a global IPython shell, which we need for IPython-specific syntax.
113 113 """
114 114 import new
115 115
116 116 import IPython
117 117
118 118 def xsys(cmd):
119 119 """Execute a command and print its output.
120 120
121 121 This is just a convenience function to replace the IPython system call
122 122 with one that is more doctest-friendly.
123 123 """
124 124 cmd = _ip.IP.var_expand(cmd,depth=1)
125 125 sys.stdout.write(commands.getoutput(cmd))
126 126 sys.stdout.flush()
127 127
128 128 # Store certain global objects that IPython modifies
129 129 _displayhook = sys.displayhook
130 130 _excepthook = sys.excepthook
131 131 _main = sys.modules.get('__main__')
132 132
133 133 # Start IPython instance. We customize it to start with minimal frills and
134 134 # with our own namespace.
135 135 argv = ['--classic','--noterm_title']
136 136 user_ns = ncdict()
137 137 IPython.Shell.IPShell(argv,user_ns)
138 138
139 139 # Deactivate the various python system hooks added by ipython for
140 140 # interactive convenience so we don't confuse the doctest system
141 141 sys.modules['__main__'] = _main
142 142 sys.displayhook = _displayhook
143 143 sys.excepthook = _excepthook
144 144
145 145 # So that ipython magics and aliases can be doctested (they work by making
146 146 # a call into a global _ip object)
147 147 _ip = IPython.ipapi.get()
148 148 __builtin__._ip = _ip
149 149
150 150 # Modify the IPython system call with one that uses getoutput, so that we
151 151 # can capture subcommands and print them to Python's stdout, otherwise the
152 152 # doctest machinery would miss them.
153 153 _ip.system = xsys
154 154
155 155 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
156 156 _ip.IP.magic_run_ori = _ip.IP.magic_run
157 157 _ip.IP.magic_run = im
158 158
159 159 # The start call MUST be made here. I'm not sure yet why it doesn't work if
160 160 # it is made later, at plugin initialization time, but in all my tests, that's
161 161 # the case.
162 162 start_ipython()
163 163
164 164 # *** END HACK ***
165 165 ###########################################################################
166 166
167 167 # Classes and functions
168 168
169 169 def is_extension_module(filename):
170 170 """Return whether the given filename is an extension module.
171 171
172 172 This simply checks that the extension is either .so or .pyd.
173 173 """
174 174 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
175 175
176 176
177 177 # Modified version of the one in the stdlib, that fixes a python bug (doctests
178 178 # not found in extension modules, http://bugs.python.org/issue3158)
179 179 class DocTestFinder(doctest.DocTestFinder):
180 180
181 181 def _from_module(self, module, object):
182 182 """
183 183 Return true if the given object is defined in the given
184 184 module.
185 185 """
186 186 if module is None:
187 187 #print '_fm C1' # dbg
188 188 return True
189 189 elif inspect.isfunction(object):
190 190 #print '_fm C2' # dbg
191 191 return module.__dict__ is object.func_globals
192 192 elif inspect.isbuiltin(object):
193 193 #print '_fm C2-1' # dbg
194 194 return module.__name__ == object.__module__
195 195 elif inspect.isclass(object):
196 196 #print '_fm C3' # dbg
197 197 return module.__name__ == object.__module__
198 198 elif inspect.ismethod(object):
199 199 # This one may be a bug in cython that fails to correctly set the
200 200 # __module__ attribute of methods, but since the same error is easy
201 201 # to make by extension code writers, having this safety in place
202 202 # isn't such a bad idea
203 203 #print '_fm C3-1' # dbg
204 204 return module.__name__ == object.im_class.__module__
205 205 elif inspect.getmodule(object) is not None:
206 206 #print '_fm C4' # dbg
207 207 #print 'C4 mod',module,'obj',object # dbg
208 208 return module is inspect.getmodule(object)
209 209 elif hasattr(object, '__module__'):
210 210 #print '_fm C5' # dbg
211 211 return module.__name__ == object.__module__
212 212 elif isinstance(object, property):
213 213 #print '_fm C6' # dbg
214 214 return True # [XX] no way not be sure.
215 215 else:
216 216 raise ValueError("object must be a class or function")
217 217
218 218 def _find(self, tests, obj, name, module, source_lines, globs, seen):
219 219 """
220 220 Find tests for the given object and any contained objects, and
221 221 add them to `tests`.
222 222 """
223 223
224 224 doctest.DocTestFinder._find(self,tests, obj, name, module,
225 225 source_lines, globs, seen)
226 226
227 227 # Below we re-run pieces of the above method with manual modifications,
228 228 # because the original code is buggy and fails to correctly identify
229 229 # doctests in extension modules.
230 230
231 231 # Local shorthands
232 232 from inspect import isroutine, isclass, ismodule
233 233
234 234 # Look for tests in a module's contained objects.
235 235 if inspect.ismodule(obj) and self._recurse:
236 236 for valname, val in obj.__dict__.items():
237 237 valname1 = '%s.%s' % (name, valname)
238 238 if ( (isroutine(val) or isclass(val))
239 239 and self._from_module(module, val) ):
240 240
241 241 self._find(tests, val, valname1, module, source_lines,
242 242 globs, seen)
243 243
244 244 # Look for tests in a class's contained objects.
245 245 if inspect.isclass(obj) and self._recurse:
246 246 #print 'RECURSE into class:',obj # dbg
247 247 for valname, val in obj.__dict__.items():
248 248 #valname1 = '%s.%s' % (name, valname) # dbg
249 249 #print 'N',name,'VN:',valname,'val:',str(val)[:77] # dbg
250 250 # Special handling for staticmethod/classmethod.
251 251 if isinstance(val, staticmethod):
252 252 val = getattr(obj, valname)
253 253 if isinstance(val, classmethod):
254 254 val = getattr(obj, valname).im_func
255 255
256 256 # Recurse to methods, properties, and nested classes.
257 257 if ((inspect.isfunction(val) or inspect.isclass(val) or
258 258 inspect.ismethod(val) or
259 259 isinstance(val, property)) and
260 260 self._from_module(module, val)):
261 261 valname = '%s.%s' % (name, valname)
262 262 self._find(tests, val, valname, module, source_lines,
263 263 globs, seen)
264 264
265 265
266 266 # second-chance checker; if the default comparison doesn't
267 267 # pass, then see if the expected output string contains flags that
268 268 # tell us to ignore the output
269 269 class IPDoctestOutputChecker(doctest.OutputChecker):
270 270 def check_output(self, want, got, optionflags):
271 271 #print '*** My Checker!' # dbg
272 272
273 273 ret = doctest.OutputChecker.check_output(self, want, got,
274 274 optionflags)
275 275 if not ret:
276 276 if "#random" in want:
277 277 return True
278 278
279 279 return ret
280 280
281 281
282 282 class DocTestCase(doctests.DocTestCase):
283 283 """Proxy for DocTestCase: provides an address() method that
284 284 returns the correct address for the doctest case. Otherwise
285 285 acts as a proxy to the test case. To provide hints for address(),
286 286 an obj may also be passed -- this will be used as the test object
287 287 for purposes of determining the test address, if it is provided.
288 288 """
289 289
290 290 # Note: this method was taken from numpy's nosetester module.
291 291
292 292 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
293 293 # its constructor that blocks non-default arguments from being passed
294 294 # down into doctest.DocTestCase
295 295
296 296 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
297 297 checker=None, obj=None, result_var='_'):
298 298 self._result_var = result_var
299 299 doctests.DocTestCase.__init__(self, test,
300 300 optionflags=optionflags,
301 301 setUp=setUp, tearDown=tearDown,
302 302 checker=checker)
303 303 # Now we must actually copy the original constructor from the stdlib
304 304 # doctest class, because we can't call it directly and a bug in nose
305 305 # means it never gets passed the right arguments.
306 306
307 307 self._dt_optionflags = optionflags
308 308 self._dt_checker = checker
309 309 self._dt_test = test
310 310 self._dt_setUp = setUp
311 311 self._dt_tearDown = tearDown
312 312
313 313 # Modified runTest from the default stdlib
314 314 def runTest(self):
315 315 #print 'HERE!' # dbg
316 316
317 317 test = self._dt_test
318 318 old = sys.stdout
319 319 new = StringIO()
320 320 optionflags = self._dt_optionflags
321 321
322 322 if not (optionflags & REPORTING_FLAGS):
323 323 # The option flags don't include any reporting flags,
324 324 # so add the default reporting flags
325 325 optionflags |= _unittest_reportflags
326 326
327 327 runner = IPDocTestRunner(optionflags=optionflags,
328 328 checker=self._dt_checker, verbose=False)
329 329
330 330 try:
331 331 runner.DIVIDER = "-"*70
332 332 failures, tries = runner.run(
333 333 test, out=new.write, clear_globs=False)
334 334 finally:
335 335 sys.stdout = old
336 336
337 337 if failures:
338 338 raise self.failureException(self.format_failure(new.getvalue()))
339 339
340 340
341 341 # A simple subclassing of the original with a different class name, so we can
342 342 # distinguish and treat differently IPython examples from pure python ones.
343 343 class IPExample(doctest.Example): pass
344 344
345 345
346 346 class IPExternalExample(doctest.Example):
347 347 """Doctest examples to be run in an external process."""
348 348
349 349 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
350 350 options=None):
351 351 # Parent constructor
352 352 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
353 353
354 354 # An EXTRA newline is needed to prevent pexpect hangs
355 355 self.source += '\n'
356 356
357 357
358 358 class IPDocTestParser(doctest.DocTestParser):
359 359 """
360 360 A class used to parse strings containing doctest examples.
361 361
362 362 Note: This is a version modified to properly recognize IPython input and
363 363 convert any IPython examples into valid Python ones.
364 364 """
365 365 # This regular expression is used to find doctest examples in a
366 366 # string. It defines three groups: `source` is the source code
367 367 # (including leading indentation and prompts); `indent` is the
368 368 # indentation of the first (PS1) line of the source code; and
369 369 # `want` is the expected output (including leading indentation).
370 370
371 371 # Classic Python prompts or default IPython ones
372 372 _PS1_PY = r'>>>'
373 373 _PS2_PY = r'\.\.\.'
374 374
375 375 _PS1_IP = r'In\ \[\d+\]:'
376 376 _PS2_IP = r'\ \ \ \.\.\.+:'
377 377
378 378 _RE_TPL = r'''
379 379 # Source consists of a PS1 line followed by zero or more PS2 lines.
380 380 (?P<source>
381 381 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
382 382 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
383 383 \n? # a newline
384 384 # Want consists of any non-blank lines that do not start with PS1.
385 385 (?P<want> (?:(?![ ]*$) # Not a blank line
386 386 (?![ ]*%s) # Not a line starting with PS1
387 387 (?![ ]*%s) # Not a line starting with PS2
388 388 .*$\n? # But any other line
389 389 )*)
390 390 '''
391 391
392 392 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
393 393 re.MULTILINE | re.VERBOSE)
394 394
395 395 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
396 396 re.MULTILINE | re.VERBOSE)
397 397
398 398 def ip2py(self,source):
399 399 """Convert input IPython source into valid Python."""
400 400 out = []
401 401 newline = out.append
402 402 for lnum,line in enumerate(source.splitlines()):
403 403 newline(_ip.IP.prefilter(line,lnum>0))
404 404 newline('') # ensure a closing newline, needed by doctest
405 405 #print "PYSRC:", '\n'.join(out) # dbg
406 406 return '\n'.join(out)
407 407
408 408 def parse(self, string, name='<string>'):
409 409 """
410 410 Divide the given string into examples and intervening text,
411 411 and return them as a list of alternating Examples and strings.
412 412 Line numbers for the Examples are 0-based. The optional
413 413 argument `name` is a name identifying this string, and is only
414 414 used for error messages.
415 415 """
416 416
417 417 #print 'Parse string:\n',string # dbg
418 418
419 419 string = string.expandtabs()
420 420 # If all lines begin with the same indentation, then strip it.
421 421 min_indent = self._min_indent(string)
422 422 if min_indent > 0:
423 423 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
424 424
425 425 output = []
426 426 charno, lineno = 0, 0
427 427
428 428 # Whether to convert the input from ipython to python syntax
429 429 ip2py = False
430 430 # Find all doctest examples in the string. First, try them as Python
431 431 # examples, then as IPython ones
432 432 terms = list(self._EXAMPLE_RE_PY.finditer(string))
433 433 if terms:
434 434 # Normal Python example
435 435 #print '-'*70 # dbg
436 436 #print 'PyExample, Source:\n',string # dbg
437 437 #print '-'*70 # dbg
438 438 Example = doctest.Example
439 439 else:
440 440 # It's an ipython example. Note that IPExamples are run
441 441 # in-process, so their syntax must be turned into valid python.
442 442 # IPExternalExamples are run out-of-process (via pexpect) so they
443 443 # don't need any filtering (a real ipython will be executing them).
444 444 terms = list(self._EXAMPLE_RE_IP.finditer(string))
445 445 if re.search(r'#\s*ipdoctest:\s*EXTERNAL',string):
446 446 #print '-'*70 # dbg
447 447 #print 'IPExternalExample, Source:\n',string # dbg
448 448 #print '-'*70 # dbg
449 449 Example = IPExternalExample
450 450 else:
451 451 #print '-'*70 # dbg
452 452 #print 'IPExample, Source:\n',string # dbg
453 453 #print '-'*70 # dbg
454 454 Example = IPExample
455 455 ip2py = True
456 456
457 457 for m in terms:
458 458 # Add the pre-example text to `output`.
459 459 output.append(string[charno:m.start()])
460 460 # Update lineno (lines before this example)
461 461 lineno += string.count('\n', charno, m.start())
462 462 # Extract info from the regexp match.
463 463 (source, options, want, exc_msg) = \
464 464 self._parse_example(m, name, lineno,ip2py)
465 465 if Example is IPExternalExample:
466 466 options[doctest.NORMALIZE_WHITESPACE] = True
467 467 want += '\n'
468 468 # Create an Example, and add it to the list.
469 469 if not self._IS_BLANK_OR_COMMENT(source):
470 470 #print 'Example source:', source # dbg
471 471 output.append(Example(source, want, exc_msg,
472 472 lineno=lineno,
473 473 indent=min_indent+len(m.group('indent')),
474 474 options=options))
475 475 # Update lineno (lines inside this example)
476 476 lineno += string.count('\n', m.start(), m.end())
477 477 # Update charno.
478 478 charno = m.end()
479 479 # Add any remaining post-example text to `output`.
480 480 output.append(string[charno:])
481 481 return output
482 482
483 483 def _parse_example(self, m, name, lineno,ip2py=False):
484 484 """
485 485 Given a regular expression match from `_EXAMPLE_RE` (`m`),
486 486 return a pair `(source, want)`, where `source` is the matched
487 487 example's source code (with prompts and indentation stripped);
488 488 and `want` is the example's expected output (with indentation
489 489 stripped).
490 490
491 491 `name` is the string's name, and `lineno` is the line number
492 492 where the example starts; both are used for error messages.
493 493
494 494 Optional:
495 495 `ip2py`: if true, filter the input via IPython to convert the syntax
496 496 into valid python.
497 497 """
498 498
499 499 # Get the example's indentation level.
500 500 indent = len(m.group('indent'))
501 501
502 502 # Divide source into lines; check that they're properly
503 503 # indented; and then strip their indentation & prompts.
504 504 source_lines = m.group('source').split('\n')
505 505
506 506 # We're using variable-length input prompts
507 507 ps1 = m.group('ps1')
508 508 ps2 = m.group('ps2')
509 509 ps1_len = len(ps1)
510 510
511 511 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
512 512 if ps2:
513 513 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
514 514
515 515 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
516 516
517 517 if ip2py:
518 518 # Convert source input from IPython into valid Python syntax
519 519 source = self.ip2py(source)
520 520
521 521 # Divide want into lines; check that it's properly indented; and
522 522 # then strip the indentation. Spaces before the last newline should
523 523 # be preserved, so plain rstrip() isn't good enough.
524 524 want = m.group('want')
525 525 want_lines = want.split('\n')
526 526 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
527 527 del want_lines[-1] # forget final newline & spaces after it
528 528 self._check_prefix(want_lines, ' '*indent, name,
529 529 lineno + len(source_lines))
530 530
531 531 # Remove ipython output prompt that might be present in the first line
532 532 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
533 533
534 534 want = '\n'.join([wl[indent:] for wl in want_lines])
535 535
536 536 # If `want` contains a traceback message, then extract it.
537 537 m = self._EXCEPTION_RE.match(want)
538 538 if m:
539 539 exc_msg = m.group('msg')
540 540 else:
541 541 exc_msg = None
542 542
543 543 # Extract options from the source.
544 544 options = self._find_options(source, name, lineno)
545 545
546 546 return source, options, want, exc_msg
547 547
548 548 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
549 549 """
550 550 Given the lines of a source string (including prompts and
551 551 leading indentation), check to make sure that every prompt is
552 552 followed by a space character. If any line is not followed by
553 553 a space character, then raise ValueError.
554 554
555 555 Note: IPython-modified version which takes the input prompt length as a
556 556 parameter, so that prompts of variable length can be dealt with.
557 557 """
558 558 space_idx = indent+ps1_len
559 559 min_len = space_idx+1
560 560 for i, line in enumerate(lines):
561 561 if len(line) >= min_len and line[space_idx] != ' ':
562 562 raise ValueError('line %r of the docstring for %s '
563 563 'lacks blank after %s: %r' %
564 564 (lineno+i+1, name,
565 565 line[indent:space_idx], line))
566 566
567 567
568 568 SKIP = doctest.register_optionflag('SKIP')
569 569
570 570
571 class IPDocTestRunner(doctest.DocTestRunner):
572
573 # Unfortunately, doctest uses a private method (__run) for the actual run
574 # execution, so we can't cleanly override just that part. Instead, we have
575 # to copy/paste the entire run() implementation so we can call our own
576 # customized runner.
577
578 #/////////////////////////////////////////////////////////////////
579 # DocTest Running
580 #/////////////////////////////////////////////////////////////////
581
582 __LINECACHE_FILENAME_RE = re.compile(r'<doctest '
583 r'(?P<name>[\w\.]+)'
584 r'\[(?P<examplenum>\d+)\]>$')
585
586 def __patched_linecache_getlines(self, filename, module_globals=None):
587 m = self.__LINECACHE_FILENAME_RE.match(filename)
588 if m and m.group('name') == self.test.name:
589 example = self.test.examples[int(m.group('examplenum'))]
590 return example.source.splitlines(True)
591 else:
592 return self.save_linecache_getlines(filename, module_globals)
593
594
595 def _run_ip(self, test, compileflags, out):
596 """
597 Run the examples in `test`. Write the outcome of each example
598 with one of the `DocTestRunner.report_*` methods, using the
599 writer function `out`. `compileflags` is the set of compiler
600 flags that should be used to execute examples. Return a tuple
601 `(f, t)`, where `t` is the number of examples tried, and `f`
602 is the number of examples that failed. The examples are run
603 in the namespace `test.globs`.
604 """
605
606 #print 'Custom ip runner! __run' # dbg
607
608 # Keep track of the number of failures and tries.
609 failures = tries = 0
610
611 # Save the option flags (since option directives can be used
612 # to modify them).
613 original_optionflags = self.optionflags
614
615 SUCCESS, FAILURE, BOOM = range(3) # `outcome` state
616
617 check = self._checker.check_output
618
619 # Process each example.
620 for examplenum, example in enumerate(test.examples):
621
622 # If REPORT_ONLY_FIRST_FAILURE is set, then supress
623 # reporting after the first failure.
624 quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and
625 failures > 0)
626
627 # Merge in the example's options.
628 self.optionflags = original_optionflags
629 if example.options:
630 for (optionflag, val) in example.options.items():
631 if val:
632 self.optionflags |= optionflag
633 else:
634 self.optionflags &= ~optionflag
635
636 # If 'SKIP' is set, then skip this example.
637 if self.optionflags & SKIP:
638 continue
639
640 # Record that we started this example.
641 tries += 1
642 if not quiet:
643 self.report_start(out, test, example)
644
645 # Use a special filename for compile(), so we can retrieve
646 # the source code during interactive debugging (see
647 # __patched_linecache_getlines).
648 filename = '<doctest %s[%d]>' % (test.name, examplenum)
649
650 # Run the example in the given context (globs), and record
651 # any exception that gets raised. (But don't intercept
652 # keyboard interrupts.)
653 try:
654 # Don't blink! This is where the user's code gets run.
655
656 # Hack: ipython needs access to the execution context of the
657 # example, so that it can propagate user variables loaded by
658 # %run into test.globs. We put them here into our modified
659 # %run as a function attribute. Our new %run will then only
660 # make the namespace update when called (rather than
661 # unconconditionally updating test.globs here for all examples,
662 # most of which won't be calling %run anyway).
663 _run_ns_sync.test_globs = test.globs
664
665 exec compile(example.source, filename, "single",
666 compileflags, 1) in test.globs
667 self.debugger.set_continue() # ==== Example Finished ====
668 exception = None
669 except KeyboardInterrupt:
670 raise
671 except:
672 exception = sys.exc_info()
673 self.debugger.set_continue() # ==== Example Finished ====
674
675 got = self._fakeout.getvalue() # the actual output
676 self._fakeout.truncate(0)
677 outcome = FAILURE # guilty until proved innocent or insane
678
679 # If the example executed without raising any exceptions,
680 # verify its output.
681 if exception is None:
682 if check(example.want, got, self.optionflags):
683 outcome = SUCCESS
684
685 # The example raised an exception: check if it was expected.
686 else:
687 exc_info = sys.exc_info()
688 exc_msg = traceback.format_exception_only(*exc_info[:2])[-1]
689 if not quiet:
690 got += _exception_traceback(exc_info)
691
692 # If `example.exc_msg` is None, then we weren't expecting
693 # an exception.
694 if example.exc_msg is None:
695 outcome = BOOM
696
697 # We expected an exception: see whether it matches.
698 elif check(example.exc_msg, exc_msg, self.optionflags):
699 outcome = SUCCESS
700
701 # Another chance if they didn't care about the detail.
702 elif self.optionflags & IGNORE_EXCEPTION_DETAIL:
703 m1 = re.match(r'[^:]*:', example.exc_msg)
704 m2 = re.match(r'[^:]*:', exc_msg)
705 if m1 and m2 and check(m1.group(0), m2.group(0),
706 self.optionflags):
707 outcome = SUCCESS
708
709 # Report the outcome.
710 if outcome is SUCCESS:
711 if not quiet:
712 self.report_success(out, test, example, got)
713 elif outcome is FAILURE:
714 if not quiet:
715 self.report_failure(out, test, example, got)
716 failures += 1
717 elif outcome is BOOM:
718 if not quiet:
719 self.report_unexpected_exception(out, test, example,
720 exc_info)
721 failures += 1
722 else:
723 assert False, ("unknown outcome", outcome)
724
725 # Restore the option flags (in case they were modified)
726 self.optionflags = original_optionflags
727
728 # Record and return the number of failures and tries.
729
730 # Hack to access a parent private method by working around Python's
731 # name mangling (which is fortunately simple).
732 #self.__record_outcome(test, failures, tries)
733 doctest.DocTestRunner._DocTestRunner__record_outcome(self,test,
734 failures, tries)
735
736 return failures, tries
737
738
739 # Unfortunately doctest has chosen to implement a couple of key methods as
740 # private (__run, in particular). We are forced to copy the entire run
741 # method here just so we can override that one. Ugh.
571 class IPDocTestRunner(doctest.DocTestRunner,object):
572 """Test runner that synchronizes the IPython namespace with test globals.
573 """
742 574
743 575 def run(self, test, compileflags=None, out=None, clear_globs=True):
744 """
745 Run the examples in `test`, and display the results using the
746 writer function `out`.
747
748 The examples are run in the namespace `test.globs`. If
749 `clear_globs` is true (the default), then this namespace will
750 be cleared after the test runs, to help with garbage
751 collection. If you would like to examine the namespace after
752 the test completes, then use `clear_globs=False`.
753
754 `compileflags` gives the set of flags that should be used by
755 the Python compiler when running the examples. If not
756 specified, then it will default to the set of future-import
757 flags that apply to `globs`.
758
759 The output of each example is checked using
760 `DocTestRunner.check_output`, and the results are formatted by
761 the `DocTestRunner.report_*` methods.
762 """
763 #print 'Custom ip runner!' # dbg
764
765 self.test = test
766
767 if compileflags is None:
768 compileflags = _extract_future_flags(test.globs)
769
770 save_stdout = sys.stdout
771 if out is None:
772 out = save_stdout.write
773 sys.stdout = self._fakeout
774
775 # Patch pdb.set_trace to restore sys.stdout during interactive
776 # debugging (so it's not still redirected to self._fakeout).
777 # Note that the interactive output will go to *our*
778 # save_stdout, even if that's not the real sys.stdout; this
779 # allows us to write test cases for the set_trace behavior.
780 save_set_trace = pdb.set_trace
781 self.debugger = _OutputRedirectingPdb(save_stdout)
782 self.debugger.reset()
783 pdb.set_trace = self.debugger.set_trace
784
785 # Patch linecache.getlines, so we can see the example's source
786 # when we're inside the debugger.
787 self.save_linecache_getlines = linecache.getlines
788 linecache.getlines = self.__patched_linecache_getlines
789 576
790 try:
791 # Hack to access a parent private method by working around Python's
792 # name mangling (which is fortunately simple).
793 #return self.__run(test, compileflags, out)
794 return self._run_ip(test, compileflags, out)
795 #return doctest.DocTestRunner._DocTestRunner__run(self,test,
796 # compileflags, out)
797 finally:
798 _ip.user_ns.update(test.globs)
799 sys.stdout = save_stdout
800 pdb.set_trace = save_set_trace
801 linecache.getlines = self.save_linecache_getlines
802 if clear_globs:
803 test.globs.clear()
577 # Hack: ipython needs access to the execution context of the example,
578 # so that it can propagate user variables loaded by %run into
579 # test.globs. We put them here into our modified %run as a function
580 # attribute. Our new %run will then only make the namespace update
581 # when called (rather than unconconditionally updating test.globs here
582 # for all examples, most of which won't be calling %run anyway).
583 _run_ns_sync.test_globs = test.globs
584
585 return super(IPDocTestRunner,self).run(test,
586 compileflags,out,clear_globs)
804 587
805 588
806 589 class DocFileCase(doctest.DocFileCase):
807 590 """Overrides to provide filename
808 591 """
809 592 def address(self):
810 593 return (self._dt_test.filename, None, None)
811 594
812 595
813 596 class ExtensionDoctest(doctests.Doctest):
814 597 """Nose Plugin that supports doctests in extension modules.
815 598 """
816 599 name = 'extdoctest' # call nosetests with --with-extdoctest
817 600 enabled = True
818 601
819 602 def options(self, parser, env=os.environ):
820 603 Plugin.options(self, parser, env)
821 604
822 605 def configure(self, options, config):
823 606 Plugin.configure(self, options, config)
824 607 self.doctest_tests = options.doctest_tests
825 608 self.extension = tolist(options.doctestExtension)
826 609 self.finder = DocTestFinder()
827 610 self.parser = doctest.DocTestParser()
828 611 self.globs = None
829 612 self.extraglobs = None
830 613
831 614 def loadTestsFromExtensionModule(self,filename):
832 615 bpath,mod = os.path.split(filename)
833 616 modname = os.path.splitext(mod)[0]
834 617 try:
835 618 sys.path.append(bpath)
836 619 module = __import__(modname)
837 620 tests = list(self.loadTestsFromModule(module))
838 621 finally:
839 622 sys.path.pop()
840 623 return tests
841 624
842 625 # NOTE: the method below is almost a copy of the original one in nose, with
843 626 # a few modifications to control output checking.
844 627
845 628 def loadTestsFromModule(self, module):
846 629 #print 'lTM',module # dbg
847 630
848 631 if not self.matches(module.__name__):
849 632 log.debug("Doctest doesn't want module %s", module)
850 633 return
851 634
852 635 ## try:
853 636 ## print 'Globs:',self.globs.keys() # dbg
854 637 ## except:
855 638 ## pass
856 639
857 640 tests = self.finder.find(module,globs=self.globs,
858 641 extraglobs=self.extraglobs)
859 642 if not tests:
860 643 return
861 644 tests.sort()
862 645 module_file = module.__file__
863 646 if module_file[-4:] in ('.pyc', '.pyo'):
864 647 module_file = module_file[:-1]
865 648 for test in tests:
866 649 if not test.examples:
867 650 continue
868 651 if not test.filename:
869 652 test.filename = module_file
870 653
871 654 # xxx - checker and options may be ok instantiated once outside loop
872 655
873 656 # always use whitespace and ellipsis options
874 657 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
875 658 checker = IPDoctestOutputChecker()
876 659
877 660 yield DocTestCase(test,
878 661 optionflags=optionflags,
879 662 checker=checker)
880 663
881 664 def loadTestsFromFile(self, filename):
882 665 #print 'lTF',filename # dbg
883 666
884 667 if is_extension_module(filename):
885 668 for t in self.loadTestsFromExtensionModule(filename):
886 669 yield t
887 670 else:
888 671 if self.extension and anyp(filename.endswith, self.extension):
889 672 name = os.path.basename(filename)
890 673 dh = open(filename)
891 674 try:
892 675 doc = dh.read()
893 676 finally:
894 677 dh.close()
895 678 test = self.parser.get_doctest(
896 679 doc, globs={'__file__': filename}, name=name,
897 680 filename=filename, lineno=0)
898 681 if test.examples:
899 682 #print 'FileCase:',test.examples # dbg
900 683 yield DocFileCase(test)
901 684 else:
902 685 yield False # no tests to load
903 686
904 687 def wantFile(self,filename):
905 688 """Return whether the given filename should be scanned for tests.
906 689
907 690 Modified version that accepts extension modules as valid containers for
908 691 doctests.
909 692 """
910 693 #print 'Filename:',filename # dbg
911 694
912 695 # temporarily hardcoded list, will move to driver later
913 696 exclude = ['IPython/external/',
914 697 'IPython/Extensions/ipy_',
915 698 'IPython/platutils_win32',
916 699 'IPython/frontend/cocoa',
917 700 'IPython_doctest_plugin',
918 701 'IPython/Gnuplot',
919 702 'IPython/Extensions/PhysicalQIn']
920 703
921 704 for fex in exclude:
922 705 if fex in filename: # substring
923 706 #print '###>>> SKIP:',filename # dbg
924 707 return False
925 708
926 709 if is_extension_module(filename):
927 710 return True
928 711 else:
929 712 return doctests.Doctest.wantFile(self,filename)
930 713
931 714
932 715 class IPythonDoctest(ExtensionDoctest):
933 716 """Nose Plugin that supports doctests in extension modules.
934 717 """
935 718 name = 'ipdoctest' # call nosetests with --with-ipdoctest
936 719 enabled = True
937 720
938 721 def configure(self, options, config):
939 722
940 723 Plugin.configure(self, options, config)
941 724 self.doctest_tests = options.doctest_tests
942 725 self.extension = tolist(options.doctestExtension)
943 726 self.parser = IPDocTestParser()
944 727 self.finder = DocTestFinder(parser=self.parser)
945 728
946 729 # XXX - we need to run in the ipython user's namespace, but doing so is
947 730 # breaking normal doctests!
948 731
949 732 #self.globs = _ip.user_ns
950 733 self.globs = None
951 734
952 735 self.extraglobs = None
953 736
954 737 # Use a specially modified test runner that is IPython-aware
955 738 self.iprunner = None
General Comments 0
You need to be logged in to leave comments. Login now