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