Merge pull request #4327 from ndevenish/approx
Let approx() work on more generic sequences
This commit is contained in:
commit
e63c7a13ff
1
AUTHORS
1
AUTHORS
|
@ -166,6 +166,7 @@ Miro Hrončok
|
||||||
Nathaniel Waisbrot
|
Nathaniel Waisbrot
|
||||||
Ned Batchelder
|
Ned Batchelder
|
||||||
Neven Mundar
|
Neven Mundar
|
||||||
|
Nicholas Devenish
|
||||||
Niclas Olofsson
|
Niclas Olofsson
|
||||||
Nicolas Delaby
|
Nicolas Delaby
|
||||||
Oleg Pidsadnyi
|
Oleg Pidsadnyi
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
``approx`` again works with more generic containers, more precisely instances of ``Iterable`` and ``Sized`` instead of more restrictive ``Sequence``.
|
|
@ -45,11 +45,11 @@ MODULE_NOT_FOUND_ERROR = "ModuleNotFoundError" if PY36 else "ImportError"
|
||||||
|
|
||||||
if _PY3:
|
if _PY3:
|
||||||
from collections.abc import MutableMapping as MappingMixin
|
from collections.abc import MutableMapping as MappingMixin
|
||||||
from collections.abc import Mapping, Sequence
|
from collections.abc import Iterable, Mapping, Sequence, Sized
|
||||||
else:
|
else:
|
||||||
# those raise DeprecationWarnings in Python >=3.7
|
# those raise DeprecationWarnings in Python >=3.7
|
||||||
from collections import MutableMapping as MappingMixin # noqa
|
from collections import MutableMapping as MappingMixin # noqa
|
||||||
from collections import Mapping, Sequence # noqa
|
from collections import Iterable, Mapping, Sequence, Sized # noqa
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 4):
|
if sys.version_info >= (3, 4):
|
||||||
|
|
|
@ -15,8 +15,9 @@ from six.moves import zip
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
from _pytest import deprecated
|
from _pytest import deprecated
|
||||||
from _pytest.compat import isclass
|
from _pytest.compat import isclass
|
||||||
|
from _pytest.compat import Iterable
|
||||||
from _pytest.compat import Mapping
|
from _pytest.compat import Mapping
|
||||||
from _pytest.compat import Sequence
|
from _pytest.compat import Sized
|
||||||
from _pytest.compat import STRING_TYPES
|
from _pytest.compat import STRING_TYPES
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
|
|
||||||
|
@ -186,7 +187,7 @@ class ApproxMapping(ApproxBase):
|
||||||
raise _non_numeric_type_error(self.expected, at="key={!r}".format(key))
|
raise _non_numeric_type_error(self.expected, at="key={!r}".format(key))
|
||||||
|
|
||||||
|
|
||||||
class ApproxSequence(ApproxBase):
|
class ApproxSequencelike(ApproxBase):
|
||||||
"""
|
"""
|
||||||
Perform approximate comparisons where the expected value is a sequence of
|
Perform approximate comparisons where the expected value is a sequence of
|
||||||
numbers.
|
numbers.
|
||||||
|
@ -522,10 +523,14 @@ def approx(expected, rel=None, abs=None, nan_ok=False):
|
||||||
cls = ApproxScalar
|
cls = ApproxScalar
|
||||||
elif isinstance(expected, Mapping):
|
elif isinstance(expected, Mapping):
|
||||||
cls = ApproxMapping
|
cls = ApproxMapping
|
||||||
elif isinstance(expected, Sequence) and not isinstance(expected, STRING_TYPES):
|
|
||||||
cls = ApproxSequence
|
|
||||||
elif _is_numpy_array(expected):
|
elif _is_numpy_array(expected):
|
||||||
cls = ApproxNumpy
|
cls = ApproxNumpy
|
||||||
|
elif (
|
||||||
|
isinstance(expected, Iterable)
|
||||||
|
and isinstance(expected, Sized)
|
||||||
|
and not isinstance(expected, STRING_TYPES)
|
||||||
|
):
|
||||||
|
cls = ApproxSequencelike
|
||||||
else:
|
else:
|
||||||
raise _non_numeric_type_error(expected, at=None)
|
raise _non_numeric_type_error(expected, at=None)
|
||||||
|
|
||||||
|
|
|
@ -496,3 +496,14 @@ class TestApprox(object):
|
||||||
assert actual != approx(expected, rel=5e-8, abs=0)
|
assert actual != approx(expected, rel=5e-8, abs=0)
|
||||||
assert approx(expected, rel=5e-7, abs=0) == actual
|
assert approx(expected, rel=5e-7, abs=0) == actual
|
||||||
assert approx(expected, rel=5e-8, abs=0) != actual
|
assert approx(expected, rel=5e-8, abs=0) != actual
|
||||||
|
|
||||||
|
def test_generic_sized_iterable_object(self):
|
||||||
|
class MySizedIterable(object):
|
||||||
|
def __iter__(self):
|
||||||
|
return iter([1, 2, 3, 4])
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return 4
|
||||||
|
|
||||||
|
expected = MySizedIterable()
|
||||||
|
assert [1, 2, 3, 4] == approx(expected)
|
||||||
|
|
Loading…
Reference in New Issue