attrs icon indicating copy to clipboard operation
attrs copied to clipboard

Mypy false positive for union validator

Open AdrianSosic opened this issue 1 year ago • 1 comments

Not sure if this is a duplicate but I couldn't find the problem in the open issues. If I overlooked it, please close, of course.

from attrs import define, field
from attrs.validators import instance_of

LeTypeAlias = int | str


@define
class LeClass:
    x: LeTypeAlias = field(validator=instance_of(LeTypeAlias))

Works perfectly but mypy complains about:

error: No overload variant of "instance_of" matches argument type "UnionType[int, str]"  [call-overload]

AdrianSosic avatar Aug 16 '24 13:08 AdrianSosic

That doesn’t sound familiar and should be easy to fix. 🤞

hynek avatar Aug 17 '24 10:08 hynek

I think, to be completely correct from a static typing perspective, LeTypeAlias should actually be:

type LeTypeAlias = int | str

In that case, Mypy and Pyright think it's a typing.TypeAliasType. Note that type aliases cannot be used with isinstance - it will blow up at runtime. So we should let this be a type error or change _InstanceOfValidator to explicitly work with them.

I don't remember off the top of my head why you're not supposed to just use LeTypeAlias = int | str, and PEP 695 doesn't say much. I think type works better with generics and forward references?

But if you were to just use the union inline:

from attrs import define, field
from attrs.validators import instance_of

@define
class LeClass:
    x: int | str = field(validator=instance_of(int | str))

Then the argument to instance_of would be types.UnionType.

Tinche avatar Dec 14 '24 22:12 Tinche