Improve error checking messages: add position and use pprint
This commit is contained in:
parent
098dca3a9f
commit
611d254ed5
|
@ -1,4 +1,5 @@
|
||||||
import math
|
import math
|
||||||
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
from numbers import Number
|
from numbers import Number
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
@ -32,10 +33,11 @@ def _cmp_raises_type_error(self, other):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _non_numeric_type_error(value):
|
def _non_numeric_type_error(value, at):
|
||||||
|
at_str = "at {}".format(at) if at else ""
|
||||||
return TypeError(
|
return TypeError(
|
||||||
"cannot make approximate comparisons to non-numeric values, e.g. {!r}".format(
|
"cannot make approximate comparisons to non-numeric values: {!r} ".format(
|
||||||
value
|
value, at_str
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,6 +56,7 @@ class ApproxBase(object):
|
||||||
__array_priority__ = 100
|
__array_priority__ = 100
|
||||||
|
|
||||||
def __init__(self, expected, rel=None, abs=None, nan_ok=False):
|
def __init__(self, expected, rel=None, abs=None, nan_ok=False):
|
||||||
|
__tracebackhide__ = True
|
||||||
self.expected = expected
|
self.expected = expected
|
||||||
self.abs = abs
|
self.abs = abs
|
||||||
self.rel = rel
|
self.rel = rel
|
||||||
|
@ -170,15 +173,13 @@ class ApproxMapping(ApproxBase):
|
||||||
yield actual[k], self.expected[k]
|
yield actual[k], self.expected[k]
|
||||||
|
|
||||||
def _check_type(self):
|
def _check_type(self):
|
||||||
for x in self.expected.values():
|
__tracebackhide__ = True
|
||||||
if isinstance(x, type(self.expected)):
|
for key, value in self.expected.items():
|
||||||
raise TypeError(
|
if isinstance(value, type(self.expected)):
|
||||||
"pytest.approx() does not support nested dictionaries, e.g. {!r}".format(
|
msg = "pytest.approx() does not support nested dictionaries: key={!r} value={!r}\n full mapping={}"
|
||||||
self.expected
|
raise TypeError(msg.format(key, value, pprint.pformat(self.expected)))
|
||||||
)
|
elif not isinstance(value, Number):
|
||||||
)
|
raise _non_numeric_type_error(self.expected, at="key={!r}".format(key))
|
||||||
elif not isinstance(x, Number):
|
|
||||||
raise _non_numeric_type_error(self.expected)
|
|
||||||
|
|
||||||
|
|
||||||
class ApproxSequence(ApproxBase):
|
class ApproxSequence(ApproxBase):
|
||||||
|
@ -204,15 +205,15 @@ class ApproxSequence(ApproxBase):
|
||||||
return zip(actual, self.expected)
|
return zip(actual, self.expected)
|
||||||
|
|
||||||
def _check_type(self):
|
def _check_type(self):
|
||||||
for x in self.expected:
|
__tracebackhide__ = True
|
||||||
|
for index, x in enumerate(self.expected):
|
||||||
if isinstance(x, type(self.expected)):
|
if isinstance(x, type(self.expected)):
|
||||||
raise TypeError(
|
msg = "pytest.approx() does not support nested data structures: {!r} at index {}\n full sequence: {}"
|
||||||
"pytest.approx() does not support nested data structures, e.g. {!r}".format(
|
raise TypeError(msg.format(x, index, pprint.pformat(self.expected)))
|
||||||
self.expected
|
|
||||||
)
|
|
||||||
)
|
|
||||||
elif not isinstance(x, Number):
|
elif not isinstance(x, Number):
|
||||||
raise _non_numeric_type_error(self.expected)
|
raise _non_numeric_type_error(
|
||||||
|
self.expected, at="index {}".format(index)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ApproxScalar(ApproxBase):
|
class ApproxScalar(ApproxBase):
|
||||||
|
@ -520,7 +521,7 @@ def approx(expected, rel=None, abs=None, nan_ok=False):
|
||||||
elif _is_numpy_array(expected):
|
elif _is_numpy_array(expected):
|
||||||
cls = ApproxNumpy
|
cls = ApproxNumpy
|
||||||
else:
|
else:
|
||||||
raise _non_numeric_type_error(expected)
|
raise _non_numeric_type_error(expected, at=None)
|
||||||
|
|
||||||
return cls(expected, rel, abs, nan_ok)
|
return cls(expected, rel, abs, nan_ok)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue