{"id":"af23743444ccb4f2","repo":"pytest-dev/pytest","slug":"expected-value-must-support-abs-when-relative","errorCode":null,"errorMessage":"expected value must support abs(...) when relative tolerance is used, got {type(expected).__name__}","messagePattern":"expected value must support abs\\(\\.\\.\\.\\) when relative tolerance is used, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/approx.py","lineNumber":455,"sourceCode":"    rel: float | Decimal | None\n    abs: float | Decimal | None\n\n    def __init__(\n        self,\n        expected: ExpectedT,\n        rel: float | Decimal | timedelta | None,\n        abs: float | Decimal | timedelta | None,\n        nan_ok: bool,\n    ) -> None:\n        __tracebackhide__ = True\n        if rel is not None:\n            if not isinstance(rel, (int, float, Decimal)):\n                raise TypeError(\n                    f\"relative tolerance for a scalar value must be an int, float or Decimal, \"\n                    f\"got {type(rel).__name__}\"\n                )\n            if not isinstance(expected, SupportsAbs):\n                raise TypeError(\n                    f\"expected value must support abs(...) when relative tolerance is used, \"\n                    f\"got {type(expected).__name__}\"\n                )\n        if abs is not None and not isinstance(abs, (int, float, Decimal)):\n            raise TypeError(\n                f\"absolute tolerance for a scalar value must be an int, float or Decimal, \"\n                f\"got {type(abs).__name__}\"\n            )\n        super().__init__(expected, rel=rel, abs=abs, nan_ok=nan_ok)\n\n    def __repr__(self) -> str:\n        \"\"\"Return a string communicating both the expected value and the\n        tolerance for the comparison being made.\n\n        For example, ``1.0 ± 1e-6``, ``(3+4j) ± 5e-6 ∠ ±180°``.\n        \"\"\"\n        # Don't show a tolerance for values that aren't compared using\n        # tolerances, i.e. non-numerics and infinities. Need to call abs to","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/approx.py#L437-L473","documentation":"When a relative tolerance (rel) is specified for ApproxScalar, the expected value must support abs(...) to compute the relative component (rel * abs(expected)). If the expected value does not implement __abs__ (e.g., a string or custom object), pytest raises TypeError. This is validated eagerly in __init__.","triggerScenarios":"Calling approx('hello', rel=0.01) or approx(SomeObj(), rel=0.01) where the expected value lacks __abs__. The isinstance(expected, SupportsAbs) check fails.","commonSituations":"Comparing a non-numeric value with a relative tolerance, or passing a tolerance meant for numbers to a custom object comparison.","solutions":["Use absolute tolerance (abs=) instead of relative tolerance for non-numeric or non-abs-supporting values.","Remove the rel parameter if only exact comparison is needed.","Ensure the expected value is numeric (int, float, Decimal) when using rel."],"exampleFix":"# before\napprox('hello', rel=0.01)\n\n# after\napprox('hello')  # no rel, exact comparison\n# or for numeric values:\napprox(3.14, rel=0.01)","handlingStrategy":"type-guard","validationCode":"from typing import Protocol\nimport numbers\n\nclass SupportsAbs(Protocol):\n    def __abs__(self) -> float: ...\n\ndef validate_expected_with_rel(expected, rel):\n    if rel is not None and not hasattr(expected, '__abs__'):\n        raise TypeError(f'expected value must support abs() when rel is used, got {type(expected).__name__}')\n    return expected\n\n# usage:\n# if rel_tol: validate_expected_with_rel(value, rel_tol)","typeGuard":"def supports_abs(value) -> bool:\n    return hasattr(value, '__abs__') and callable(getattr(value, '__abs__'))","tryCatchPattern":null,"preventionTips":["Only use rel= with numeric expected values (int, float, Decimal, complex).","For non-numeric comparisons, use abs= or omit tolerance entirely.","Check that the expected value is a number before applying relative tolerance."],"tags":["approx","type-error","tolerance","validation"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}