doctest.py (45198B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\doctest.py 2 __docformat__ = 'reStructuredText en' 3 __all__ = ['register_optionflag', 4 'DONT_ACCEPT_TRUE_FOR_1', 5 'DONT_ACCEPT_BLANKLINE', 6 'NORMALIZE_WHITESPACE', 7 'ELLIPSIS', 8 'SKIP', 9 'IGNORE_EXCEPTION_DETAIL', 10 'COMPARISON_FLAGS', 11 'REPORT_UDIFF', 12 'REPORT_CDIFF', 13 'REPORT_NDIFF', 14 'REPORT_ONLY_FIRST_FAILURE', 15 'REPORTING_FLAGS', 16 'Example', 17 'DocTest', 18 'DocTestParser', 19 'DocTestFinder', 20 'DocTestRunner', 21 'OutputChecker', 22 'DocTestFailure', 23 'UnexpectedException', 24 'DebugRunner', 25 'testmod', 26 'testfile', 27 'run_docstring_examples', 28 'Tester', 29 'DocTestSuite', 30 'DocFileSuite', 31 'set_unittest_reportflags', 32 'script_from_examples', 33 'testsource', 34 'debug_src', 35 'debug'] 36 import __future__ 37 import sys, traceback, inspect, linecache, os, re 38 import unittest, difflib, pdb, tempfile 39 import warnings 40 from StringIO import StringIO 41 from collections import namedtuple 42 TestResults = namedtuple('TestResults', 'failed attempted') 43 OPTIONFLAGS_BY_NAME = {} 44 45 def register_optionflag(name): 46 return OPTIONFLAGS_BY_NAME.setdefault(name, 1 << len(OPTIONFLAGS_BY_NAME)) 47 48 49 DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1') 50 DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE') 51 NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE') 52 ELLIPSIS = register_optionflag('ELLIPSIS') 53 SKIP = register_optionflag('SKIP') 54 IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL') 55 COMPARISON_FLAGS = DONT_ACCEPT_TRUE_FOR_1 | DONT_ACCEPT_BLANKLINE | NORMALIZE_WHITESPACE | ELLIPSIS | SKIP | IGNORE_EXCEPTION_DETAIL 56 REPORT_UDIFF = register_optionflag('REPORT_UDIFF') 57 REPORT_CDIFF = register_optionflag('REPORT_CDIFF') 58 REPORT_NDIFF = register_optionflag('REPORT_NDIFF') 59 REPORT_ONLY_FIRST_FAILURE = register_optionflag('REPORT_ONLY_FIRST_FAILURE') 60 REPORTING_FLAGS = REPORT_UDIFF | REPORT_CDIFF | REPORT_NDIFF | REPORT_ONLY_FIRST_FAILURE 61 BLANKLINE_MARKER = '<BLANKLINE>' 62 ELLIPSIS_MARKER = '...' 63 64 def _extract_future_flags(globs): 65 flags = 0 66 for fname in __future__.all_feature_names: 67 feature = globs.get(fname, None) 68 if feature is getattr(__future__, fname): 69 flags |= feature.compiler_flag 70 71 return flags 72 73 74 def _normalize_module(module, depth = 2): 75 if inspect.ismodule(module): 76 return module 77 if isinstance(module, (str, unicode)): 78 return __import__(module, globals(), locals(), ['*']) 79 if module is None: 80 return sys.modules[sys._getframe(depth).f_globals['__name__']] 81 raise TypeError('Expected a module, string, or None') 82 83 84 def _load_testfile(filename, package, module_relative): 85 if module_relative: 86 package = _normalize_module(package, 3) 87 filename = _module_relative_path(package, filename) 88 if hasattr(package, '__loader__'): 89 if hasattr(package.__loader__, 'get_data'): 90 file_contents = package.__loader__.get_data(filename) 91 return (file_contents.replace(os.linesep, '\n'), filename) 92 with open(filename) as f: 93 return (f.read(), filename) 94 95 96 _encoding = getattr(sys.__stdout__, 'encoding', None) or 'utf-8' 97 98 def _indent(s, indent = 4): 99 if isinstance(s, unicode): 100 s = s.encode(_encoding, 'backslashreplace') 101 return re.sub('(?m)^(?!$)', indent * ' ', s) 102 103 104 def _exception_traceback(exc_info): 105 excout = StringIO() 106 exc_type, exc_val, exc_tb = exc_info 107 traceback.print_exception(exc_type, exc_val, exc_tb, file=excout) 108 return excout.getvalue() 109 110 111 class _SpoofOut(StringIO): 112 113 def getvalue(self): 114 result = StringIO.getvalue(self) 115 if result and not result.endswith('\n'): 116 result += '\n' 117 if hasattr(self, 'softspace'): 118 del self.softspace 119 return result 120 121 def truncate(self, size = None): 122 StringIO.truncate(self, size) 123 if hasattr(self, 'softspace'): 124 del self.softspace 125 if not self.buf: 126 self.buf = '' 127 128 129 def _ellipsis_match(want, got): 130 if ELLIPSIS_MARKER not in want: 131 return want == got 132 ws = want.split(ELLIPSIS_MARKER) 133 startpos, endpos = 0, len(got) 134 w = ws[0] 135 if w: 136 if got.startswith(w): 137 startpos = len(w) 138 del ws[0] 139 else: 140 return False 141 w = ws[-1] 142 if w: 143 if got.endswith(w): 144 endpos -= len(w) 145 del ws[-1] 146 else: 147 return False 148 if startpos > endpos: 149 return False 150 for w in ws: 151 startpos = got.find(w, startpos, endpos) 152 if startpos < 0: 153 return False 154 startpos += len(w) 155 156 return True 157 158 159 def _comment_line(line): 160 line = line.rstrip() 161 if line: 162 return '# ' + line 163 else: 164 return '#' 165 166 167 class _OutputRedirectingPdb(pdb.Pdb): 168 169 def __init__(self, out): 170 self.__out = out 171 self.__debugger_used = False 172 pdb.Pdb.__init__(self, stdout=out) 173 self.use_rawinput = 1 174 175 def set_trace(self, frame = None): 176 self.__debugger_used = True 177 if frame is None: 178 frame = sys._getframe().f_back 179 pdb.Pdb.set_trace(self, frame) 180 181 def set_continue(self): 182 if self.__debugger_used: 183 pdb.Pdb.set_continue(self) 184 185 def trace_dispatch(self, *args): 186 save_stdout = sys.stdout 187 sys.stdout = self.__out 188 try: 189 return pdb.Pdb.trace_dispatch(self, *args) 190 finally: 191 sys.stdout = save_stdout 192 193 194 def _module_relative_path(module, path): 195 if not inspect.ismodule(module): 196 raise TypeError, 'Expected a module: %r' % module 197 if path.startswith('/'): 198 raise ValueError, 'Module-relative files may not have absolute paths' 199 if hasattr(module, '__file__'): 200 basedir = os.path.split(module.__file__)[0] 201 elif module.__name__ == '__main__': 202 if len(sys.argv) > 0 and sys.argv[0] != '': 203 basedir = os.path.split(sys.argv[0])[0] 204 else: 205 basedir = os.curdir 206 else: 207 raise ValueError("Can't resolve paths relative to the module " + module + ' (it has no __file__)') 208 return os.path.join(basedir, *path.split('/')) 209 210 211 class Example(): 212 213 def __init__(self, source, want, exc_msg = None, lineno = 0, indent = 0, options = None): 214 if not source.endswith('\n'): 215 source += '\n' 216 if want and not want.endswith('\n'): 217 want += '\n' 218 if exc_msg is not None and not exc_msg.endswith('\n'): 219 exc_msg += '\n' 220 self.source = source 221 self.want = want 222 self.lineno = lineno 223 self.indent = indent 224 if options is None: 225 options = {} 226 self.options = options 227 self.exc_msg = exc_msg 228 229 230 class DocTest(): 231 232 def __init__(self, examples, globs, name, filename, lineno, docstring): 233 self.examples = examples 234 self.docstring = docstring 235 self.globs = globs.copy() 236 self.name = name 237 self.filename = filename 238 self.lineno = lineno 239 240 def __repr__(self): 241 if len(self.examples) == 0: 242 examples = 'no examples' 243 elif len(self.examples) == 1: 244 examples = '1 example' 245 else: 246 examples = '%d examples' % len(self.examples) 247 return '<DocTest %s from %s:%s (%s)>' % (self.name, 248 self.filename, 249 self.lineno, 250 examples) 251 252 def __cmp__(self, other): 253 if not isinstance(other, DocTest): 254 return -1 255 return cmp((self.name, 256 self.filename, 257 self.lineno, 258 id(self)), (other.name, 259 other.filename, 260 other.lineno, 261 id(other))) 262 263 264 class DocTestParser(): 265 _EXAMPLE_RE = re.compile('\n # Source consists of a PS1 line followed by zero or more PS2 lines.\n (?P<source>\n (?:^(?P<indent> [ ]*) >>> .*) # PS1 line\n (?:\\n [ ]* \\.\\.\\. .*)*) # PS2 lines\n \\n?\n # Want consists of any non-blank lines that do not start with PS1.\n (?P<want> (?:(?![ ]*$) # Not a blank line\n (?![ ]*>>>) # Not a line starting with PS1\n .*$\\n? # But any other line\n )*)\n ', re.MULTILINE | re.VERBOSE) 266 _EXCEPTION_RE = re.compile("\n # Grab the traceback header. Different versions of Python have\n # said different things on the first traceback line.\n ^(?P<hdr> Traceback\\ \\(\n (?: most\\ recent\\ call\\ last\n | innermost\\ last\n ) \\) :\n )\n \\s* $ # toss trailing whitespace on the header.\n (?P<stack> .*?) # don't blink: absorb stuff until...\n ^ (?P<msg> \\w+ .*) # a line *starts* with alphanum.\n ", re.VERBOSE | re.MULTILINE | re.DOTALL) 267 _IS_BLANK_OR_COMMENT = re.compile('^[ ]*(#.*)?$').match 268 269 def parse(self, string, name = '<string>'): 270 string = string.expandtabs() 271 min_indent = self._min_indent(string) 272 if min_indent > 0: 273 string = '\n'.join([ l[min_indent:] for l in string.split('\n') ]) 274 output = [] 275 charno, lineno = (0, 0) 276 for m in self._EXAMPLE_RE.finditer(string): 277 output.append(string[charno:m.start()]) 278 lineno += string.count('\n', charno, m.start()) 279 source, options, want, exc_msg = self._parse_example(m, name, lineno) 280 if not self._IS_BLANK_OR_COMMENT(source): 281 output.append(Example(source, want, exc_msg, lineno=lineno, indent=min_indent + len(m.group('indent')), options=options)) 282 lineno += string.count('\n', m.start(), m.end()) 283 charno = m.end() 284 285 output.append(string[charno:]) 286 return output 287 288 def get_doctest(self, string, globs, name, filename, lineno): 289 return DocTest(self.get_examples(string, name), globs, name, filename, lineno, string) 290 291 def get_examples(self, string, name = '<string>'): 292 return [ x for x in self.parse(string, name) if isinstance(x, Example) ] 293 294 def _parse_example(self, m, name, lineno): 295 indent = len(m.group('indent')) 296 source_lines = m.group('source').split('\n') 297 self._check_prompt_blank(source_lines, indent, name, lineno) 298 self._check_prefix(source_lines[1:], ' ' * indent + '.', name, lineno) 299 source = '\n'.join([ sl[indent + 4:] for sl in source_lines ]) 300 want = m.group('want') 301 want_lines = want.split('\n') 302 if len(want_lines) > 1 and re.match(' *$', want_lines[-1]): 303 del want_lines[-1] 304 self._check_prefix(want_lines, ' ' * indent, name, lineno + len(source_lines)) 305 want = '\n'.join([ wl[indent:] for wl in want_lines ]) 306 m = self._EXCEPTION_RE.match(want) 307 if m: 308 exc_msg = m.group('msg') 309 else: 310 exc_msg = None 311 options = self._find_options(source, name, lineno) 312 return (source, 313 options, 314 want, 315 exc_msg) 316 317 _OPTION_DIRECTIVE_RE = re.compile('#\\s*doctest:\\s*([^\\n\\\'"]*)$', re.MULTILINE) 318 319 def _find_options(self, source, name, lineno): 320 options = {} 321 for m in self._OPTION_DIRECTIVE_RE.finditer(source): 322 option_strings = m.group(1).replace(',', ' ').split() 323 for option in option_strings: 324 if option[0] not in '+-' or option[1:] not in OPTIONFLAGS_BY_NAME: 325 raise ValueError('line %r of the doctest for %s has an invalid option: %r' % (lineno + 1, name, option)) 326 flag = OPTIONFLAGS_BY_NAME[option[1:]] 327 options[flag] = option[0] == '+' 328 329 if options and self._IS_BLANK_OR_COMMENT(source): 330 raise ValueError('line %r of the doctest for %s has an option directive on a line with no example: %r' % (lineno, name, source)) 331 return options 332 333 _INDENT_RE = re.compile('^([ ]*)(?=\\S)', re.MULTILINE) 334 335 def _min_indent(self, s): 336 indents = [ len(indent) for indent in self._INDENT_RE.findall(s) ] 337 if len(indents) > 0: 338 return min(indents) 339 else: 340 return 0 341 342 def _check_prompt_blank(self, lines, indent, name, lineno): 343 for i, line in enumerate(lines): 344 if len(line) >= indent + 4 and line[indent + 3] != ' ': 345 raise ValueError('line %r of the docstring for %s lacks blank after %s: %r' % (lineno + i + 1, 346 name, 347 line[indent:indent + 3], 348 line)) 349 350 def _check_prefix(self, lines, prefix, name, lineno): 351 for i, line in enumerate(lines): 352 if line and not line.startswith(prefix): 353 raise ValueError('line %r of the docstring for %s has inconsistent leading whitespace: %r' % (lineno + i + 1, name, line)) 354 355 356 class DocTestFinder(): 357 358 def __init__(self, verbose = False, parser = DocTestParser(), recurse = True, exclude_empty = True): 359 self._parser = parser 360 self._verbose = verbose 361 self._recurse = recurse 362 self._exclude_empty = exclude_empty 363 364 def find(self, obj, name = None, module = None, globs = None, extraglobs = None): 365 if name is None: 366 name = getattr(obj, '__name__', None) 367 if name is None: 368 raise ValueError("DocTestFinder.find: name must be given when obj.__name__ doesn't exist: %r" % (type(obj),)) 369 if module is False: 370 module = None 371 elif module is None: 372 module = inspect.getmodule(obj) 373 try: 374 file = inspect.getsourcefile(obj) or inspect.getfile(obj) 375 if module is not None: 376 source_lines = linecache.getlines(file, module.__dict__) 377 else: 378 source_lines = linecache.getlines(file) 379 if not source_lines: 380 source_lines = None 381 except TypeError: 382 source_lines = None 383 384 if globs is None: 385 if module is None: 386 globs = {} 387 else: 388 globs = module.__dict__.copy() 389 else: 390 globs = globs.copy() 391 if extraglobs is not None: 392 globs.update(extraglobs) 393 if '__name__' not in globs: 394 globs['__name__'] = '__main__' 395 tests = [] 396 self._find(tests, obj, name, module, source_lines, globs, {}) 397 tests.sort() 398 return tests 399 400 def _from_module(self, module, object): 401 if module is None: 402 return True 403 if inspect.getmodule(object) is not None: 404 return module is inspect.getmodule(object) 405 if inspect.isfunction(object): 406 return module.__dict__ is object.func_globals 407 if inspect.isclass(object): 408 return module.__name__ == object.__module__ 409 if hasattr(object, '__module__'): 410 return module.__name__ == object.__module__ 411 if isinstance(object, property): 412 return True 413 raise ValueError('object must be a class or function') 414 415 def _find(self, tests, obj, name, module, source_lines, globs, seen): 416 if self._verbose: 417 print 'Finding tests in %s' % name 418 if id(obj) in seen: 419 return 420 seen[id(obj)] = 1 421 test = self._get_test(obj, name, module, globs, source_lines) 422 if test is not None: 423 tests.append(test) 424 if inspect.ismodule(obj) and self._recurse: 425 for valname, val in obj.__dict__.items(): 426 valname = '%s.%s' % (name, valname) 427 if (inspect.isfunction(val) or inspect.isclass(val)) and self._from_module(module, val): 428 self._find(tests, val, valname, module, source_lines, globs, seen) 429 430 if inspect.ismodule(obj) and self._recurse: 431 for valname, val in getattr(obj, '__test__', {}).items(): 432 if not isinstance(valname, basestring): 433 raise ValueError('DocTestFinder.find: __test__ keys must be strings: %r' % (type(valname),)) 434 if not (inspect.isfunction(val) or inspect.isclass(val) or inspect.ismethod(val) or inspect.ismodule(val) or isinstance(val, basestring)): 435 raise ValueError('DocTestFinder.find: __test__ values must be strings, functions, methods, classes, or modules: %r' % (type(val),)) 436 valname = '%s.__test__.%s' % (name, valname) 437 self._find(tests, val, valname, module, source_lines, globs, seen) 438 439 if inspect.isclass(obj) and self._recurse: 440 for valname, val in obj.__dict__.items(): 441 if isinstance(val, staticmethod): 442 val = getattr(obj, valname) 443 if isinstance(val, classmethod): 444 val = getattr(obj, valname).im_func 445 if (inspect.isfunction(val) or inspect.isclass(val) or isinstance(val, property)) and self._from_module(module, val): 446 valname = '%s.%s' % (name, valname) 447 self._find(tests, val, valname, module, source_lines, globs, seen) 448 449 def _get_test(self, obj, name, module, globs, source_lines): 450 if isinstance(obj, basestring): 451 docstring = obj 452 else: 453 try: 454 if obj.__doc__ is None: 455 docstring = '' 456 else: 457 docstring = obj.__doc__ 458 if not isinstance(docstring, basestring): 459 docstring = str(docstring) 460 except (TypeError, AttributeError): 461 docstring = '' 462 463 lineno = self._find_lineno(obj, source_lines) 464 if self._exclude_empty and not docstring: 465 return 466 if module is None: 467 filename = None 468 else: 469 filename = getattr(module, '__file__', module.__name__) 470 if filename[-4:] in ('.pyc', '.pyo'): 471 filename = filename[:-1] 472 return self._parser.get_doctest(docstring, globs, name, filename, lineno) 473 474 def _find_lineno(self, obj, source_lines): 475 lineno = None 476 if inspect.ismodule(obj): 477 lineno = 0 478 if inspect.isclass(obj): 479 if source_lines is None: 480 return 481 pat = re.compile('^\\s*class\\s*%s\\b' % getattr(obj, '__name__', '-')) 482 for i, line in enumerate(source_lines): 483 if pat.match(line): 484 lineno = i 485 break 486 487 if inspect.ismethod(obj): 488 obj = obj.im_func 489 if inspect.isfunction(obj): 490 obj = obj.func_code 491 if inspect.istraceback(obj): 492 obj = obj.tb_frame 493 if inspect.isframe(obj): 494 obj = obj.f_code 495 if inspect.iscode(obj): 496 lineno = getattr(obj, 'co_firstlineno', None) - 1 497 if lineno is not None: 498 if source_lines is None: 499 return lineno + 1 500 pat = re.compile('(^|.*:)\\s*\\w*("|\')') 501 for lineno in range(lineno, len(source_lines)): 502 if pat.match(source_lines[lineno]): 503 return lineno 504 505 506 class DocTestRunner(): 507 DIVIDER = '*' * 70 508 509 def __init__(self, checker = None, verbose = None, optionflags = 0): 510 self._checker = checker or OutputChecker() 511 if verbose is None: 512 verbose = '-v' in sys.argv 513 self._verbose = verbose 514 self.optionflags = optionflags 515 self.original_optionflags = optionflags 516 self.tries = 0 517 self.failures = 0 518 self._name2ft = {} 519 self._fakeout = _SpoofOut() 520 521 def report_start(self, out, test, example): 522 if self._verbose: 523 if example.want: 524 out('Trying:\n' + _indent(example.source) + 'Expecting:\n' + _indent(example.want)) 525 else: 526 out('Trying:\n' + _indent(example.source) + 'Expecting nothing\n') 527 528 def report_success(self, out, test, example, got): 529 if self._verbose: 530 out('ok\n') 531 532 def report_failure(self, out, test, example, got): 533 out(self._failure_header(test, example) + self._checker.output_difference(example, got, self.optionflags)) 534 535 def report_unexpected_exception(self, out, test, example, exc_info): 536 out(self._failure_header(test, example) + 'Exception raised:\n' + _indent(_exception_traceback(exc_info))) 537 538 def _failure_header(self, test, example): 539 out = [self.DIVIDER] 540 if test.filename: 541 if test.lineno is not None and example.lineno is not None: 542 lineno = test.lineno + example.lineno + 1 543 else: 544 lineno = '?' 545 out.append('File "%s", line %s, in %s' % (test.filename, lineno, test.name)) 546 else: 547 out.append('Line %s, in %s' % (example.lineno + 1, test.name)) 548 out.append('Failed example:') 549 source = example.source 550 out.append(_indent(source)) 551 return '\n'.join(out) 552 553 def __run(self, test, compileflags, out): 554 failures = tries = 0 555 original_optionflags = self.optionflags 556 SUCCESS, FAILURE, BOOM = range(3) 557 check = self._checker.check_output 558 for examplenum, example in enumerate(test.examples): 559 quiet = self.optionflags & REPORT_ONLY_FIRST_FAILURE and failures > 0 560 self.optionflags = original_optionflags 561 if example.options: 562 for optionflag, val in example.options.items(): 563 if val: 564 self.optionflags |= optionflag 565 else: 566 self.optionflags &= ~optionflag 567 568 if self.optionflags & SKIP: 569 continue 570 tries += 1 571 if not quiet: 572 self.report_start(out, test, example) 573 filename = '<doctest %s[%d]>' % (test.name, examplenum) 574 try: 575 exec compile(example.source, filename, 'single', compileflags, 1) in test.globs 576 self.debugger.set_continue() 577 exception = None 578 except KeyboardInterrupt: 579 raise 580 except: 581 exception = sys.exc_info() 582 self.debugger.set_continue() 583 584 got = self._fakeout.getvalue() 585 self._fakeout.truncate(0) 586 outcome = FAILURE 587 if exception is None: 588 if check(example.want, got, self.optionflags): 589 outcome = SUCCESS 590 else: 591 exc_info = sys.exc_info() 592 exc_msg = traceback.format_exception_only(*exc_info[:2])[-1] 593 if not quiet: 594 got += _exception_traceback(exc_info) 595 if example.exc_msg is None: 596 outcome = BOOM 597 elif check(example.exc_msg, exc_msg, self.optionflags): 598 outcome = SUCCESS 599 elif self.optionflags & IGNORE_EXCEPTION_DETAIL: 600 m1 = re.match('(?:[^:]*\\.)?([^:]*:)', example.exc_msg) 601 m2 = re.match('(?:[^:]*\\.)?([^:]*:)', exc_msg) 602 if m1 and m2 and check(m1.group(1), m2.group(1), self.optionflags): 603 outcome = SUCCESS 604 if outcome is SUCCESS: 605 if not quiet: 606 self.report_success(out, test, example, got) 607 elif outcome is FAILURE: 608 if not quiet: 609 self.report_failure(out, test, example, got) 610 failures += 1 611 elif outcome is BOOM: 612 if not quiet: 613 self.report_unexpected_exception(out, test, example, exc_info) 614 failures += 1 615 616 self.optionflags = original_optionflags 617 self.__record_outcome(test, failures, tries) 618 return TestResults(failures, tries) 619 620 def __record_outcome(self, test, f, t): 621 f2, t2 = self._name2ft.get(test.name, (0, 0)) 622 self._name2ft[test.name] = (f + f2, t + t2) 623 self.failures += f 624 self.tries += t 625 626 __LINECACHE_FILENAME_RE = re.compile('<doctest (?P<name>.+)\\[(?P<examplenum>\\d+)\\]>$') 627 628 def __patched_linecache_getlines(self, filename, module_globals = None): 629 m = self.__LINECACHE_FILENAME_RE.match(filename) 630 if m and m.group('name') == self.test.name: 631 example = self.test.examples[int(m.group('examplenum'))] 632 source = example.source 633 if isinstance(source, unicode): 634 source = source.encode('ascii', 'backslashreplace') 635 return source.splitlines(True) 636 else: 637 return self.save_linecache_getlines(filename, module_globals) 638 639 def run(self, test, compileflags = None, out = None, clear_globs = True): 640 self.test = test 641 if compileflags is None: 642 compileflags = _extract_future_flags(test.globs) 643 save_stdout = sys.stdout 644 if out is None: 645 out = save_stdout.write 646 sys.stdout = self._fakeout 647 save_set_trace = pdb.set_trace 648 self.debugger = _OutputRedirectingPdb(save_stdout) 649 self.debugger.reset() 650 pdb.set_trace = self.debugger.set_trace 651 self.save_linecache_getlines = linecache.getlines 652 linecache.getlines = self.__patched_linecache_getlines 653 save_displayhook = sys.displayhook 654 sys.displayhook = sys.__displayhook__ 655 try: 656 return self.__run(test, compileflags, out) 657 finally: 658 sys.stdout = save_stdout 659 pdb.set_trace = save_set_trace 660 linecache.getlines = self.save_linecache_getlines 661 sys.displayhook = save_displayhook 662 if clear_globs: 663 test.globs.clear() 664 665 def summarize(self, verbose = None): 666 if verbose is None: 667 verbose = self._verbose 668 notests = [] 669 passed = [] 670 failed = [] 671 totalt = totalf = 0 672 for x in self._name2ft.items(): 673 name, (f, t) = x 674 totalt += t 675 totalf += f 676 if t == 0: 677 notests.append(name) 678 elif f == 0: 679 passed.append((name, t)) 680 else: 681 failed.append(x) 682 683 if verbose: 684 if notests: 685 print len(notests), 'items had no tests:' 686 notests.sort() 687 for thing in notests: 688 print ' ', thing 689 690 if passed: 691 print len(passed), 'items passed all tests:' 692 passed.sort() 693 for thing, count in passed: 694 print ' %3d tests in %s' % (count, thing) 695 696 if failed: 697 print self.DIVIDER 698 print len(failed), 'items had failures:' 699 failed.sort() 700 for thing, (f, t) in failed: 701 print ' %3d of %3d in %s' % (f, t, thing) 702 703 if verbose: 704 print totalt, 'tests in', len(self._name2ft), 'items.' 705 print totalt - totalf, 'passed and', totalf, 'failed.' 706 if totalf: 707 print '***Test Failed***', totalf, 'failures.' 708 elif verbose: 709 print 'Test passed.' 710 return TestResults(totalf, totalt) 711 712 def merge(self, other): 713 d = self._name2ft 714 for name, (f, t) in other._name2ft.items(): 715 if name in d: 716 f2, t2 = d[name] 717 f = f + f2 718 t = t + t2 719 d[name] = (f, t) 720 721 722 class OutputChecker(): 723 724 def check_output(self, want, got, optionflags): 725 if got == want: 726 return True 727 if not optionflags & DONT_ACCEPT_TRUE_FOR_1: 728 if (got, want) == ('True\n', '1\n'): 729 return True 730 if (got, want) == ('False\n', '0\n'): 731 return True 732 if not optionflags & DONT_ACCEPT_BLANKLINE: 733 want = re.sub('(?m)^%s\\s*?$' % re.escape(BLANKLINE_MARKER), '', want) 734 got = re.sub('(?m)^\\s*?$', '', got) 735 if got == want: 736 return True 737 if optionflags & NORMALIZE_WHITESPACE: 738 got = ' '.join(got.split()) 739 want = ' '.join(want.split()) 740 if got == want: 741 return True 742 if optionflags & ELLIPSIS: 743 if _ellipsis_match(want, got): 744 return True 745 return False 746 747 def _do_a_fancy_diff(self, want, got, optionflags): 748 if not optionflags & (REPORT_UDIFF | REPORT_CDIFF | REPORT_NDIFF): 749 return False 750 if optionflags & REPORT_NDIFF: 751 return True 752 return want.count('\n') > 2 and got.count('\n') > 2 753 754 def output_difference(self, example, got, optionflags): 755 want = example.want 756 if not optionflags & DONT_ACCEPT_BLANKLINE: 757 got = re.sub('(?m)^[ ]*(?=\n)', BLANKLINE_MARKER, got) 758 if self._do_a_fancy_diff(want, got, optionflags): 759 want_lines = want.splitlines(True) 760 got_lines = got.splitlines(True) 761 if optionflags & REPORT_UDIFF: 762 diff = difflib.unified_diff(want_lines, got_lines, n=2) 763 diff = list(diff)[2:] 764 kind = 'unified diff with -expected +actual' 765 elif optionflags & REPORT_CDIFF: 766 diff = difflib.context_diff(want_lines, got_lines, n=2) 767 diff = list(diff)[2:] 768 kind = 'context diff with expected followed by actual' 769 elif optionflags & REPORT_NDIFF: 770 engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) 771 diff = list(engine.compare(want_lines, got_lines)) 772 kind = 'ndiff with -expected +actual' 773 diff = [ line.rstrip() + '\n' for line in diff ] 774 return 'Differences (%s):\n' % kind + _indent(''.join(diff)) 775 elif want and got: 776 return 'Expected:\n%sGot:\n%s' % (_indent(want), _indent(got)) 777 elif want: 778 return 'Expected:\n%sGot nothing\n' % _indent(want) 779 elif got: 780 return 'Expected nothing\nGot:\n%s' % _indent(got) 781 else: 782 return 'Expected nothing\nGot nothing\n' 783 784 785 class DocTestFailure(Exception): 786 787 def __init__(self, test, example, got): 788 self.test = test 789 self.example = example 790 self.got = got 791 792 def __str__(self): 793 return str(self.test) 794 795 796 class UnexpectedException(Exception): 797 798 def __init__(self, test, example, exc_info): 799 self.test = test 800 self.example = example 801 self.exc_info = exc_info 802 803 def __str__(self): 804 return str(self.test) 805 806 807 class DebugRunner(DocTestRunner): 808 809 def run(self, test, compileflags = None, out = None, clear_globs = True): 810 r = DocTestRunner.run(self, test, compileflags, out, False) 811 if clear_globs: 812 test.globs.clear() 813 return r 814 815 def report_unexpected_exception(self, out, test, example, exc_info): 816 raise UnexpectedException(test, example, exc_info) 817 818 def report_failure(self, out, test, example, got): 819 raise DocTestFailure(test, example, got) 820 821 822 master = None 823 824 def testmod(m = None, name = None, globs = None, verbose = None, report = True, optionflags = 0, extraglobs = None, raise_on_error = False, exclude_empty = False): 825 global master 826 if m is None: 827 m = sys.modules.get('__main__') 828 if not inspect.ismodule(m): 829 raise TypeError('testmod: module required; %r' % (m,)) 830 if name is None: 831 name = m.__name__ 832 finder = DocTestFinder(exclude_empty=exclude_empty) 833 if raise_on_error: 834 runner = DebugRunner(verbose=verbose, optionflags=optionflags) 835 else: 836 runner = DocTestRunner(verbose=verbose, optionflags=optionflags) 837 for test in finder.find(m, name, globs=globs, extraglobs=extraglobs): 838 runner.run(test) 839 840 if report: 841 runner.summarize() 842 if master is None: 843 master = runner 844 else: 845 master.merge(runner) 846 return TestResults(runner.failures, runner.tries) 847 848 849 def testfile(filename, module_relative = True, name = None, package = None, globs = None, verbose = None, report = True, optionflags = 0, extraglobs = None, raise_on_error = False, parser = DocTestParser(), encoding = None): 850 global master 851 if package and not module_relative: 852 raise ValueError('Package may only be specified for module-relative paths.') 853 text, filename = _load_testfile(filename, package, module_relative) 854 if name is None: 855 name = os.path.basename(filename) 856 if globs is None: 857 globs = {} 858 else: 859 globs = globs.copy() 860 if extraglobs is not None: 861 globs.update(extraglobs) 862 if '__name__' not in globs: 863 globs['__name__'] = '__main__' 864 if raise_on_error: 865 runner = DebugRunner(verbose=verbose, optionflags=optionflags) 866 else: 867 runner = DocTestRunner(verbose=verbose, optionflags=optionflags) 868 if encoding is not None: 869 text = text.decode(encoding) 870 test = parser.get_doctest(text, globs, name, filename, 0) 871 runner.run(test) 872 if report: 873 runner.summarize() 874 if master is None: 875 master = runner 876 else: 877 master.merge(runner) 878 return TestResults(runner.failures, runner.tries) 879 880 881 def run_docstring_examples(f, globs, verbose = False, name = 'NoName', compileflags = None, optionflags = 0): 882 finder = DocTestFinder(verbose=verbose, recurse=False) 883 runner = DocTestRunner(verbose=verbose, optionflags=optionflags) 884 for test in finder.find(f, name, globs=globs): 885 runner.run(test, compileflags=compileflags) 886 887 888 class Tester(): 889 890 def __init__(self, mod = None, globs = None, verbose = None, optionflags = 0): 891 warnings.warn('class Tester is deprecated; use class doctest.DocTestRunner instead', DeprecationWarning, stacklevel=2) 892 if mod is None and globs is None: 893 raise TypeError('Tester.__init__: must specify mod or globs') 894 if mod is not None and not inspect.ismodule(mod): 895 raise TypeError('Tester.__init__: mod must be a module; %r' % (mod,)) 896 if globs is None: 897 globs = mod.__dict__ 898 self.globs = globs 899 self.verbose = verbose 900 self.optionflags = optionflags 901 self.testfinder = DocTestFinder() 902 self.testrunner = DocTestRunner(verbose=verbose, optionflags=optionflags) 903 904 def runstring(self, s, name): 905 test = DocTestParser().get_doctest(s, self.globs, name, None, None) 906 if self.verbose: 907 print 'Running string', name 908 f, t = self.testrunner.run(test) 909 if self.verbose: 910 print f, 'of', t, 'examples failed in string', name 911 return TestResults(f, t) 912 913 def rundoc(self, object, name = None, module = None): 914 f = t = 0 915 tests = self.testfinder.find(object, name, module=module, globs=self.globs) 916 for test in tests: 917 f2, t2 = self.testrunner.run(test) 918 f, t = f + f2, t + t2 919 920 return TestResults(f, t) 921 922 def rundict(self, d, name, module = None): 923 import types 924 m = types.ModuleType(name) 925 m.__dict__.update(d) 926 if module is None: 927 module = False 928 return self.rundoc(m, name, module) 929 930 def run__test__(self, d, name): 931 import types 932 m = types.ModuleType(name) 933 m.__test__ = d 934 return self.rundoc(m, name) 935 936 def summarize(self, verbose = None): 937 return self.testrunner.summarize(verbose) 938 939 def merge(self, other): 940 self.testrunner.merge(other.testrunner) 941 942 943 _unittest_reportflags = 0 944 945 def set_unittest_reportflags(flags): 946 global _unittest_reportflags 947 if flags & REPORTING_FLAGS != flags: 948 raise ValueError('Only reporting flags allowed', flags) 949 old = _unittest_reportflags 950 _unittest_reportflags = flags 951 return old 952 953 954 class DocTestCase(unittest.TestCase): 955 956 def __init__(self, test, optionflags = 0, setUp = None, tearDown = None, checker = None): 957 unittest.TestCase.__init__(self) 958 self._dt_optionflags = optionflags 959 self._dt_checker = checker 960 self._dt_test = test 961 self._dt_setUp = setUp 962 self._dt_tearDown = tearDown 963 964 def setUp(self): 965 test = self._dt_test 966 if self._dt_setUp is not None: 967 self._dt_setUp(test) 968 969 def tearDown(self): 970 test = self._dt_test 971 if self._dt_tearDown is not None: 972 self._dt_tearDown(test) 973 test.globs.clear() 974 975 def runTest(self): 976 test = self._dt_test 977 old = sys.stdout 978 new = StringIO() 979 optionflags = self._dt_optionflags 980 if not optionflags & REPORTING_FLAGS: 981 optionflags |= _unittest_reportflags 982 runner = DocTestRunner(optionflags=optionflags, checker=self._dt_checker, verbose=False) 983 try: 984 runner.DIVIDER = '-' * 70 985 failures, tries = runner.run(test, out=new.write, clear_globs=False) 986 finally: 987 sys.stdout = old 988 989 if failures: 990 raise self.failureException(self.format_failure(new.getvalue())) 991 992 def format_failure(self, err): 993 test = self._dt_test 994 if test.lineno is None: 995 lineno = 'unknown line number' 996 else: 997 lineno = '%s' % test.lineno 998 lname = '.'.join(test.name.split('.')[-1:]) 999 return 'Failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' % (test.name, 1000 test.filename, 1001 lineno, 1002 lname, 1003 err) 1004 1005 def debug(self): 1006 self.setUp() 1007 runner = DebugRunner(optionflags=self._dt_optionflags, checker=self._dt_checker, verbose=False) 1008 runner.run(self._dt_test, clear_globs=False) 1009 self.tearDown() 1010 1011 def id(self): 1012 return self._dt_test.name 1013 1014 def __repr__(self): 1015 name = self._dt_test.name.split('.') 1016 return '%s (%s)' % (name[-1], '.'.join(name[:-1])) 1017 1018 __str__ = __repr__ 1019 1020 def shortDescription(self): 1021 return 'Doctest: ' + self._dt_test.name 1022 1023 1024 class SkipDocTestCase(DocTestCase): 1025 1026 def __init__(self): 1027 DocTestCase.__init__(self, None) 1028 1029 def setUp(self): 1030 self.skipTest('DocTestSuite will not work with -O2 and above') 1031 1032 def test_skip(self): 1033 pass 1034 1035 def shortDescription(self): 1036 return 'Skipping tests from %s' % module.__name__ 1037 1038 1039 def DocTestSuite(module = None, globs = None, extraglobs = None, test_finder = None, **options): 1040 if test_finder is None: 1041 test_finder = DocTestFinder() 1042 module = _normalize_module(module) 1043 tests = test_finder.find(module, globs=globs, extraglobs=extraglobs) 1044 if not tests and sys.flags.optimize >= 2: 1045 suite = unittest.TestSuite() 1046 suite.addTest(SkipDocTestCase()) 1047 return suite 1048 if not tests: 1049 raise ValueError(module, 'has no tests') 1050 tests.sort() 1051 suite = unittest.TestSuite() 1052 for test in tests: 1053 if len(test.examples) == 0: 1054 continue 1055 if not test.filename: 1056 filename = module.__file__ 1057 if filename[-4:] in ('.pyc', '.pyo'): 1058 filename = filename[:-1] 1059 test.filename = filename 1060 suite.addTest(DocTestCase(test, **options)) 1061 1062 return suite 1063 1064 1065 class DocFileCase(DocTestCase): 1066 1067 def id(self): 1068 return '_'.join(self._dt_test.name.split('.')) 1069 1070 def __repr__(self): 1071 return self._dt_test.filename 1072 1073 __str__ = __repr__ 1074 1075 def format_failure(self, err): 1076 return 'Failed doctest test for %s\n File "%s", line 0\n\n%s' % (self._dt_test.name, self._dt_test.filename, err) 1077 1078 1079 def DocFileTest(path, module_relative = True, package = None, globs = None, parser = DocTestParser(), encoding = None, **options): 1080 if globs is None: 1081 globs = {} 1082 else: 1083 globs = globs.copy() 1084 if package and not module_relative: 1085 raise ValueError('Package may only be specified for module-relative paths.') 1086 doc, path = _load_testfile(path, package, module_relative) 1087 if '__file__' not in globs: 1088 globs['__file__'] = path 1089 name = os.path.basename(path) 1090 if encoding is not None: 1091 doc = doc.decode(encoding) 1092 test = parser.get_doctest(doc, globs, name, path, 0) 1093 return DocFileCase(test, **options) 1094 1095 1096 def DocFileSuite(*paths, **kw): 1097 suite = unittest.TestSuite() 1098 if kw.get('module_relative', True): 1099 kw['package'] = _normalize_module(kw.get('package')) 1100 for path in paths: 1101 suite.addTest(DocFileTest(path, **kw)) 1102 1103 return suite 1104 1105 1106 def script_from_examples(s): 1107 output = [] 1108 for piece in DocTestParser().parse(s): 1109 if isinstance(piece, Example): 1110 output.append(piece.source[:-1]) 1111 want = piece.want 1112 if want: 1113 output.append('# Expected:') 1114 output += [ '## ' + l for l in want.split('\n')[:-1] ] 1115 else: 1116 output += [ _comment_line(l) for l in piece.split('\n')[:-1] ] 1117 1118 while output and output[-1] == '#': 1119 output.pop() 1120 1121 while output and output[0] == '#': 1122 output.pop(0) 1123 1124 return '\n'.join(output) + '\n' 1125 1126 1127 def testsource(module, name): 1128 module = _normalize_module(module) 1129 tests = DocTestFinder().find(module) 1130 test = [ t for t in tests if t.name == name ] 1131 if not test: 1132 raise ValueError(name, 'not found in tests') 1133 test = test[0] 1134 testsrc = script_from_examples(test.docstring) 1135 return testsrc 1136 1137 1138 def debug_src(src, pm = False, globs = None): 1139 testsrc = script_from_examples(src) 1140 debug_script(testsrc, pm, globs) 1141 1142 1143 def debug_script(src, pm = False, globs = None): 1144 import pdb 1145 srcfilename = tempfile.mktemp('.py', 'doctestdebug') 1146 f = open(srcfilename, 'w') 1147 f.write(src) 1148 f.close() 1149 try: 1150 if globs: 1151 globs = globs.copy() 1152 else: 1153 globs = {} 1154 if pm: 1155 try: 1156 execfile(srcfilename, globs, globs) 1157 except: 1158 print sys.exc_info()[1] 1159 pdb.post_mortem(sys.exc_info()[2]) 1160 1161 else: 1162 pdb.run('execfile(%r)' % srcfilename, globs, globs) 1163 finally: 1164 os.remove(srcfilename) 1165 1166 1167 def debug(module, name, pm = False): 1168 module = _normalize_module(module) 1169 testsrc = testsource(module, name) 1170 debug_script(testsrc, pm, module.__dict__) 1171 1172 1173 class _TestClass(): 1174 1175 def __init__(self, val): 1176 self.val = val 1177 1178 def square(self): 1179 self.val = self.val ** 2 1180 return self 1181 1182 def get(self): 1183 return self.val 1184 1185 1186 __test__ = {'_TestClass': _TestClass, 1187 'string': '\n Example of a string object, searched as-is.\n >>> x = 1; y = 2\n >>> x + y, x * y\n (3, 2)\n ', 1188 'bool-int equivalence': '\n In 2.2, boolean expressions displayed\n 0 or 1. By default, we still accept\n them. This can be disabled by passing\n DONT_ACCEPT_TRUE_FOR_1 to the new\n optionflags argument.\n >>> 4 == 4\n 1\n >>> 4 == 4\n True\n >>> 4 > 4\n 0\n >>> 4 > 4\n False\n ', 1189 'blank lines': "\n Blank lines can be marked with <BLANKLINE>:\n >>> print 'foo\\n\\nbar\\n'\n foo\n <BLANKLINE>\n bar\n <BLANKLINE>\n ", 1190 'ellipsis': "\n If the ellipsis flag is used, then '...' can be used to\n elide substrings in the desired output:\n >>> print range(1000) #doctest: +ELLIPSIS\n [0, 1, 2, ..., 999]\n ", 1191 'whitespace normalization': '\n If the whitespace normalization flag is used, then\n differences in whitespace are ignored.\n >>> print range(30) #doctest: +NORMALIZE_WHITESPACE\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,\n 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,\n 27, 28, 29]\n '} 1192 1193 def _test(): 1194 testfiles = [ arg for arg in sys.argv[1:] if arg and arg[0] != '-' ] 1195 if not testfiles: 1196 name = os.path.basename(sys.argv[0]) 1197 if '__loader__' in globals(): 1198 name, _ = os.path.splitext(name) 1199 print 'usage: {0} [-v] file ...'.format(name) 1200 return 2 1201 for filename in testfiles: 1202 if filename.endswith('.py'): 1203 dirname, filename = os.path.split(filename) 1204 sys.path.insert(0, dirname) 1205 m = __import__(filename[:-3]) 1206 del sys.path[0] 1207 failures, _ = testmod(m) 1208 else: 1209 failures, _ = testfile(filename, module_relative=False) 1210 if failures: 1211 return 1 1212 1213 return 0 1214 1215 1216 if __name__ == '__main__': 1217 sys.exit(_test())