pytest-dev/pytest · error · TypeError

pytest.approx() only supports ordered sequences, but got: {e

Error message

pytest.approx() only supports ordered sequences, but got: {expected!r}

What it means

The approx() dispatcher accepts Decimal, Mapping, numpy array, sequence-like objects, datetime/timedelta, and scalars — but a Collection that is NOT ordered (no __getitem__) is unsupported. The classic case is a set. pytest refuses because element order is required to pair up actual vs expected values.

Source

Thrown at src/_pytest/approx.py:967

    # The actual logic for making approximate comparisons can be found in
    # ApproxScalar, which is used to compare individual numbers.  All of the
    # other Approx classes eventually delegate to this class.  The ApproxBase
    # class provides some convenient methods and overloads, but isn't really
    # essential.

    __tracebackhide__ = True

    if isinstance(expected, Decimal):
        return ApproxDecimal(expected, rel=rel, abs=abs, nan_ok=nan_ok)  # type: ignore[return-value]
    elif isinstance(expected, Mapping):
        return ApproxMapping(expected, rel=rel, abs=abs, nan_ok=nan_ok)  # type: ignore[return-value]
    elif (np_array := _as_numpy_array(expected)) is not None:
        return ApproxNumpy(np_array, rel=rel, abs=abs, nan_ok=nan_ok)
    elif _is_sequence_like(expected):
        return ApproxSequenceLike(expected, rel=rel, abs=abs, nan_ok=nan_ok)  # type: ignore[return-value]
    elif isinstance(expected, Collection) and not isinstance(expected, str | bytes):
        msg = f"pytest.approx() only supports ordered sequences, but got: {expected!r}"
        raise TypeError(msg)
    elif isinstance(expected, (datetime, timedelta)):
        return ApproxTimedelta(expected, rel=rel, abs=abs, nan_ok=nan_ok)  # type: ignore[return-value]
    else:
        return ApproxScalar(expected, rel=rel, abs=abs, nan_ok=nan_ok)


def _is_sequence_like(expected: object) -> TypeGuard[Sequence[Any]]:
    return (
        hasattr(expected, "__getitem__")
        and isinstance(expected, Sized)
        and not isinstance(expected, str | bytes)
    )


def _as_numpy_array(obj: object) -> ndarray | None:
    """
    Return an ndarray if the given object is implicitly convertible to ndarray,
    and numpy is already imported, otherwise None.

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Convert to an ordered structure: approx([1, 2, 3]) (list) or approx((1,2,3)) (tuple).
  2. If you want set-like membership, write the assertion explicitly: assert set(actual) == set(expected).
  3. For custom containers, implement __getitem__ and Sized or pass an iterable wrapped in list().

Example fix

// before
assert actual == approx({1, 2, 3})
// after
assert actual == approx([1, 2, 3])
Defensive patterns

Strategy: type-guard

Validate before calling

from collections.abc import Collection, Sequence

def approx_seq(expected):
    if isinstance(expected, Collection) and not isinstance(expected, str | bytes | Sequence):
        # unordered collection (e.g. set) — sort or convert before approx
        expected = sorted(expected)
    return pytest.approx(expected)

Type guard

from collections.abc import Sequence

def is_ordered_sequence(v) -> bool:
    return isinstance(v, Sequence) and not isinstance(v, (str, bytes))

Prevention

When it happens

Trigger: Call pytest.approx({1, 2, 3}) (a set) or any Collection lacking __getitem__. The dispatcher hits the `isinstance(expected, Collection) and not str/bytes` branch after sequence-like and Mapping checks fail.

Common situations: Passing a set to approx() expecting unordered membership comparison; passing a frozenset; passing a custom Collection that does not implement sequence protocol.

Related errors


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/50f8fc0d14e4a927.json. Report an issue: GitHub.