Conversation
|
Since you say "experimental" I'm not reviewing this yet and I've added "[WIP]" to the subject. (I think GMail may even thread notifications correctly because of the brackets.) |
|
It's far from perfect, but since it caught quite a few unintentional |
|
I propose that @ddfisher should review this. |
ilinum
left a comment
There was a problem hiding this comment.
I provided some cosmetic feedback but I unfortunately, I can't give any deep review since my knowledge of mypy is limited. Perhaps, @ddfisher can help.
Overall, I think this feature is great! We should try to finish it up and merge it.
Maybe we can name the flag --warn-implicit-any-generic or --disallow-implicit-any-generic.
|
|
||
| def fail(self, msg: str, ctx: Context, serious: bool = False, *, | ||
| blocker: bool = False) -> None: | ||
| blocker: bool = False, implicit_any: bool = False) -> None: |
There was a problem hiding this comment.
It seems like adding an extra parameter to fail function might not be the best way to do it.
I would try to keep this function generic for any kind of failures.
Perhaps, you can check if the error is in the caller.
There was a problem hiding this comment.
I agree. Unfortunately, I need to suppress the error message based on the information (options, and whether the module being checked is a stub) that's unavailable inside TypeAnalyser methods where the error occurs. I am not sure what the best fix for this would be. If I don't add an extra parameter to fail, I'll have to pass all this information into TypeAnalyser, but that's not good either since TypeAnalyser should not care about those details.
|
|
||
| def fail(self, msg: str, ctx: Context, *, blocker: bool = False) -> None: | ||
| def fail(self, msg: str, ctx: Context, *, blocker: bool = False, | ||
| implicit_any: bool = False) -> None: |
There was a problem hiding this comment.
Same as above - not sure if it's good to have an implicit_any parameter.
| if not self.options.warn_implicit_any or self.errors.file.endswith('.pyi'): | ||
| return | ||
| # TempNode, so must have already reported in the first pass | ||
| if ctx.get_line() == -1: |
There was a problem hiding this comment.
This seems like a hack but I couldn't find a way to do it better. Perhaps, someone with more mypy experience may help with that?
There was a problem hiding this comment.
Are you talking about checking for stubs or checking for temporary nodes? I don't know if I would cosnider either of them a hack (my threshold of hackiness in the error-reporting code is much higher than in normal code); but if anyone has a better solution, it would be nice.
| return self.analyze_callable_type(t) | ||
| elif fullname == 'typing.Type': | ||
| if len(t.args) == 0: | ||
| self.implicit_any('Type without type args', t) |
There was a problem hiding this comment.
There doesn's seem to be a test case for this. It's probably worth having one.
| if self.nesting_level > 0: | ||
| self.fail('Invalid type: ClassVar nested inside other type', t) | ||
| if len(t.args) == 0: | ||
| self.implicit_any('ClassVar without type args', t) |
There was a problem hiding this comment.
There doesn's seem to be a test case for this. It's probably worth having one.
| # context. This is slightly problematic as it allows using the type 'Any' | ||
| # as a base class -- however, this will fail soon at runtime so the problem | ||
| # is pretty minor. | ||
| self.implicit_any('Assigning value of type Any', t) |
There was a problem hiding this comment.
There doesn's seem to be a test case for this. It's probably worth having one.
mypy/typeanal.py
Outdated
| fallback=instance) | ||
| return instance | ||
| else: | ||
| self.implicit_any('Fallback', t) |
There was a problem hiding this comment.
This seems to be a debug statement.
There was a problem hiding this comment.
Hmm, how can you tell that this cannot happen in a production run?
| def fail(self, msg: str, ctx: Context, *, blocker: bool = False, | ||
| implicit_any: bool = False) -> None: | ||
| if implicit_any: | ||
| if not self.options.warn_implicit_any or self.errors.file.endswith('.pyi'): |
There was a problem hiding this comment.
There should be a better way for checking for stub files but I can't seem to find it.
Why are you limiting the flag to non-stub files anyway?
There was a problem hiding this comment.
I also can't find it.
In stub files, a lot of the times the type argument in genertic types is omitted (e.g., Union[type, Tuple], def f() -> tuple:, def g() -> Iterable:, etc.). There'll be hundreds of warnings like this, making the flag unusable.
I am sure we don't want to change the stubs to avoid implicit Any (and even if we did, that change would have to happen first, before warn_implicit_any starts paying attention to stubs).
|
Just remembered this doesn't cover the cases when not all type parameters are specified. So like |
What do you mean by this? |
|
@ilevkivskyi you are right. I looked at the code and it didn't seem like it would handle these kind of errors. But I just ran mypy now and it is an error. |
|
@pkch are you interested in working on this? |
|
Ah yes, I'm going to make the fixes I'm aware of. However, I'm still not sure if the overall approach is acceptable. |
(--disallow-any=generics) This code is based on python#3141 by pkch. This option disallows implicit Anys from omitted type parameters to generic types. For instance, `def x() -> List` would produce an error while `def x() -> List[Any]` is allowed. Note that with the flag enabled builtin generic types such as `list` and `set` are also forbidden.
|
I reworked this PR and submitted it as #3637. Closing this PR in favor of the new one. |
(--disallow-any=generics) This code is based on #3141 by pkch. This option disallows implicit Anys from omitted type parameters to generic types. For instance, `def x() -> List` would produce an error while `def x() -> List[Any]` is allowed. Note that with the flag enabled builtin generic types such as `list` and `set` are also forbidden.
Experimental: attempt to address parts of #2901