Skip to content

Type declarations of base class attributes not carried over to subclasses if None is present #2022

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

Closed
Vgr255 opened this issue Aug 13, 2016 · 4 comments
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal

Comments

@Vgr255
Copy link

Vgr255 commented Aug 13, 2016

Simplest repro:

class BaseClass:
    my_attr = () # type: tuple

class Subclass(BaseClass):
    my_attr = None

Output:

testing.py: note: In class "Subclass":
testing.py:5: error: Need type annotation for variable

However, if None isn't the sole value but part of something else, this is likely not the desired behaviour. Consider this:

from typing import Tuple, Any

class BaseClass:
    my_attr = ( ("", None), ) # type: Tuple[Tuple[str, Any]]

class Subclass(BaseClass):
    my_attr = (
        ("one",  set ),
        ("two",  str ),
        ("three",None),
    )

Output:

testing.py: note: In class "Subclass":
testing.py:8: error: Need type annotation for variable

Changing None for anything else, adding a # type: ignore comment on the ("one", set), line (but not on any other line of the assignment) silences the error. This is somewhat related to #1338 (and, to a lesser extent, #1032).

@gvanrossum gvanrossum added the bug mypy got something wrong label Aug 13, 2016
@gvanrossum gvanrossum added this to the 0.5 milestone Aug 13, 2016
@gvanrossum
Copy link
Member

Yeah, definitely a bug. I think it's related to #1338, the type of class attributes is just not checked against the base classes at all (unlike methods).

JukkaL pushed a commit that referenced this issue Nov 28, 2016
#2380)

* For class variables, lookup type in base classes (#1338, #2022, #2211)

* Ignore TypeVars from base class when looking up types of class variables

* Break even if the base type is a TypeVar

This avoids looking into the base class of a base class while the type has been changed

* Support TypeVar when lookup up class variables in a base class

* An additional test-case to see if TypeVars are resolved with an extra subclass

* Also handle TypeVars in, for example, a List

* Fix initial test-case

* Validate if type is defined with an incompatible value against the type of a base class

* Additional test case to ensure methods/variables don't overwrite each other

* Also support properties

* Add test case to show class variable type can be overwritten with Any
gvanrossum added a commit that referenced this issue Nov 28, 2016
gvanrossum pushed a commit that referenced this issue Jan 27, 2017
@gvanrossum
Copy link
Member

Looking into this again (now that #2510 has been merged) I think there's still something fishy here: I think the first example (in the absence of --strict-optional) should be silent, since it's essentially equivalent to

x = None  # type: int
x = None

which is silent.

(However the second example contains an error, since the subclass uses attr instead of my_attr. Fixing that, the example correctly complains that the top-level Tuple type in the subclass (of three items) is incompatible with the type from the base class (of 1 item).)

@Vgr255
Copy link
Author

Vgr255 commented Jan 28, 2017

Whoops, I probably messed up when I copied the repro over. Edited the comment to correct this. I sadly no longer have a use case for this, as the affected code is gone. I still think it's worth fixing, though, and I hope you figure it out. Cheers!

@gvanrossum gvanrossum removed this from the 0.5 milestone Mar 29, 2017
@JukkaL JukkaL added the false-positive mypy gave an error on correct code label May 18, 2018
@AlexWaygood
Copy link
Member

The example code no longer causes a mypy error if you use the --no-strict-optional option (which was the default at the time of the bug being filed). If you don't use the --no-strict-optional option, you just need to change the annotations to this:

class BaseClass:
    my_attr = () # type: tuple | None

class Subclass(BaseClass):
    my_attr = None

And mypy is fine with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong false-positive mypy gave an error on correct code priority-1-normal
Projects
None yet
Development

No branches or pull requests

4 participants