pytest-dev/pytest · error · TypeError

pytest.approx() does not support nested dictionaries: key={!

Error message

pytest.approx() does not support nested dictionaries: key={!r} value={!r}
  full mapping={}

What it means

pytest.approx() does not support nested dictionaries. When ApproxMapping.__init__ iterates the expected mapping, if any value is itself an instance of the same mapping type (e.g., a dict value that is also a dict), pytest raises TypeError. This is a design limitation because approx() only compares flat numeric values.

Source

Thrown at src/_pytest/approx.py:265


class ApproxMapping(Approx[Mapping[Any, Any]]):
    """Perform approximate comparisons where the expected value is a mapping
    with numeric values (the keys can be anything)."""

    def __init__(
        self,
        expected: Mapping[Any, Any],
        rel: float | Decimal | timedelta | None,
        abs: float | Decimal | timedelta | None,
        nan_ok: bool,
    ) -> None:
        __tracebackhide__ = True

        for key, value in expected.items():
            if isinstance(value, type(expected)):
                msg = "pytest.approx() does not support nested dictionaries: key={!r} value={!r}\n  full mapping={}"
                raise TypeError(msg.format(key, value, pprint.pformat(expected)))

        super().__init__(expected, rel=rel, abs=abs, nan_ok=nan_ok)

    def __repr__(self) -> str:
        return f"approx({ ({k: self._approx_scalar(v) for k, v in self.expected.items()})!r})"

    def _repr_compare(self, other_side: Mapping[object, float]) -> list[str]:
        import math

        if len(self.expected) != len(other_side):
            return [
                "Impossible to compare mappings with different sizes.",
                f"Lengths: {len(self.expected)} and {len(other_side)}",
            ]

        if self.expected.keys() != other_side.keys():
            return [
                "comparison failed.",

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Flatten the dictionary before comparison, or compare sub-dicts separately.
  2. Use a manual recursive comparison helper for nested structures.
  3. Extract and compare only the numeric leaf values with individual approx() calls.

Example fix

# before
assert result == approx({'a': 1.0, 'b': {'c': 2.0}})

# after
assert result['a'] == approx(1.0)
assert result['b']['c'] == approx(2.0)
Defensive patterns

Strategy: type-guard

Validate before calling

from collections.abc import Mapping

def is_flat_numeric_mapping(d: Mapping) -> bool:
    """Check that a mapping has no nested mappings (suitable for approx())."""
    return all(not isinstance(v, Mapping) for v in d.values())

# usage:
# assert is_flat_numeric_mapping(expected), 'approx() requires a flat dict; flatten nested dicts first'

Type guard

from collections.abc import Mapping

def is_approx_compatible_mapping(value) -> bool:
    return isinstance(value, Mapping) and all(
        not isinstance(v, Mapping) for v in value.values()
    )

Prevention

When it happens

Trigger: Calling approx({'a': 1.0, 'b': {'c': 2.0}}). The value for key 'b' is a dict, isinstance(value, type(expected)) is True, so TypeError is raised.

Common situations: Comparing nested API responses, config dicts, or JSON-like structures that contain sub-dictionaries with floats.

Related errors


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