Using the attrs library, I can define a validator for attribute values:
from attrs import define, field
def is_odd(inst, attr, value):
if value % 2 == 1:
return None
raise ValueError("Only odd values allowed")
@define
class Foo:
bar = field(validator=is_odd)
Foo(1)
Foo(2)
The Foo(1) instantiation succeeds and the Foo(2) instantiation fails with a ValueError, as intended.
Unsurprisingly, this code does not type-check (according to mypy --strict):
foo.py:3:1: error: Function is missing a type annotation [no-untyped-def]
def is_odd(inst, attr, value):
^
foo.py:11:3: error: Need type annotation for "bar" [var-annotated]
bar = field(validator=is_odd)
^
Found 2 errors in 1 file (checked 1 source file)
However, I don't see how to annotate it so that it does. A naive first attempt might look like:
from attrs import Attribute, define, field
def is_odd(inst: object, attr: Attribute, value: int) -> None:
if value % 2 == 1:
return None
raise ValueError("Only odd values allowed")
@define
class Foo:
bar: int = field(validator=is_odd)
Foo(1)
Foo(2)
However mypy --strict reports this error:
foo.py:3:32: error: Missing type parameters for generic type "Attribute" [type-arg]
This can be fixed by supplying the missing type parameter:
from attrs import Attribute, define, field
def is_odd(inst: object, attr: Attribute[int], value: int) -> None:
if value % 2 == 1:
return None
raise ValueError("Only odd values allowed")
@define
class Foo:
bar: int = field(validator=is_odd)
Foo(1)
Foo(2)
This satisfies mypy:
Success: no issues found in 1 source file
However, the program is now broken at runtime:
Traceback (most recent call last):
File "foo.py", line 3, in <module>
def is_odd(inst: object, attr: Attribute[int], value: int) -> None:
TypeError: 'type' object is not subscriptable
How can the program be made correct at runtime and also type-check under mypy --strict (without just adding "ignore" comments to silence the error)?