python-attrs/attrs

`attr.Attributes` incompatible with `Literal`

Why-not-now opened this issue · 3 comments

Because attr.Attributes causes the type it contains to be invariant, Literal types like Literal[1] to be incompatible with attr.Attributes[int]

from __future__ import annotations

from attr import Attribute
from attrs import define, field


def _check(self, attribute: Attribute[int], value: int):
    print(type(attribute))
    if value > 42:
        msg = "x must be smaller or equal to 42"
        raise ValueError(msg)


def trick_type_hinter() -> int:
    return 1

a = trick_type_hinter()

@define
class LiteralDefault:
    x: int = field(default=1, validator=_check)

@define
class LiteralFactory:
    x: int = field(factory=lambda: 1, validator=_check)

@define
class CustomDefault:
    x: int = field(default=a, validator=_check)

@define
class CustomFactory:
    x: int = field(factory=lambda: a, validator=_check)

LiteralDefault error:

  Type "(self: Unknown, attribute: Attribute[int], value: int) -> None" cannot be assigned to type "_ValidatorArgType[_T@field] | None"
    Type "(self: Unknown, attribute: Attribute[int], value: int) -> None" cannot be assigned to type "(Any, Attribute[_T@field], _T@field) -> Any"
      Parameter 2: type "Attribute[_T@field]" cannot be assigned to type "Attribute[int]"
        "Attribute[Literal[1]]" is incompatible with "Attribute[int]"
          Type parameter "_T@Attribute" is invariant, but "Literal[1]" is not the same as "int"
    "function" is incompatible with "Sequence[(Any, Attribute[_T@field], _T@field) -> Any]"
    Type cannot be assigned to type "None"

LiteralFactory error:

  Type "(self: Unknown, attribute: Attribute[int], value: int) -> None" cannot be assigned to type "_ValidatorArgType[_T@field] | None"
    Type "(self: Unknown, attribute: Attribute[int], value: int) -> None" cannot be assigned to type "(Any, Attribute[_T@field], _T@field) -> Any"
      Parameter 2: type "Attribute[_T@field]" cannot be assigned to type "Attribute[int]"
        "Attribute[Literal[1]]" is incompatible with "Attribute[int]"
          Type parameter "_T@Attribute" is invariant, but "Literal[1]" is not the same as "int"
    "function" is incompatible with "Sequence[(Any, Attribute[_T@field], _T@field) -> Any]"
    Type cannot be assigned to type "None"

While casting 1 to int using Typing.cast(int, 1) fixes it, I think this is not the behaviour I expected.

Tinche commented

Hm yeah, something here should be covariant I guess?

I think default and default factory should be covariant. (I may be wrong, covariance/contravariance breaks my head)