Skip to content

Mypy errors out with attrs, generics and inheritance #15658

Closed

Description

@LeBoucEtMistere

Bug Report

When checking python code that uses attrs dataclasses, Generic classes and inheritance, mypy fails to infer the actual type of a TypeVar.

Swapping attrs for std dataclasses removes the error.

Simplifying inheritance chain also removes the error.

I suspect this might be an issue in the mypy-attr plugin.

To Reproduce
can't put a playground link since it doesn't support attrs sorry.

import abc
from typing import Generic, TypeVar

from attr import frozen


# define a hierarchy of State types
class BaseState(metaclass=abc.ABCMeta):
    ...


T_State = TypeVar("T_State", bound=BaseState, covariant=True)


@frozen()
class JumpState(BaseState):
    start: int


# define a hierarchy of signals


@frozen()
class AbstractBaseSignal(metaclass=abc.ABCMeta):
    pass


T_Signal = TypeVar("T_Signal", bound=AbstractBaseSignal)


@frozen()
class SignalA(Generic[T_State], AbstractBaseSignal, metaclass=abc.ABCMeta):
    state: T_State


@frozen()
class SignalAA(SignalA[T_State], metaclass=abc.ABCMeta):
    pass


# this signal specializes the generic type to a well defined JumpState type
class SignalAAA(SignalAA[JumpState]):
    pass


def foo(s: SignalAAA) -> None:
    reveal_type(s)  # SignalAAA
    reveal_type(s.state)  # T_State instead of JumpState
    reveal_type(s.state.start)  # start is not found on T_State

if you swap all the frozen decorators for dataclass it suddendly works, s.state is correctly inferred as a JumpState.

if you remove the class SignalAA and have SignalAAA inherit directly from SignalA (i.e. short-circuit the inheritance chain) it works correctly as well.

Expected Behavior

I would expect this code to typecheck, especially since it does with standard dataclasses. I suspect a problem with the mypy-attrs plugin.

Actual Behavior

mypy output on this example:

type_test.py:47: note: Revealed type is "type_test.SignalAAA"
type_test.py:49: note: Revealed type is "T_State`1"
type_test.py:50: error: "T_State" has no attribute "start"  [attr-defined]
type_test.py:50: note: Revealed type is "Any"
Found 1 error in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: issue confirmed at least starting from 0.991 to latest version. It was working fine with version 0.910.
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files):
[mypy]
python_version = 3.9
warn_unused_configs = True
warn_unused_ignores = True
warn_return_any = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
follow_imports = silent
ignore_missing_imports = True
  • Python version used: 3.9
  • attrs package version: 23.1.0 (bug reproduced in 22.1.0 as well)

The bug was observed first while updating our mypy version from 0.910 to 0.991.

Activity

  1. ikonst commented on Jul 18, 2023

    @ikonst
    Contributor

    Thanks for the version range. git bisect points to 20b0b9b (merged in #12590) as to where it starts (@JukkaL for insights).

  2. ikonst commented on Jul 18, 2023

    @ikonst
    Contributor

    FWIW, replacing attr.frozen with attrs.mutable or attrs.define also "fixes" it 😕

  3. added a commit that references this issue on Aug 12, 2023
    0e4521a
  4. LeBoucEtMistere commented on Aug 12, 2023

    @LeBoucEtMistere
    Author

    Thanks for the quick fix, much appreciated ! Do you know when will the next mypy release come out so that I can upgrade on my end and fix my code ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions