-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Fix argument checking on empty dict with double stars #9629
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
Changes from 3 commits
a5dcac8
2a88bb8
13dc4d2
ff90cf3
989512b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -396,7 +396,7 @@ class A: pass | |
from typing import Any, Dict | ||
def f(*args: 'A') -> None: pass | ||
d = None # type: Dict[Any, Any] | ||
f(**d) # E: Too many arguments for "f" | ||
f(**d) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this no longer an error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is addressed by the author (not me) in the PR description.
The rationale being that since a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm open to persuasion on this, but to me it seems totally reasonable to give an error for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @JelleZijlstra One problem with giving an error on that is that it's a common pattern in Python's cooperative multiple inheritance to do forwarding like so: class SomeMixin:
def __init__(self, **kwargs):
# Do other things...
super().__init__(**kwargs)
class SomeBase:
def __init__(self, x, **kwargs):
self.x = x
super().__init__(**kwargs)
class C(SomeMixin, SomeBase):
pass Not everyone uses cooperative multiple inheritance, but I don't think this pattern should raise any type errors. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, that's a good point! Let's just land this in that case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you so much. I've been looking forward to this 😄 |
||
class A: pass | ||
[builtins fixtures/dict.pyi] | ||
|
||
|
@@ -491,3 +491,9 @@ m = {} # type: Mapping[str, object] | |
f(**m) | ||
g(**m) # TODO: Should be an error | ||
[builtins fixtures/dict.pyi] | ||
|
||
[case testPassingEmptyDictWithStars] | ||
def f(): pass | ||
|
||
f(**{}) | ||
[builtins fixtures/dict.pyi] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also add a test case where we check the this continues to generate an error:
|
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.
Unfortunately the
Any
type here may result in false negatives, since it's used for type inference:More generally, it would be great if we can avoid inferring
Any
types in fully annotated code.Random idea: Use
Mapping[str, <nothing>]
as the context, potentially only if the kwargs expression is an empty dictionary expression (check for it here). This would certainly be a hack, but at least it's a pretty localized hack.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 see... Another idea can be to relax the check here to allow the case where
typ
isdict[<nothing>, <nothing>]
. At first I didn't like this solution as I thought it was less elegant, but if trying to change the inferred type will result in a hacky code like you said, maybe this one is better?mypy/mypy/checkexpr.py
Lines 3933 to 3949 in 985a20d