pytest-dev/pytest · error · TypeError

pytest.approx() requires an explicit tolerance for…

Error message

pytest.approx() requires an explicit tolerance for datetime/timedelta comparisons: e.g. approx(expected, abs=timedelta(seconds=1)) or approx(expected, rel=0.01)

What it means

ApproxTimedelta.__init__ requires at least one explicit tolerance (abs or rel) for datetime/timedelta comparisons, unlike scalars which default to rel=1e-6/abs=1e-12. datetime/timedelta have no sensible default tolerance window (1e-6 of what unit?), so pytest refuses to guess. The error suggests both valid forms. The check fires when both abs and rel are None.

Solutions

  1. For datetime, pass an absolute timedelta: `approx(dt, abs=timedelta(seconds=1))`.
  2. For timedelta, pass rel (a number, fraction of the duration) or abs: `approx(td, rel=0.01)` or `approx(td, abs=timedelta(milliseconds=10))`.
  3. Centralize the chosen tolerance in a fixture/constant to keep datetime assertions consistent.

Example fix

# before
assert actual_dt == approx(expected_dt)
# after
assert actual_dt == approx(expected_dt, abs=timedelta(seconds=1))
Defensive patterns

Strategy: validation

Validate before calling

from datetime import datetime, timedelta
def ensure_datetime_tolerance(expected, rel, abs):
    if isinstance(expected, (datetime, timedelta)) and rel is None and abs is None:
        if isinstance(expected, datetime):
            return {'abs': timedelta(seconds=1)}
        return {'rel': 0.01}
    return {'rel': rel, 'abs': abs}
# usage
assert actual == approx(expected, **ensure_datetime_tolerance(expected, rel, abs))

Type guard

from datetime import datetime, timedelta
def needs_explicit_tolerance(expected) -> bool:
    return isinstance(expected, (datetime, timedelta))

Prevention

When it happens

Trigger: Calling approx(datetime.now()); approx(timedelta(seconds=5)); approx(dt) with no keyword args. Triggered at ApproxTimedelta.__init__ (src/_pytest/approx.py:656-662).

Common situations: Migrating a numeric approx() call to datetime without adding tolerance; assuming a default tolerance exists; refactoring a test to use datetime while keeping the old bare approx() call.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/5e7b055f34604a5d. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/approx.py:657

        self,
        expected: datetime | timedelta,
        rel: float | Decimal | timedelta | None,
        abs: float | Decimal | timedelta | None,
        nan_ok: bool,
    ) -> None:
        __tracebackhide__ = True
        if isinstance(expected, datetime) and rel is not None:
            raise TypeError(
                "pytest.approx() does not support relative tolerance for "
                "datetime comparisons. Use abs=timedelta(...) instead."
            )
        if nan_ok:
            raise TypeError(
                "pytest.approx() does not support nan_ok for "
                "datetime/timedelta comparisons."
            )
        if abs is None and rel is None:
            raise TypeError(
                "pytest.approx() requires an explicit tolerance for "
                "datetime/timedelta comparisons: "
                "e.g. approx(expected, abs=timedelta(seconds=1)) "
                "or approx(expected, rel=0.01)"
            )
        if abs is not None and not isinstance(abs, timedelta):
            raise TypeError(
                f"absolute tolerance for datetime/timedelta must be a "
                f"timedelta, got {type(abs).__name__}"
            )
        if abs is not None and abs < timedelta(0):
            raise ValueError(f"absolute tolerance can't be negative: {abs}")
        if rel is not None:
            if not isinstance(rel, (int, float)):
                raise TypeError(
                    f"relative tolerance for timedelta must be a "
                    f"number, got {type(rel).__name__}"
                )

View on GitHub (pinned to 0d6fbdeffa)