I want to use pytest.approx(...)
inside immutable dataclasses (frozen=True
) in my unittest, so I can use a single assert
to check possibly quite complex structures.
This works fine when I use these structures inside test functions, but when I declare a global variable/constant which uses approx
, I get an error in mypy.
Example code:
from pytest import approx
from typing import Final
from dataclasses import dataclass
@dataclass(frozen=True)
class A:
x: float
EXPECTED_VALUE_1: Final = A(approx(0.5)) # <- this is the problem
def test_1():
assert A(0.5) == EXPECTED_VALUE_1
def test_2():
expected_value_2 = A(approx(0.5)) # <- this is fine
assert A(0.5) == expected_value_2
The error:
$ mypy .
a.py:10: error: Argument 1 to "A" has incompatible type "ApproxBase"; expected "float" [arg-type]
Found 1 error in 1 file (checked 1 source file)
I think I know why - mypy by default ignores untyped functions (and my unittest functions are all untyped), but outside those functions it checks.
I've found 2 solutions:
# type: ignore
where this happens - which is in my opinion ugly and makes the code less readablepytest.fixture
in place of a global constant. But in many cases, I have a lot of these EXPECTED_...
constants (which are using approx
) and converting them to fixtures makes code a lot longer and less readable, so, for simple, immutable data, I would like to keep using these global constants.Can I somehow configure mypy to just ignore every call to approx
and check everything else?
Configuration:
Python 3.10.16
mypy 1.16.0
mypy configuration:
[mypy]
python_version = 3.10
ignore_missing_imports = True
Suggested solutions/duplicate questions:
# type: ignore
, which is something I wrote in "What I tried" section I know about and that it's not a solution I want. I want a solution where I would, if possible, change mypy config or somehow "patch" approx
so mypy would ignore just the approx
calls but otherwise check typing errors.You can go with duck-like-typing and define statically different version of approx
:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
def approx[T](expected: T, rel=None, abs=None, nan_ok=False) -> T: ...
else:
from pytest import approx
With this approx(0.5)
will viewed as a float
by your type-checker, at runtime the normal ApproxBase
is used.