python/dist/src/Lib doctest.py,1.114,1.115

Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32322/dist/src/Lib Modified Files: doctest.py Log Message: Added a new NORMALIZE_NUMBERS option, which causes number literals in the expected output to match corresponding number literals in the actual output if their values are equal (to ten digits of precision). Index: doctest.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/doctest.py,v retrieving revision 1.114 retrieving revision 1.115 diff -u -d -r1.114 -r1.115 --- doctest.py 27 Sep 2004 03:42:58 -0000 1.114 +++ doctest.py 28 Sep 2004 04:29:57 -0000 1.115 @@ -55,6 +55,7 @@ 'NORMALIZE_WHITESPACE', 'ELLIPSIS', 'IGNORE_EXCEPTION_DETAIL', + 'NORMALIZE_NUMBERS', 'COMPARISON_FLAGS', 'REPORT_UDIFF', 'REPORT_CDIFF', @@ -139,12 +140,14 @@ NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE') ELLIPSIS = register_optionflag('ELLIPSIS') IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL') +NORMALIZE_NUMBERS = register_optionflag('NORMALIZE_NUMBERS') COMPARISON_FLAGS = (DONT_ACCEPT_TRUE_FOR_1 | DONT_ACCEPT_BLANKLINE | NORMALIZE_WHITESPACE | ELLIPSIS | - IGNORE_EXCEPTION_DETAIL) + IGNORE_EXCEPTION_DETAIL | + NORMALIZE_NUMBERS) REPORT_UDIFF = register_optionflag('REPORT_UDIFF') REPORT_CDIFF = register_optionflag('REPORT_CDIFF') @@ -277,6 +280,72 @@ if hasattr(self, "softspace"): del self.softspace +# The number of digits of precision that must be equal for +# NORMALIZE_NUMBERS to consider two numbers equal. +_NORMALIZE_NUMBERS_PRECISION_THRESHOLD = 10 + +# A regular expression that matches Python number literals. This is +# used by _normalize_numbers to look for numbers that should be +# normalized. +_NUMBER_LITERAL = re.compile(r''' + (\d+[.]\d*(?:[eE][-+]?\d+)?[jJ]? | # float (w/ digits left of ".") + [.]\d+(?:[eE][-+]?\d+)?[jJ]? | # float (no digits left of ".") + \d+ (?:[eE][-+]?\d+) [jJ]? | # float (no ".", exponent only) + \d [jJ] | # float (no ".", imaginary only) + 0[xX]\d+[lL]? | # hexint + 0[0-7]*[lL]? | # octint or zero + \d+[lL]? ) # decint + ''', re.VERBOSE) + +def _normalize_numbers(want, got): + """ + If all the numbers in `want` and `got` match (one-for-one), then + return a new version of `got` with the exact number strings from + `want` spliced in. Two numbers match if `str` of their float + values are equal. (I.e., `x` matches `y` if + `str(float(x))==str(float(y))`). + """ + want_pieces = _NUMBER_LITERAL.split(want) + got_pieces = _NUMBER_LITERAL.split(got) + + # If they don't have the same number of numbers, fail immediately. + if len(want_pieces) != len(got_pieces): + return got + + # If any individual numbers don't match, then fail. + for i in range(1, len(got_pieces), 2): + w, g = eval(want_pieces[i]), eval(got_pieces[i]) + if not _numbers_match(w, g): + return got + + # Success; replace numbers in got w/ numbers from want. + for i in range(1, len(got_pieces), 2): + got_pieces[i] = want_pieces[i] + return ''.join(got_pieces) + +def _numbers_match(x, y): + """ + A helper function for _normalize_numbers, that returns true if the + numbers `x` and `y` are close enough to match for NORMALIZE_NUMBERS. + """ + # Equal numbers match. + if x == y: + return True + # Split up complex numbers into real & imag. + if isinstance(x, complex): + return (isinstance(y, complex) and + _numbers_match(x.real, y.real) and + _numbers_match(x.imag, y.imag)) + # If the signs are different, they don't match. + if x*y < 0: + return False + # If one is zero and the other isn't, they don't match. + if x==0 or y==0: + return False + # They're not exactly equal, but are they close enough? + threshold = 10**-_NORMALIZE_NUMBERS_PRECISION_THRESHOLD + return (abs(x-y) / min(abs(x), abs(y))) < threshold + # Worst-case linear-time ellipsis matching. def _ellipsis_match(want, got): """ @@ -1503,6 +1572,13 @@ if got == want: return True + # This flag causes doctest to treat numbers that are within a + # small threshold as if they are equal. + if optionflags & NORMALIZE_NUMBERS: + got = _normalize_numbers(want, got) + if got == want: + return True + # The ELLIPSIS flag says to let the sequence "..." in `want` # match any substring in `got`. if optionflags & ELLIPSIS: @@ -1783,6 +1859,7 @@ NORMALIZE_WHITESPACE ELLIPSIS IGNORE_EXCEPTION_DETAIL + NORMALIZE_NUMBERS REPORT_UDIFF REPORT_CDIFF REPORT_NDIFF @@ -1905,6 +1982,7 @@ NORMALIZE_WHITESPACE ELLIPSIS IGNORE_EXCEPTION_DETAIL + NORMALIZE_NUMBERS REPORT_UDIFF REPORT_CDIFF REPORT_NDIFF
participants (1)
-
edloper@users.sourceforge.net