-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Add new flag for warning about instantiating classes with declared but uninitialized attributes #13797
base: master
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I enabled the flag by default in order to look at the mypy_primer output. The error in https://github.com/mystor/git-revise is from this pattern: from __future__ import annotations
from typing import Type, cast
class A:
x: int
def __new__(cls: Type[A], x: int) -> A:
self = super().__new__(cls)
self.x = x
return cast(A, self)
a = A(3) I don't think this can be supported... |
https://github.com/encode/starlette has this: class State:
_state: typing.Dict[str, typing.Any]
def __init__(self, state: typing.Optional[typing.Dict[str, typing.Any]] = None):
if state is None:
state = {}
super().__setattr__("_state", state) Also very difficult to support, I think. |
This comment has been minimized.
This comment has been minimized.
This pattern in https://github.com/systemd/mkosi class A:
CONST: int
CONST = 4
a = A() should work though (even though that should be a I'll fix this. |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this is not a full review: just a bunch of ideas :)
test-data/unit/check-warnings.test
Outdated
# flags: --warn-uninitialized-attributes | ||
class A: | ||
x: int | ||
a = A() # E: Cannot instantiate abstract class "A" with abstract attribute "x" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should totally change the error message.
Class A
is not abstract by any means.
Maybe we should say: Cannot instantiate aclass "A" with annotated but unset attribute "x"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I now went with Class "A" has annotated but unset attributes: "x"
because "Cannot instantiate" seemed too strong to me (because the instantiation will work fine at runtime). But I'm not attached to this at all and I'm happy to change it again.
This comment has been minimized.
This comment has been minimized.
263cc42
to
3c1afaf
Compare
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
One question is whether initialization should only be recognized if it happens in the |
mypy/semanal_namedtuple.py
Outdated
elif isinstance(sym.node, Var): | ||
# NamedTuple fields are initialized in the generated __init__. | ||
sym.node.is_uninitialized = False | ||
pass | ||
# Keep existing (user-provided) definitions under mangled names, so they | ||
# get semantically analyzed. | ||
r_key = get_unique_redefinition_name(key, named_tuple_info.names) | ||
named_tuple_info.names[r_key] = sym | ||
if isinstance(value.node, Var): | ||
# NamedTuple fields are initialized in the generated __init__. | ||
value.node.is_uninitialized = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I honestly don't understand why I needed to add this check twice, but if I don't, then either the self-check or the tests fails.
mypy/semanal_namedtuple.py
Outdated
elif isinstance(sym.node, Var): | ||
# NamedTuple fields are initialized in the generated __init__. | ||
sym.node.is_uninitialized = False | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe because of pass
? Isn't it suppose to be continue
?
cd4f7d2
to
208e0a0
Compare
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
12bfe00
to
be8b79f
Compare
This comment has been minimized.
This comment has been minimized.
Please, resolve merge conflicts |
be8b79f
to
560f365
Compare
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
Fixes #4426
(also related: #4019)
Issue #4426 proposed prohibiting abstract attributes. I took a stab at implementing this, but I added it behind a new flag.
The new flag makes mypy complain when variables are declared in a class (with a type annotation) but never initialized. Other type checkers have similar features: for pyright, it's behind the flag
reportUninitializedInstanceVariable
and pyre does this by default.One problem is that there are many ways to go about this. I think there are 4 natural places where the warning could be raised:
I went with option C because 1) it was easier to implement because I could re-use the code that deals with Protocol attributes; 2) it's more flexible than option A and B while easier to keep track of than option D; and 3) it fits with other reporting patterns in mypy, which is to report abstract status at the point of instantiation.
Option C is more flexible because the following code is allowed:
Though I'll note that pyright and pyre went with option A (suppressing the error for abstract classes).
Because I repurposed the Protocol attribute code, the error messages aren't ideal yet, but I can still change that if the general idea of the PR is approved of. Currently, if
--warn-uninitialized-attributes
is turned on, then the error message for this codeis:
The name of the flag is
--warn-uninitialized-attributes
, but tell me if it should be something else.By the way, if I turn on this flag for the self check in the tests, then this is the result (8 errors).