You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow disabling implicit Any for type aliases #2696
reveal_type for output: Revealed type is 'def [T in (builtins.list[builtins.int], builtins.dict)] (inp: T-1, processor: def (Any))'`
Processor is implicitly treated as Processor[Any] in this case.
Changing output to def output(inp: T, processor: Processor[T]) -> None: resolves the issue and lets mypy catch the bug.
The problem is that implicit Any for type aliases can easily go unnoticed.
Suggestions:
As suggested by @roganov & @ilevkivskyi : Add --disable-implicit-any flag to mypy, which will disable this behavior and forces the user to be explicit. Drawback, users who do not know about the flag might learn about the bug the hard way (in production 😉 )
Disable implicit Any by default for type aliases, and force users to be explicit (either by parameterizing [Any] or [T]). Drawback, might introduce a lot of mypy errors for existing, "error free" code base (confusing/annoying to users). Also, not entirely sure about how this impacts other scenarios.
Produce warning when used type alias has no explicit parameterization. This will make mypy exit without failure, but just point the user to potential bugs. Drawback, warnings might be annoying for users who are ok with their codebase (i.e. might require --suppress-implicit-any-warning)
One option would be to use deprecate --disallow-untyped-defs and use --disallow-implicit-any as a superset of that option + checking that there no implicit Any types for other reasons, such the example above.
Hm, I expect that the "x: Iterable" case is very common. Would be worth doing a little experiment with that: find the code that implements this, make it raise an error instead, and see what it catches in some real-world codebases, starting with mypy. FWIW the pattern '\[AnyType\(\)\]\s*\*' seems to find many of these (I count 11).
I'm very much in favor of --disallow-implicit-any.
However, this isn't currently allowed (not sure why):
from typing import *
T = TypeVar('T')
x: List[T] # Invalid type
ListAlias = List[T]
y: ListAlias[T] # Invalid type
def f() -> None:
x: ListAlias[T] # Invalid type
So when we need to define variables that belong to a generic container type, but without the item type being part of the type of the function call arguments, we have to rely on implicit Any like this:
from typing import *
T = TypeVar('T')
x: List
ListAlias = List[T]
y: ListAlias
def f() -> None:
x: ListAlias
Therefore I think either the proposed --disallow-implicit-any flag should not create warnings in the second code snippet; or the first code snippet should be made legal.
But what you expect to be the meaning of this? Type variables are only used for generic functions, and generic types and aliases. What would be the meaning of an unbound type variable in an annotation?
I agree, x: SomeGenericContainerAlias[T] outside a function signature leaves mypy no chance to solve for T; however, it can still be used to define a generic container if someone prefers to completely eliminate reliance on implicit Any. I didn't mean to propose that, just listing it as an option.
My main point was that currently we often rely on implicit Any with a normal generic or a generic alias to specify a container type (as in my second code snippet). So --disallow-implicit-any shouldn't complain in those cases.
It feels like a special case is needed for aliases.
When C is a generic class (defined with a class statement that uses a type variable in a base class), I think we should still allow using x: C as a shorthand for x: C[Any].
But when A is a generic alias (defined with an assignment statement using a type variable on the right-hand side) the experience from #2690 and the discussion here suggest that it may be better to outright reject using x: A, instead requiring x: A[Any] if that's what is meant, or (in the parameter list of a generic function or in the body of a generic class) x: A[T].
I'm not sure I understand why we'd want to make that distinction. It seems like a good idea to keep the behavior of aliases and classes as similar as possible.
It's just a hunch based on experience -- I've fallen into this trap several
times. Somehow `A = List[T]` doesn't scream "generic" like `class
A(List[T]):` does.
I think this is now fixed since we have --disallow-any=generics in 0.540 that also catches implicit Any in generic aliases. (IIRC it was replaced by a dedicated flag in a recent PR.)
Activity
JukkaL commentedon Jan 16, 2017
One option would be to use deprecate
--disallow-untyped-defsand use--disallow-implicit-anyas a superset of that option + checking that there no implicitAnytypes for other reasons, such the example above.ilevkivskyi commentedon Jan 16, 2017
+1 to Jukka's idea. We have at least three places where an absence of type is equivalent to
Any:def f(x, ...): ...is equivalent todef f(x: Any, ...): ...x: Iterableis equivalent tox: Iterable[Any]Maybe there others that I don't remember. It would be difficult to remember what is the option to disable each usage.
gvanrossum commentedon Jan 16, 2017
Hm, I expect that the "x: Iterable" case is very common. Would be worth doing a little experiment with that: find the code that implements this, make it raise an error instead, and see what it catches in some real-world codebases, starting with mypy. FWIW the pattern
'\[AnyType\(\)\]\s*\*'seems to find many of these (I count 11).pkch commentedon Feb 24, 2017
I'm very much in favor of
--disallow-implicit-any.However, this isn't currently allowed (not sure why):
So when we need to define variables that belong to a generic container type, but without the item type being part of the type of the function call arguments, we have to rely on implicit
Anylike this:Therefore I think either the proposed
--disallow-implicit-anyflag should not create warnings in the second code snippet; or the first code snippet should be made legal.ilevkivskyi commentedon Feb 24, 2017
But what you expect to be the meaning of this? Type variables are only used for generic functions, and generic types and aliases. What would be the meaning of an unbound type variable in an annotation?
pkch commentedon Feb 24, 2017
I agree,
x: SomeGenericContainerAlias[T]outside a function signature leavesmypyno chance to solve forT; however, it can still be used to define a generic container if someone prefers to completely eliminate reliance on implicitAny. I didn't mean to propose that, just listing it as an option.My main point was that currently we often rely on implicit
Anywith a normal generic or a generic alias to specify a container type (as in my second code snippet). So--disallow-implicit-anyshouldn't complain in those cases.gvanrossum commentedon Feb 25, 2017
It feels like a special case is needed for aliases.
When
Cis a generic class (defined with aclassstatement that uses a type variable in a base class), I think we should still allow usingx: Cas a shorthand forx: C[Any].But when
Ais a generic alias (defined with an assignment statement using a type variable on the right-hand side) the experience from #2690 and the discussion here suggest that it may be better to outright reject usingx: A, instead requiringx: A[Any]if that's what is meant, or (in the parameter list of a generic function or in the body of a generic class)x: A[T].ddfisher commentedon Feb 27, 2017
I'm not sure I understand why we'd want to make that distinction. It seems like a good idea to keep the behavior of aliases and classes as similar as possible.
gvanrossum commentedon Feb 28, 2017
ilevkivskyi commentedon Nov 2, 2017
I think this is now fixed since we have
--disallow-any=genericsin 0.540 that also catches implicitAnyin generic aliases. (IIRC it was replaced by a dedicated flag in a recent PR.)