Loading django/test/_doctest.py +103 −16 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ import unittest, difflib, pdb, tempfile import warnings from django.utils import six from django.utils.six import StringIO from django.utils.six.moves import StringIO, xrange if sys.platform.startswith('java'): # On Jython, isclass() reports some modules as classes. Patch it. Loading Loading @@ -501,11 +501,31 @@ class DocTest: # This lets us sort tests by name: def _cmpkey(self): return (self.name, self.filename, self.lineno, id(self)) def __cmp__(self, other): if not isinstance(other, DocTest): return -1 return cmp((self.name, self.filename, self.lineno, id(self)), (other.name, other.filename, other.lineno, id(other))) return cmp(self._cmpkey(), other._cmpkey()) def __lt__(self, other): return self._cmpkey() < other._cmpkey() def __le__(self, other): return self._cmpkey() <= other._cmpkey() def __gt__(self, other): return self._cmpkey() > other._cmpkey() def __ge__(self, other): return self._cmpkey() >= other._cmpkey() def __eq__(self, other): return self._cmpkey() == other._cmpkey() def __ne__(self, other): return self._cmpkey() != other._cmpkey() ###################################################################### ## 3. DocTestParser Loading Loading @@ -1229,6 +1249,57 @@ class DocTestRunner: # __patched_linecache_getlines). filename = '<doctest %s[%d]>' % (test.name, examplenum) # Doctest and Py3 issue: # If the current example that we wish to run is going to fail # because it expects a leading u"", then use an alternate displayhook original_displayhook = sys.displayhook if six.PY3: # only set alternate displayhook if Python 3.x or after lines = [] def py3_displayhook(value): if value is None: # None should not be considered at all return original_displayhook(value) # Collect the repr output in one variable s = repr(value) # Strip b"" and u"" prefixes from the repr and expected output # TODO: better way of stripping the prefixes? expected = example.want expected = expected.strip() # be wary of newlines s = s.replace("u", "") s = s.replace("b", "") expected = expected.replace("u", "") expected = expected.replace("b", "") # single quote vs. double quote should not matter # default all quote marks to double quote s = s.replace("'", '"') expected = expected.replace("'", '"') # In case of multi-line expected result lines.append(s) # let them match if s == expected: # be wary of false positives here # they should be the same, print expected value sys.stdout.write("%s\n" % example.want.strip()) # multi-line expected output, doctest uses loop elif len(expected.split("\n")) == len(lines): if "\n".join(lines) == expected: sys.stdout.write("%s\n" % example.want.strip()) else: sys.stdout.write("%s\n" % repr(value)) elif len(expected.split("\n")) != len(lines): # we are not done looping yet, do not print anything! pass else: sys.stdout.write("%s\n" % repr(value)) sys.displayhook = py3_displayhook # Run the example in the given context (globs), and record # any exception that gets raised. (But don't intercept # keyboard interrupts.) Loading @@ -1243,9 +1314,14 @@ class DocTestRunner: except: exception = sys.exc_info() self.debugger.set_continue() # ==== Example Finished ==== finally: # restore the original displayhook sys.displayhook = original_displayhook got = self._fakeout.getvalue() # the actual output self._fakeout.truncate(0) # Python 3.1 requires seek after truncate self._fakeout.seek(0) outcome = FAILURE # guilty until proved innocent or insane # If the example executed without raising any exceptions, Loading @@ -1256,10 +1332,21 @@ class DocTestRunner: # The example raised an exception: check if it was expected. else: exc_info = sys.exc_info() exc_msg = traceback.format_exception_only(*exc_info[:2])[-1] exc_msg = traceback.format_exception_only(*exception[:2])[-1] if six.PY3: # module name will be in group(1) and the expected # exception message will be in group(2) m = re.match(r'(.*)\.(\w+:.+\s)', exc_msg) # make sure there's a match if m != None: f_name = m.group(1) # check to see if m.group(1) contains the module name if f_name == exception[0].__module__: # strip the module name from exc_msg exc_msg = m.group(2) if not quiet: got += _exception_traceback(exc_info) got += _exception_traceback(exception) # If `example.exc_msg` is None, then we weren't expecting # an exception. Loading Loading @@ -1289,7 +1376,7 @@ class DocTestRunner: elif outcome is BOOM: if not quiet: self.report_unexpected_exception(out, test, example, exc_info) exception) failures += 1 else: assert False, ("unknown outcome", outcome) Loading Loading @@ -1629,8 +1716,8 @@ class DebugRunner(DocTestRunner): ... {}, 'foo', 'foo.py', 0) >>> try: ... runner.run(test) ... except UnexpectedException as failure: ... pass ... except UnexpectedException as e: ... failure = e >>> failure.test is test True Loading @@ -1657,8 +1744,8 @@ class DebugRunner(DocTestRunner): >>> try: ... runner.run(test) ... except DocTestFailure as failure: ... pass ... except DocTestFailure as e: ... failure = e DocTestFailure objects provide access to the test: Loading Loading @@ -2167,8 +2254,8 @@ class DocTestCase(unittest.TestCase): >>> case = DocTestCase(test) >>> try: ... case.debug() ... except UnexpectedException as failure: ... pass ... except UnexpectedException as e: ... failure = e The UnexpectedException contains the test, the example, and the original exception: Loading Loading @@ -2196,8 +2283,8 @@ class DocTestCase(unittest.TestCase): >>> try: ... case.debug() ... except DocTestFailure as failure: ... pass ... except DocTestFailure as e: ... failure = e DocTestFailure objects provide access to the test: Loading Loading @@ -2646,7 +2733,7 @@ __test__ = {"_TestClass": _TestClass, "whitespace normalization": r""" If the whitespace normalization flag is used, then differences in whitespace are ignored. >>> print(range(30)) #doctest: +NORMALIZE_WHITESPACE >>> print(list(xrange(30))) #doctest: +NORMALIZE_WHITESPACE [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] Loading Loading
django/test/_doctest.py +103 −16 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ import unittest, difflib, pdb, tempfile import warnings from django.utils import six from django.utils.six import StringIO from django.utils.six.moves import StringIO, xrange if sys.platform.startswith('java'): # On Jython, isclass() reports some modules as classes. Patch it. Loading Loading @@ -501,11 +501,31 @@ class DocTest: # This lets us sort tests by name: def _cmpkey(self): return (self.name, self.filename, self.lineno, id(self)) def __cmp__(self, other): if not isinstance(other, DocTest): return -1 return cmp((self.name, self.filename, self.lineno, id(self)), (other.name, other.filename, other.lineno, id(other))) return cmp(self._cmpkey(), other._cmpkey()) def __lt__(self, other): return self._cmpkey() < other._cmpkey() def __le__(self, other): return self._cmpkey() <= other._cmpkey() def __gt__(self, other): return self._cmpkey() > other._cmpkey() def __ge__(self, other): return self._cmpkey() >= other._cmpkey() def __eq__(self, other): return self._cmpkey() == other._cmpkey() def __ne__(self, other): return self._cmpkey() != other._cmpkey() ###################################################################### ## 3. DocTestParser Loading Loading @@ -1229,6 +1249,57 @@ class DocTestRunner: # __patched_linecache_getlines). filename = '<doctest %s[%d]>' % (test.name, examplenum) # Doctest and Py3 issue: # If the current example that we wish to run is going to fail # because it expects a leading u"", then use an alternate displayhook original_displayhook = sys.displayhook if six.PY3: # only set alternate displayhook if Python 3.x or after lines = [] def py3_displayhook(value): if value is None: # None should not be considered at all return original_displayhook(value) # Collect the repr output in one variable s = repr(value) # Strip b"" and u"" prefixes from the repr and expected output # TODO: better way of stripping the prefixes? expected = example.want expected = expected.strip() # be wary of newlines s = s.replace("u", "") s = s.replace("b", "") expected = expected.replace("u", "") expected = expected.replace("b", "") # single quote vs. double quote should not matter # default all quote marks to double quote s = s.replace("'", '"') expected = expected.replace("'", '"') # In case of multi-line expected result lines.append(s) # let them match if s == expected: # be wary of false positives here # they should be the same, print expected value sys.stdout.write("%s\n" % example.want.strip()) # multi-line expected output, doctest uses loop elif len(expected.split("\n")) == len(lines): if "\n".join(lines) == expected: sys.stdout.write("%s\n" % example.want.strip()) else: sys.stdout.write("%s\n" % repr(value)) elif len(expected.split("\n")) != len(lines): # we are not done looping yet, do not print anything! pass else: sys.stdout.write("%s\n" % repr(value)) sys.displayhook = py3_displayhook # Run the example in the given context (globs), and record # any exception that gets raised. (But don't intercept # keyboard interrupts.) Loading @@ -1243,9 +1314,14 @@ class DocTestRunner: except: exception = sys.exc_info() self.debugger.set_continue() # ==== Example Finished ==== finally: # restore the original displayhook sys.displayhook = original_displayhook got = self._fakeout.getvalue() # the actual output self._fakeout.truncate(0) # Python 3.1 requires seek after truncate self._fakeout.seek(0) outcome = FAILURE # guilty until proved innocent or insane # If the example executed without raising any exceptions, Loading @@ -1256,10 +1332,21 @@ class DocTestRunner: # The example raised an exception: check if it was expected. else: exc_info = sys.exc_info() exc_msg = traceback.format_exception_only(*exc_info[:2])[-1] exc_msg = traceback.format_exception_only(*exception[:2])[-1] if six.PY3: # module name will be in group(1) and the expected # exception message will be in group(2) m = re.match(r'(.*)\.(\w+:.+\s)', exc_msg) # make sure there's a match if m != None: f_name = m.group(1) # check to see if m.group(1) contains the module name if f_name == exception[0].__module__: # strip the module name from exc_msg exc_msg = m.group(2) if not quiet: got += _exception_traceback(exc_info) got += _exception_traceback(exception) # If `example.exc_msg` is None, then we weren't expecting # an exception. Loading Loading @@ -1289,7 +1376,7 @@ class DocTestRunner: elif outcome is BOOM: if not quiet: self.report_unexpected_exception(out, test, example, exc_info) exception) failures += 1 else: assert False, ("unknown outcome", outcome) Loading Loading @@ -1629,8 +1716,8 @@ class DebugRunner(DocTestRunner): ... {}, 'foo', 'foo.py', 0) >>> try: ... runner.run(test) ... except UnexpectedException as failure: ... pass ... except UnexpectedException as e: ... failure = e >>> failure.test is test True Loading @@ -1657,8 +1744,8 @@ class DebugRunner(DocTestRunner): >>> try: ... runner.run(test) ... except DocTestFailure as failure: ... pass ... except DocTestFailure as e: ... failure = e DocTestFailure objects provide access to the test: Loading Loading @@ -2167,8 +2254,8 @@ class DocTestCase(unittest.TestCase): >>> case = DocTestCase(test) >>> try: ... case.debug() ... except UnexpectedException as failure: ... pass ... except UnexpectedException as e: ... failure = e The UnexpectedException contains the test, the example, and the original exception: Loading Loading @@ -2196,8 +2283,8 @@ class DocTestCase(unittest.TestCase): >>> try: ... case.debug() ... except DocTestFailure as failure: ... pass ... except DocTestFailure as e: ... failure = e DocTestFailure objects provide access to the test: Loading Loading @@ -2646,7 +2733,7 @@ __test__ = {"_TestClass": _TestClass, "whitespace normalization": r""" If the whitespace normalization flag is used, then differences in whitespace are ignored. >>> print(range(30)) #doctest: +NORMALIZE_WHITESPACE >>> print(list(xrange(30))) #doctest: +NORMALIZE_WHITESPACE [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] Loading