I've been trying to introduce disallow_any_generics = true to an already extensively typed code base of ~48kSLOC, and the only remaining issue is typing OrderedDicts.
Given this configuration:
[mypy]
check_untyped_defs = true
disallow_any_generics = true
disallow_untyped_defs = true
ignore_missing_imports = true
no_implicit_optional = true
warn_redundant_casts = true
warn_return_any = true
warn_unused_ignores = true
Code with implicit Any:
from collections import OrderedDict
from typing import Any
def name(value: OrderedDict) -> None:
pass
This fails validation because of disallow_any_generics = true:
$ mypy example.py
example.py:4: error: Missing type parameters for generic type
Code with typed OrderedDict:
from collections import OrderedDict
from typing import Any
def name(value: OrderedDict[Any, Any]) -> None:
pass
This passes validation, but doesn't run:
$ python example.py
Traceback (most recent call last):
File "example.py", line 4, in <module>
def name(value: OrderedDict[Any, Any]) -> None:
TypeError: 'type' object is not subscriptable
Versions:
$ python --version
Python 3.6.8
$ mypy --version
mypy 0.720
(Also failed on mypy 0.711.)
I'd expect either the first snippet to be valid or the second snippet to run. As it is I'm stuck for how to proceed.
You can use string literal escapes, such as value: 'OrderedDict[Any, Any]'. Another option is from __future__ import annotations (introduced in Python 3.7).
@JukkaL Is there no way to do this without quoting the type? Because even if I if TYPE_CHECKING: from collections import OrderedDict that triggers an issue in flake8:
F401 'collections.OrderedDict' imported but unused
You can use from __future__ import annotations in 3.7+.
do you want typing.OrderedDict and not collections.OrderedDict for that annotation?
I was going to say that too but it turns out there is no typing.OrderedDict.
there is in 3.7 iirc
Oh, you're right, it is in 3.7 (https://github.com/python/cpython/blob/3.7/Lib/typing.py) but not in the typing repo (https://github.com/python/typing/blob/master/src/typing.py) where I checked first. I filed python/typing#679 to add it.
If mypy sees that OrderedDict (or another class that doesn't support indexing at runtime) is missing required generic type args, we could give a better error message that suggests using string literal escaping.
Relevant docs https://mypy.readthedocs.io/en/latest/common_issues.html#using-classes-that-are-generic-in-stubs-but-not-at-runtime
Most helpful comment
You can use string literal escapes, such as
value: 'OrderedDict[Any, Any]'. Another option isfrom __future__ import annotations(introduced in Python 3.7).