diff -r 00c95b0e82e4 Doc/library/unittest.rst
--- a/Doc/library/unittest.rst Thu Jun 02 11:36:16 2016 -0700
+++ b/Doc/library/unittest.rst Fri Jun 03 12:54:55 2016 -0700
@@ -1091,6 +1091,12 @@
| :meth:`assertNotAlmostEqual(a, b) | ``round(a-b, 7) != 0`` | |
| ` | | |
+---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertClose(a, b) | ``math.isclose(a, b)`` | 3.6 |
+ | ` | | |
+ +---------------------------------------+--------------------------------+--------------+
+ | :meth:`assertNotClose(a, b) | ``not math.isclose(a, b)`` | 3.6 |
+ | ` | | |
+ +---------------------------------------+--------------------------------+--------------+
| :meth:`assertGreater(a, b) | ``a > b`` | 3.1 |
| ` | | |
+---------------------------------------+--------------------------------+--------------+
@@ -1122,7 +1128,8 @@
equal by computing the difference, rounding to the given number of
decimal *places* (default 7), and comparing to zero. Note that these
methods round the values to the given number of *decimal places* (i.e.
- like the :func:`round` function) and not *significant digits*.
+ like the :func:`round` function) and not *significant digits*. If you
+ need something like significant digits, consider :meth:`assertClose`
If *delta* is supplied instead of *places* then the difference
between *first* and *second* must be less or equal to (or greater than) *delta*.
@@ -1134,6 +1141,45 @@
that compare equal. :meth:`assertNotAlmostEqual` automatically fails
if the objects compare equal. Added the *delta* keyword argument.
+ .. method:: assertClose(self, first, second, rel_tol=1e-09, abs_tol=0.0, msg=None)
+ assertNotClose(self, first, second, rel_tol=1e-09, abs_tol=0.0, msg=None)
+
+ Tests if two floating point numbers are close to the same value as
+ determined by their difference relative to their magnitude.
+ This is computed by the :func:`math.isclose()` function.
+
+ rel_tol=1e-09
+ maximum difference for being considered close, relative to the
+ magnitude of the input values
+ abs_tol=0.0
+ maximum difference for being considered close, regardless of the
+ magnitude of the input values. This is required if one of the values
+ is exactly zero, as nothing is "relatively" close to zero.
+
+ For the values to be considered close, the difference between them
+ must be smaller than at least one of the tolerances. The result will
+ be:
+
+ ``abs(first-second) <= max(rel_tol * max(abs(first), abs(second)), abs_tol)``.
+
+ Note that in contrast to :meth:`assertAlmostEqual`, this is similar to
+ significant digits (measured from the most significant digit). For
+ example, setting rel_tol=1e-9 tests equality of approximately nine
+ decimal digits (approximate, because the arithmetic is done in binary,
+ not decimal). :meth:`assertAlmostEqual` should be used when you know the
+ magnitude of your values, and you want them compared to given number
+ of decimal places. ``assertClose()`` can be used for any magnitude of
+ values.
+
+ ``-inf``, ``inf`` and ``NaN`` behave similarly to the IEEE 754 Standard. That
+ is, NaN is not close to anything, even itself. ``inf`` and ``-inf`` are
+ only close to themselves.
+
+ If the two objects compare equal then they will automatically
+ be considered close.
+
+ .. versionadded:: 3.6
+.. :meth:`assertClose` and :meth:`assertNotClose` added to use the `math.isclose()` method.
.. method:: assertGreater(first, second, msg=None)
assertGreaterEqual(first, second, msg=None)
diff -r 00c95b0e82e4 Lib/unittest/case.py
--- a/Lib/unittest/case.py Thu Jun 02 11:36:16 2016 -0700
+++ b/Lib/unittest/case.py Fri Jun 03 12:54:55 2016 -0700
@@ -10,6 +10,7 @@
import collections
import contextlib
import traceback
+import math
from . import result
from .util import (strclass, safe_repr, _count_diff_all_purpose,
@@ -899,6 +900,96 @@
msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg)
+ def assertClose(self, first, second, rel_tol=1e-09, abs_tol=0.0, msg=None):
+ """Fail if the two numbers are not close to the same value as
+ determined by their difference relative to their magnitude.
+ This is computed by the isclose() function in the math module.
+
+ rel_tol=1e-09
+ maximum difference for being considered "close", relative to the
+ magnitude of the input values
+ abs_tol=0.0
+ maximum difference for being considered "close", regardless of the
+ magnitude of the input values. This is required if one of the values
+ is close to zero, as nothing is "relatively" close to zero.
+
+ For the values to be considered close, the difference between them
+ must be smaller than at least one of the tolerances.
+
+ -inf, inf and NaN behave similarly to the IEEE 754 Standard. That
+ is, NaN is not close to anything, even itself. inf and -inf are
+ only close to themselves.
+
+ Note that in contrast to ``assertAlmostEqual``, this is similar to
+ significant digits (measured from the most significant digit). For
+ example, setting rel_tol=1e-9 tests equality of approximately nine
+ decimal digits. (close, because the arithmetic is done in binary,
+ not decimal)
+
+ If the two objects compare equal then they will automatically
+ compare close.
+ """
+ if first == second:
+ # shortcut
+ return
+ if math.isclose(first, second, rel_tol=rel_tol, abs_tol=abs_tol):
+ return
+ else:
+ standardMsg = ('%s != %s with relative tolerance of %.3g'
+ ' and absolute tolerance of %.3g' % (safe_repr(first),
+ safe_repr(second),
+ rel_tol,
+ abs_tol))
+ msg = self._formatMessage(msg, standardMsg)
+ raise self.failureException(msg)
+
+ def assertNotClose(self, first, second, rel_tol=1e-09, abs_tol=0.0, msg=None):
+ """Fail if the two numbers are close to the same value as
+ determined by their difference relative to their magnitude.
+ This is computed by the isclose() function in the math module.
+
+ rel_tol=1e-09
+ maximum difference for being considered "close", relative to the
+ magnitude of the input values
+ abs_tol=0.0
+ maximum difference for being considered "close", regardless of the
+ magnitude of the input values. This is required if one of the values
+ is close to zero, as nothing is "relatively" close to zero.
+
+ For the values to be considered close, the difference between them
+ must be smaller than at least one of the tolerances. The result will
+ be:
+
+ ``abs(first-second) <= max(rel_tol * max(abs(first), abs(second)), abs_tol)``.
+
+ -inf, inf and NaN behave similarly to the IEEE 754 Standard. That
+ is, NaN is not close to anything, even itself. inf and -inf are
+ only close to themselves.
+
+ Note that in contrast to ``assertAlmostEqual``, this is similar to
+ significant digits (measured from the most significant digit). For
+ example, setting rel_tol=1e-9 tests equality of approximately nine
+ decimal digits. (close, because the arithmetic is done in binary,
+ not decimal)
+
+ If the two objects compare equal then they will automatically
+ compare close.
+ """
+ if first == second:
+ # shortcut
+ standardMsg = '%s != %s are exactly equal' % (safe_repr(first),
+ safe_repr(second),
+ )
+ elif not math.isclose(first, second, rel_tol=rel_tol, abs_tol=abs_tol):
+ return
+ else:
+ standardMsg = ('%s == %s with relative tolerance of %.3g'
+ ' and absolute tolerance of %.3g' % (safe_repr(first),
+ safe_repr(second),
+ rel_tol,
+ abs_tol))
+ msg = self._formatMessage(msg, standardMsg)
+ raise self.failureException(msg)
def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
"""An equality assertion for ordered sequences (like lists and tuples).
diff -r 00c95b0e82e4 Lib/unittest/test/test_assertions.py
--- a/Lib/unittest/test/test_assertions.py Thu Jun 02 11:36:16 2016 -0700
+++ b/Lib/unittest/test/test_assertions.py Fri Jun 03 12:54:55 2016 -0700
@@ -56,6 +56,28 @@
self.assertNotAlmostEqual(first, second,
delta=datetime.timedelta(seconds=5))
+ def test_assertClose(self):
+ # Note: math.isclose() has more comprehensive tests
+ # this is just to make sure it's being called correctly
+
+ self.assertClose(1.123e-23, 1.123e-23)
+ self.assertClose(1e40, 1.0000000001e40)
+ self.assertClose(1.0, 1.000001, rel_tol=1e-4)
+ self.assertClose(0.0, 0.000001, abs_tol=1e-5)
+
+ def test_assertNotClose(self):
+ # Note: math.isclose() has more comprehensive tests
+ # this is just to make sure it's being called correctly
+
+ self.assertNotClose(1, 1e20)
+ self.assertNotClose(1, 1.00000000001, rel_tol=1e-11)
+ self.assertNotClose(0.0, 0.000001)
+ self.assertNotClose(0.0, 0.000001, abs_tol=1e-7)
+
+ # make sure short cut is run if exactly equal
+ with self.assertRaises(AssertionError):
+ self.assertNotClose(2.3, 2.3)
+
def test_assertRaises(self):
def _raise(e):
raise e