Skip to content

Types of inheritanced class attributes aren't detected #10375

Closed

Description

@abhiabhi94

Bug Report

mypy doesn't detect type of inherited class variables.

To Reproduce

from typing import List

class A:
    a: List[int]

class B(A):
    a = []  # error: Need type annotation for 'a' (hint: "a: List[<type>] = ...")

Expected Behavior

The type of B.a should ideally be inferred from the parent class A.

Actual Behavior

I get an error on the line where I initialize the attribute inside the class B with the message error: Need type annotation for 'a' (hint: "a: List[<type>] = ...").

This works if I define the attribute as an instance attribute inside the __init__ method.

from typing import List

class A:
    def __init__(self) -> None:
        self.a: List[int]

class B(A):
    def __init__(self) -> None:
        super().__init__()
        self.a = []

Your Environment

  • Mypy version used: 0.812
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.8.5
  • Operating system and version: Ubuntu 20.04.2 LTS

For what it's worth, I also tried using the mypy playground and the same issue can be reproduced there as well with python 3.9 and mypy latest. You can take a look at https://mypy-play.net/?mypy=latest&python=3.9&gist=ed3482447c995e3b1acd57706c066633

I will be happy to help if there are any clarifications required or anything else that can help resolve the issue.

Activity

  1. Timmmm commented on Dec 16, 2021

    @Timmmm

    I looked into the code and it seems like it just isn't implemented. I had a quick go, in checker.py change the code to the following:

        def check_lvalue(self, lvalue: Lvalue) -> Tuple[Optional[Type],
                                                        Optional[IndexExpr],
                                                        Optional[Var]]:
            lvalue_type = None
            index_lvalue = None
            inferred = None
    
            if self.is_definition(lvalue) and (
                not isinstance(lvalue, NameExpr) or isinstance(lvalue.node, Var)
            ):
                if isinstance(lvalue, NameExpr):
                    # If this is a class variable without a type annotation and
                    # there's a base class with the same name then set the type to
                    # that variable's type.
                    if lvalue.node.type is None:
                        for base in lvalue.node.info.mro[1:]:
                            tnode = base.names.get(lvalue.node.name)
                            if tnode is not None and tnode.type is not None:
                                lvalue_type = tnode.type
                                lvalue.node.type = lvalue_type
                                self.store_type(lvalue, lvalue_type)
                                break
    
                    if lvalue.node.type is None:
                        inferred = cast(Var, lvalue.node)
                        assert isinstance(inferred, Var)
                else:
    ...

    Not sure about the store_type(). Needs one of the developers to say if this is a vaguely correct fix.

    Test case:

    class Base:
      X: list[int] = []
    
    class Derived0(Base):
      X = []
    
    class Derived1(Base):
      X: list[str] = []
    
    class Derived2(Base):
      X = ["a"]

    Before:

    example.py:5: error: Need type annotation for "X" (hint: "X: List[<type>] = ...")
    example.py:8: error: Incompatible types in assignment (expression has type "List[str]", base class "Base" defined the type as "List[int]")
    example.py:11: error: List item 0 has incompatible type "str"; expected "int"
    Found 3 errors in 1 file (checked 1 source file)
    

    After:

    example.py:8: error: Incompatible types in assignment (expression has type "List[str]", base class "Base" defined the type as "List[int]")
    example.py:11: error: List item 0 has incompatible type "str"; expected "int"
    Found 2 errors in 1 file (checked 1 source file)
    
  2. Timmmm commented on Jan 19, 2022

    @Timmmm

    Ok I added my attempt in #12022 but it really needs feedback from an actual MyPy developer. I'd appreciate any help.

  3. erictraut commented on Aug 12, 2023

    @erictraut

    This bug appears to have been fixed. I can no longer repro it with the latest version of mypy (1.5).

  4. hauntsaninja commented on Aug 12, 2023

    @hauntsaninja
    Collaborator

    Fixed in #13494

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

    bugmypy got something wrongtopic-inferenceWhen to infer types or require explicit annotationstopic-inheritanceInheritance and incompatible overrides

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions