diff --git a/changelog/11797.bugfix.rst b/changelog/11797.bugfix.rst new file mode 100644 index 00000000000..481d81ddb41 --- /dev/null +++ b/changelog/11797.bugfix.rst @@ -0,0 +1 @@ +Ensure approx for SequenceLike objects doesn't wrap those sequences in a scalar. \ No newline at end of file diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index f914d70e83f..cf0bb40f72a 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -128,6 +128,8 @@ def _recursive_sequence_map(f, x): if isinstance(x, (list, tuple)): seq_type = type(x) return seq_type(_recursive_sequence_map(f, xi) for xi in x) + elif _is_sequence_like(x): + return [_recursive_sequence_map(f, xi) for xi in x] else: return f(x) @@ -721,12 +723,7 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase: elif _is_numpy_array(expected): expected = _as_numpy_array(expected) cls = ApproxNumpy - elif ( - hasattr(expected, "__getitem__") - and isinstance(expected, Sized) - # Type ignored because the error is wrong -- not unreachable. - and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable] - ): + elif _is_sequence_like(expected): cls = ApproxSequenceLike elif ( isinstance(expected, Collection) @@ -741,6 +738,15 @@ def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase: return cls(expected, rel, abs, nan_ok) +def _is_sequence_like(expected: object) -> bool: + return ( + hasattr(expected, "__getitem__") + and isinstance(expected, Sized) + # Type ignored because the error is wrong -- not unreachable. + and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable] + ) + + def _is_numpy_array(obj: object) -> bool: """ Return true if the given object is implicitly convertible to ndarray,