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
|
||||
Ned Batchelder
|
||||
Neven Mundar
|
||||
Nicholas Devenish
|
||||
Niclas Olofsson
|
||||
Nicolas Delaby
|
||||
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:
|
||||
from collections.abc import MutableMapping as MappingMixin
|
||||
from collections.abc import Mapping, Sequence
|
||||
from collections.abc import Iterable, Mapping, Sequence, Sized
|
||||
else:
|
||||
# those raise DeprecationWarnings in Python >=3.7
|
||||
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):
|
||||
|
|
|
@ -15,8 +15,9 @@ from six.moves import zip
|
|||
import _pytest._code
|
||||
from _pytest import deprecated
|
||||
from _pytest.compat import isclass
|
||||
from _pytest.compat import Iterable
|
||||
from _pytest.compat import Mapping
|
||||
from _pytest.compat import Sequence
|
||||
from _pytest.compat import Sized
|
||||
from _pytest.compat import STRING_TYPES
|
||||
from _pytest.outcomes import fail
|
||||
|
||||
|
@ -186,7 +187,7 @@ class ApproxMapping(ApproxBase):
|
|||
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
|
||||
numbers.
|
||||
|
@ -522,10 +523,14 @@ def approx(expected, rel=None, abs=None, nan_ok=False):
|
|||
cls = ApproxScalar
|
||||
elif isinstance(expected, Mapping):
|
||||
cls = ApproxMapping
|
||||
elif isinstance(expected, Sequence) and not isinstance(expected, STRING_TYPES):
|
||||
cls = ApproxSequence
|
||||
elif _is_numpy_array(expected):
|
||||
cls = ApproxNumpy
|
||||
elif (
|
||||
isinstance(expected, Iterable)
|
||||
and isinstance(expected, Sized)
|
||||
and not isinstance(expected, STRING_TYPES)
|
||||
):
|
||||
cls = ApproxSequencelike
|
||||
else:
|
||||
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 approx(expected, rel=5e-7, 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