| OLD | NEW |
| 1 # Module doctest. | 1 # Module doctest. |
| 2 # Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org). | 2 # Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org). |
| 3 # Major enhancements and refactoring by: | 3 # Major enhancements and refactoring by: |
| 4 # Jim Fulton | 4 # Jim Fulton |
| 5 # Edward Loper | 5 # Edward Loper |
| 6 | 6 |
| 7 # Provided as-is; use at your own risk; no warranty; no promises; enjoy! | 7 # Provided as-is; use at your own risk; no warranty; no promises; enjoy! |
| 8 | 8 |
| 9 r"""Module doctest -- a framework for running examples in docstrings. | 9 r"""Module doctest -- a framework for running examples in docstrings. |
| 10 | 10 |
| 11 In simplest use, end each module M to be tested with: | 11 In simplest use, end each module M to be tested with: |
| 12 | 12 |
| 13 def _test(): | 13 def _test(): |
| 14 import doctest | 14 import doctest |
| 15 doctest.testmod() | 15 doctest.testmod() |
| 16 | 16 |
| 17 if __name__ == "__main__": | 17 if __name__ == "__main__": |
| 18 _test() | 18 _test() |
| 19 | 19 |
| 20 Then running the module as a script will cause the examples in the | 20 Then running the module as a script will cause the examples in the |
| 21 docstrings to get executed and verified: | 21 docstrings to get executed and verified: |
| 22 | 22 |
| 23 python M.py | 23 python M.py |
| 24 | 24 |
| 25 This won't display anything unless an example fails, in which case the | 25 This won't display anything unless an example fails, in which case the |
| 26 failing example(s) and the cause(s) of the failure(s) are printed to stdout | 26 failing example(s) and the cause(s) of the failure(s) are printed to stdout |
| 27 (why not stderr? because stderr is a lame hack <0.2 wink>), and the final | 27 (why not stderr? because stderr is a lame hack <0.2 wink>), and the final |
| 28 line of output is "Test failed.". | 28 line of output is "Test failed.". |
| 29 | 29 |
| 30 Run it with the -v switch instead: | 30 Run it with the -v switch instead: |
| 31 | 31 |
| 32 python M.py -v | 32 python M.py -v |
| 33 | 33 |
| 34 and a detailed report of all examples tried is printed to stdout, along | 34 and a detailed report of all examples tried is printed to stdout, along |
| 35 with assorted summaries at the end. | 35 with assorted summaries at the end. |
| 36 | 36 |
| 37 You can force verbose mode by passing "verbose=True" to testmod, or prohibit | 37 You can force verbose mode by passing "verbose=True" to testmod, or prohibit |
| 38 it by passing "verbose=False". In either of those cases, sys.argv is not | 38 it by passing "verbose=False". In either of those cases, sys.argv is not |
| 39 examined by testmod. | 39 examined by testmod. |
| 40 | 40 |
| 41 There are a variety of other ways to run doctests, including integration | 41 There are a variety of other ways to run doctests, including integration |
| 42 with the unittest framework, and support for running non-Python text | 42 with the unittest framework, and support for running non-Python text |
| 43 files containing doctests. There are also many ways to override parts | 43 files containing doctests. There are also many ways to override parts |
| 44 of doctest's default behaviors. See the Library Reference Manual for | 44 of doctest's default behaviors. See the Library Reference Manual for |
| 45 details. | 45 details. |
| 46 """ | 46 """ |
| 47 | 47 |
| 48 __docformat__ = 'reStructuredText en' | 48 __docformat__ = 'reStructuredText en' |
| 49 | 49 |
| 50 __all__ = [ | 50 __all__ = [ |
| (...skipping 1346 matching lines...) Show 10 above Show 10 below |
| 1397 else: | 1397 else: |
| 1398 failed.append(x) | 1398 failed.append(x) |
| 1399 if verbose: | 1399 if verbose: |
| 1400 if notests: | 1400 if notests: |
| 1401 print(len(notests), "items had no tests:") | 1401 print(len(notests), "items had no tests:") |
| 1402 notests.sort() | 1402 notests.sort() |
| 1403 for thing in notests: | 1403 for thing in notests: |
| 1404 print(" ", thing) | 1404 print(" ", thing) |
| 1405 if passed: | 1405 if passed: |
| 1406 print(len(passed), "items passed all tests:") | 1406 print(len(passed), "items passed all tests:") |
| 1407 passed.sort() | 1407 passed.sort() |
| 1408 for thing, count in passed: | 1408 for thing, count in passed: |
| 1409 print(" %3d tests in %s" % (count, thing)) | 1409 print(" %3d tests in %s" % (count, thing)) |
| 1410 if failed: | 1410 if failed: |
| 1411 print(self.DIVIDER) | 1411 print(self.DIVIDER) |
| 1412 print(len(failed), "items had failures:") | 1412 print(len(failed), "items had failures:") |
| 1413 failed.sort() | 1413 failed.sort() |
| 1414 for thing, (f, t) in failed: | 1414 for thing, (f, t) in failed: |
| 1415 print(" %3d of %3d in %s" % (f, t, thing)) | 1415 print(" %3d of %3d in %s" % (f, t, thing)) |
| 1416 if verbose: | 1416 if verbose: |
| 1417 print(totalt, "tests in", len(self._name2ft), "items.") | 1417 print(totalt, "tests in", len(self._name2ft), "items.") |
| 1418 print(totalt - totalf, "passed and", totalf, "failed.") | 1418 print(totalt - totalf, "passed and", totalf, "failed.") |
| 1419 if totalf: | 1419 if totalf: |
| 1420 print("***Test Failed***", totalf, "failures.") | 1420 print("***Test Failed***", totalf, "failures.") |
| 1421 elif verbose: | 1421 elif verbose: |
| 1422 print("Test passed.") | 1422 print("Test passed.") |
| 1423 return TestResults(totalf, totalt) | 1423 return TestResults(totalf, totalt) |
| 1424 | 1424 |
| 1425 #///////////////////////////////////////////////////////////////// | 1425 #///////////////////////////////////////////////////////////////// |
| 1426 # Backward compatibility cruft to maintain doctest.master. | 1426 # Backward compatibility cruft to maintain doctest.master. |
| 1427 #///////////////////////////////////////////////////////////////// | 1427 #///////////////////////////////////////////////////////////////// |
| 1428 def merge(self, other): | 1428 def merge(self, other): |
| 1429 d = self._name2ft | 1429 d = self._name2ft |
| 1430 for name, (f, t) in other._name2ft.items(): | 1430 for name, (f, t) in other._name2ft.items(): |
| 1431 if name in d: | 1431 if name in d: |
| 1432 print("*** DocTestRunner.merge: '" + name + "' in both" \ | 1432 print("*** DocTestRunner.merge: '" + name + "' in both" \ |
| 1433 " testers; summing outcomes.") | 1433 " testers; summing outcomes.") |
| 1434 f2, t2 = d[name] | 1434 f2, t2 = d[name] |
| 1435 f = f + f2 | 1435 f = f + f2 |
| 1436 t = t + t2 | 1436 t = t + t2 |
| 1437 d[name] = f, t | 1437 d[name] = f, t |
| 1438 | 1438 |
| 1439 class OutputChecker: | 1439 class OutputChecker: |
| 1440 """ | 1440 """ |
| 1441 A class used to check the whether the actual output from a doctest | 1441 A class used to check the whether the actual output from a doctest |
| 1442 example matches the expected output. `OutputChecker` defines two | 1442 example matches the expected output. `OutputChecker` defines two |
| 1443 methods: `check_output`, which compares a given pair of outputs, | 1443 methods: `check_output`, which compares a given pair of outputs, |
| 1444 and returns true if they match; and `output_difference`, which | 1444 and returns true if they match; and `output_difference`, which |
| 1445 returns a string describing the differences between two outputs. | 1445 returns a string describing the differences between two outputs. |
| 1446 """ | 1446 """ |
| 1447 |
| 1448 def _toAscii(self, s): |
| 1449 """ |
| 1450 Convert string to hex-escaped ASCII string. |
| 1451 """ |
| 1452 return str(s.encode('ASCII', 'backslashreplace'), "ASCII") |
| 1453 |
| 1447 def check_output(self, want, got, optionflags): | 1454 def check_output(self, want, got, optionflags): |
| 1448 """ | 1455 """ |
| 1449 Return True iff the actual output from an example (`got`) | 1456 Return True iff the actual output from an example (`got`) |
| 1450 matches the expected output (`want`). These strings are | 1457 matches the expected output (`want`). These strings are |
| 1451 always considered to match if they are identical; but | 1458 always considered to match if they are identical; but |
| 1452 depending on what option flags the test runner is using, | 1459 depending on what option flags the test runner is using, |
| 1453 several non-exact match types are also possible. See the | 1460 several non-exact match types are also possible. See the |
| 1454 documentation for `TestRunner` for more information about | 1461 documentation for `TestRunner` for more information about |
| 1455 option flags. | 1462 option flags. |
| 1456 """ | 1463 """ |
| 1464 |
| 1465 # If `want` contains hex-escaped character such as "\u1234", |
| 1466 # then `want` is a string of six characters(e.g. [\,u,1,2,3,4]). |
| 1467 # On the other hand, `got` could be an another sequence of |
| 1468 # characters such as [\u1234], so `want` and `got` should |
| 1469 # be folded to hex-escaped ASCII string to compare. |
| 1470 got = self._toAscii(got) |
| 1471 want = self._toAscii(want) |
| 1472 |
| 1457 # Handle the common case first, for efficiency: | 1473 # Handle the common case first, for efficiency: |
| 1458 # if they're string-identical, always return true. | 1474 # if they're string-identical, always return true. |
| 1459 if got == want: | 1475 if got == want: |
| 1460 return True | 1476 return True |
| 1461 | 1477 |
| 1462 # The values True and False replaced 1 and 0 as the return | 1478 # The values True and False replaced 1 and 0 as the return |
| 1463 # value for boolean comparisons in Python 2.3. | 1479 # value for boolean comparisons in Python 2.3. |
| 1464 if not (optionflags & DONT_ACCEPT_TRUE_FOR_1): | 1480 if not (optionflags & DONT_ACCEPT_TRUE_FOR_1): |
| 1465 if (got,want) == ("True\n", "1\n"): | 1481 if (got,want) == ("True\n", "1\n"): |
| 1466 return True | 1482 return True |
| 1467 if (got,want) == ("False\n", "0\n"): | 1483 if (got,want) == ("False\n", "0\n"): |
| 1468 return True | 1484 return True |
| 1469 | 1485 |
| 1470 # <BLANKLINE> can be used as a special sequence to signify a | 1486 # <BLANKLINE> can be used as a special sequence to signify a |
| 1471 # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. | 1487 # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. |
| 1472 if not (optionflags & DONT_ACCEPT_BLANKLINE): | 1488 if not (optionflags & DONT_ACCEPT_BLANKLINE): |
| 1473 # Replace <BLANKLINE> in want with a blank line. | 1489 # Replace <BLANKLINE> in want with a blank line. |
| 1474 want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER), | 1490 want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER), |
| 1475 '', want) | 1491 '', want) |
| 1476 # If a line in got contains only spaces, then remove the | 1492 # If a line in got contains only spaces, then remove the |
| 1477 # spaces. | 1493 # spaces. |
| 1478 got = re.sub('(?m)^\s*?$', '', got) | 1494 got = re.sub('(?m)^\s*?$', '', got) |
| 1479 if got == want: | 1495 if got == want: |
| 1480 return True | 1496 return True |
| 1481 | 1497 |
| 1482 # This flag causes doctest to ignore any differences in the | 1498 # This flag causes doctest to ignore any differences in the |
| 1483 # contents of whitespace strings. Note that this can be used | 1499 # contents of whitespace strings. Note that this can be used |
| 1484 # in conjunction with the ELLIPSIS flag. | 1500 # in conjunction with the ELLIPSIS flag. |
| 1485 if optionflags & NORMALIZE_WHITESPACE: | 1501 if optionflags & NORMALIZE_WHITESPACE: |
| 1486 got = ' '.join(got.split()) | 1502 got = ' '.join(got.split()) |
| 1487 want = ' '.join(want.split()) | 1503 want = ' '.join(want.split()) |
| 1488 if got == want: | 1504 if got == want: |
| 1489 return True | 1505 return True |
| 1490 | 1506 |
| 1491 # The ELLIPSIS flag says to let the sequence "..." in `want` | 1507 # The ELLIPSIS flag says to let the sequence "..." in `want` |
| 1492 # match any substring in `got`. | 1508 # match any substring in `got`. |
| 1493 if optionflags & ELLIPSIS: | 1509 if optionflags & ELLIPSIS: |
| 1494 if _ellipsis_match(want, got): | 1510 if _ellipsis_match(want, got): |
| 1495 return True | 1511 return True |
| 1496 | 1512 |
| 1497 # We didn't find any match; return false. | 1513 # We didn't find any match; return false. |
| 1498 return False | 1514 return False |
| 1499 | 1515 |
| 1500 # Should we do a fancy diff? | 1516 # Should we do a fancy diff? |
| 1501 def _do_a_fancy_diff(self, want, got, optionflags): | 1517 def _do_a_fancy_diff(self, want, got, optionflags): |
| 1502 # Not unless they asked for a fancy diff. | 1518 # Not unless they asked for a fancy diff. |
| 1503 if not optionflags & (REPORT_UDIFF | | 1519 if not optionflags & (REPORT_UDIFF | |
| 1504 REPORT_CDIFF | | 1520 REPORT_CDIFF | |
| 1505 REPORT_NDIFF): | 1521 REPORT_NDIFF): |
| 1506 return False | 1522 return False |
| (...skipping 1112 matching lines...) Show 10 above Show 10 below |
| 2619 "blank lines": r""" | 2635 "blank lines": r""" |
| 2620 Blank lines can be marked with <BLANKLINE>: | 2636 Blank lines can be marked with <BLANKLINE>: |
| 2621 >>> print('foo\n\nbar\n') | 2637 >>> print('foo\n\nbar\n') |
| 2622 foo | 2638 foo |
| 2623 <BLANKLINE> | 2639 <BLANKLINE> |
| 2624 bar | 2640 bar |
| 2625 <BLANKLINE> | 2641 <BLANKLINE> |
| 2626 """, | 2642 """, |
| 2627 | 2643 |
| 2628 "ellipsis": r""" | 2644 "ellipsis": r""" |
| 2629 If the ellipsis flag is used, then '...' can be used to | 2645 If the ellipsis flag is used, then '...' can be used to |
| 2630 elide substrings in the desired output: | 2646 elide substrings in the desired output: |
| 2631 >>> print(list(range(1000))) #doctest: +ELLIPSIS | 2647 >>> print(list(range(1000))) #doctest: +ELLIPSIS |
| 2632 [0, 1, 2, ..., 999] | 2648 [0, 1, 2, ..., 999] |
| 2633 """, | 2649 """, |
| 2634 | 2650 |
| 2635 "whitespace normalization": r""" | 2651 "whitespace normalization": r""" |
| 2636 If the whitespace normalization flag is used, then | 2652 If the whitespace normalization flag is used, then |
| 2637 differences in whitespace are ignored. | 2653 differences in whitespace are ignored. |
| 2638 >>> print(list(range(30))) #doctest: +NORMALIZE_WHITESPACE | 2654 >>> print(list(range(30))) #doctest: +NORMALIZE_WHITESPACE |
| 2639 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | 2655 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 2640 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, | 2656 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, |
| 2641 27, 28, 29] | 2657 27, 28, 29] |
| 2642 """, | 2658 """, |
| 2643 } | 2659 } |
| 2644 | 2660 |
| 2645 def _test(): | 2661 def _test(): |
| 2646 testfiles = [arg for arg in sys.argv[1:] if arg and arg[0] != '-'] | 2662 testfiles = [arg for arg in sys.argv[1:] if arg and arg[0] != '-'] |
| 2647 if testfiles: | 2663 if testfiles: |
| 2648 for filename in testfiles: | 2664 for filename in testfiles: |
| 2649 if filename.endswith(".py"): | 2665 if filename.endswith(".py"): |
| 2650 # It is a module -- insert its dir into sys.path and try to | 2666 # It is a module -- insert its dir into sys.path and try to |
| 2651 # import it. If it is part of a package, that possibly won't wor
k | 2667 # import it. If it is part of a package, that possibly won't wor
k |
| 2652 # because of package imports. | 2668 # because of package imports. |
| 2653 dirname, filename = os.path.split(filename) | 2669 dirname, filename = os.path.split(filename) |
| 2654 sys.path.insert(0, dirname) | 2670 sys.path.insert(0, dirname) |
| 2655 m = __import__(filename[:-3]) | 2671 m = __import__(filename[:-3]) |
| 2656 del sys.path[0] | 2672 del sys.path[0] |
| 2657 failures, _ = testmod(m) | 2673 failures, _ = testmod(m) |
| 2658 else: | 2674 else: |
| 2659 failures, _ = testfile(filename, module_relative=False) | 2675 failures, _ = testfile(filename, module_relative=False) |
| 2660 if failures: | 2676 if failures: |
| 2661 return 1 | 2677 return 1 |
| 2662 else: | 2678 else: |
| 2663 r = unittest.TextTestRunner() | 2679 r = unittest.TextTestRunner() |
| 2664 r.run(DocTestSuite()) | 2680 r.run(DocTestSuite()) |
| 2665 return 0 | 2681 return 0 |
| 2666 | 2682 |
| 2667 if __name__ == "__main__": | 2683 if __name__ == "__main__": |
| 2668 sys.exit(_test()) | 2684 sys.exit(_test()) |
| OLD | NEW |