-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Add flag to output error if a typed function is used with an untyped decorator #3555
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
Conversation
and the --disallow-untyped-defs flag is enabled
# Conflicts: # mypy/messages.py
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.
Before merging, can you run this against our internal codebases and make sure that there aren't too many errors and that the errors seem like they really should be fixed?
mypy/checker.py
Outdated
def is_typed_callable(c: Optional[Type]) -> bool: | ||
if not c or not isinstance(c, CallableType): | ||
return False | ||
return all(not isinstance(t, AnyType) or not t.implicit |
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.
Nit: I think this would be much clearer as not any(isinstance(t, AnyType) and t.implicit)
.
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.
(If you disagree, feel free to leave as-is.)
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.
Hmm, I think that's better!
mypy/checker.py
Outdated
func: FuncDef, | ||
dec_type: Type, | ||
dec_expr: Expression) -> None: | ||
def is_typed_callable(c: Optional[Type]) -> bool: |
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.
It's better to not define subfunctions unless they actually use variables from the parent function. I'd make these top-level instead.
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.
All right, that makes sense.
The main concern is that this will be seen as a regression by people who have carefully annotated (part of) their codebase but are using untyped decorators (maybe from another part of their codebase). On the one hand these people have a problem (unannotated code persists, and the call sites may have further errors), on the other hand they may not have the bandwidth to solve it quickly, and until it's solved they can no longer use the |
After thinking about this some more, I agree with you, this change would discourage use of I think it would be reasonable to have a new flag Just a note that there is |
OK, let's do the separate flag. Re: `--disallow-any=decorator` -- maybe
that should be `decorated` instead? Or are you suggesting that that flag is
sufficient for this use case? Maybe it is.
|
(The flag is actually |
I think a new flag is the right way forward here. @ilinum can you make that change? |
# Conflicts: # mypy/options.py
--disallow-untyped-defs
flag is enabled
(Minor note: PR/commit names should be actions.) |
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.
Some functionality and testing changes needed.
mypy/checker.py
Outdated
def is_typed_callable(c: Optional[Type]) -> bool: | ||
if not c or not isinstance(c, CallableType): | ||
return False | ||
return not any(isinstance(t, AnyType) and t.implicit |
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.
It looks like this is checking for a fully typed callable, but we should check for a callable with that has any annotations. This case should have appeared in tests.
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.
Done!
test-data/unit/check-flags.test
Outdated
return i | ||
|
||
[case testDisallowUntypedDefsMultipleUntypedDecorators] | ||
# flags: --disallow-untyped-decorators --disallow-untyped-defs |
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.
What is the --disallow-untyped-defs
part of this test testing?
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.
Hmm, my original thinking was to make sure to interacts well with --disallow-untyped-defs
but I think that the flags don't have that much in common. I removed the test and added another one for multiple decorators.
test-data/unit/cmdline.test
Outdated
z.py:1: error: Function is missing a type annotation | ||
x.py:1: error: Function is missing a type annotation | ||
|
||
[case testDisallowUntypedDefsUntypedFunc] |
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.
Why can't this test be in check-flags.test
?
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.
Not sure of the original reason.
Moved to check-flags.test
.
|
||
@d # no error | ||
def f(): 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.
Please add tests for partially typed functions.
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.
Done!
Okay, code review feedback should be addressed now! |
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.
LGTM! Tiny tiny nit -- feel free to merge if you disagree, otherwise fix and then merge.
mypy/checker.py
Outdated
|
||
self.check_for_missing_annotations(fdef) | ||
if 'unimported' in self.options.disallow_any: | ||
if fdef.type and isinstance(fdef.type, CallableType): |
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.
Nit: I think this may be slightly clearer as not all(... and ...)
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.
Hmm, yep, I think that's better!
I will make the change, make sure it passes the tests and then merge.
No description provided.