Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types of inheritanced class attributes aren't detected #10375

Closed
abhiabhi94 opened this issue Apr 27, 2021 · 4 comments
Closed

Types of inheritanced class attributes aren't detected #10375

abhiabhi94 opened this issue Apr 27, 2021 · 4 comments
Labels
bug mypy got something wrong topic-inference When to infer types or require explicit annotations topic-inheritance Inheritance and incompatible overrides

Comments

@abhiabhi94
Copy link

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.

@Timmmm
Copy link

Timmmm commented Dec 16, 2021

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)

@Timmmm
Copy link

Timmmm commented Jan 19, 2022

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

@AlexWaygood AlexWaygood added topic-inheritance Inheritance and incompatible overrides topic-inference When to infer types or require explicit annotations labels Mar 31, 2022
wrwrwr added a commit to wrwrwr/mypy that referenced this issue Jan 21, 2023
Related python#10375 and python#10506.

For an unhinted assignment to a class variable defined in a base class,
this allows subderived classes to only match the type in the base class,
rather than the one inferred from the assignment value.
wrwrwr added a commit to wrwrwr/mypy that referenced this issue Jan 21, 2023
Related python#10375 and python#10506.

For an unhinted assignment to a class variable defined in a base class,
this allows subderived classes to only match the type in the base class,
rather than the one inferred from the assignment value.
wrwrwr added a commit to wrwrwr/mypy that referenced this issue Jan 21, 2023
Related python#10375 and python#10506.

For an unhinted assignment to a class variable defined in a base class,
this allows subderived classes to only match the type in the base class,
rather than the one inferred from the assignment value.
wrwrwr added a commit to wrwrwr/mypy that referenced this issue Jan 21, 2023
Related python#10375 and python#10506.

For an unhinted assignment to a class variable defined in a base class,
this allows subderived classes to only match the type in the base class,
rather than the one inferred from the assignment value.
wrwrwr added a commit to wrwrwr/mypy that referenced this issue Jan 21, 2023
Related python#10375 and python#10506.

For an unhinted assignment to a class variable defined in a base class,
this allows subderived classes to only match the type in the base class,
rather than the one inferred from the assignment value.
@erictraut
Copy link

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

@hauntsaninja
Copy link
Collaborator

Fixed in #13494

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-inference When to infer types or require explicit annotations topic-inheritance Inheritance and incompatible overrides
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants