Closed
Description
Issue description
This doesn't generate an error:
# test_case7.py
from typing import List
def untyped_func_def_with_typed_body():
a: List[int] = [0, 1, 2]
key: str = "asdf"
a[key] # <- No error, despite internals being typed
This does:
# test_case8.py
from typing import List
def typed_func_def_with_typed_body() -> None:
a: List[int] = [0, 1, 2]
key: str = "asdf"
a[key] # <- *Now* this generates an error
That maybe technically "documented", but that's really esoteric and completely unintuitive. I've spent hours chasing this down.
Archived original flailing to arrive at core problem
UPDATE 2: Okay, this just keeps getting weirder and weirder. Consider:
# test_case3.py
def func():
a = [0, 1, 2]
a["asdf"] # <- This doesn't generate an error
b = [0, 1, 2]
b["asdf"] # <- But this does?!
Runtime:
% mypy --config=/dev/null test_case3.py
/dev/null: No [mypy] section in config file
test_case3.py:8: error: No overload variant of "__getitem__" of "list" matches argument type "str"
test_case3.py:8: note: Possible overload variants:
test_case3.py:8: note: def __getitem__(self, SupportsIndex) -> int
test_case3.py:8: note: def __getitem__(self, slice) -> List[int]
Found 1 error in 1 file (checked 1 source file)
UPDATE 1: You don't need the @overload
s. It still doesn't work without them. Here's the simplified case:
# test_case2.py
from typing import List, Union
class GetItemTest:
def __getitem__(self, key: Union[int, slice]) -> Union[int, List[int]]:
return list(range(10))[key]
def test_a():
a = GetItemTest()
a["asdf"] # <- Why isn't this a typing error?
Original case (same effect):
# test_case1.py
from typing import List, Union, overload
class GetItemTest:
@overload
def __getitem__(self, key: int) -> int:
...
@overload
def __getitem__(self, key: slice) -> List[int]:
...
def __getitem__(self, key: Union[int, slice]) -> Union[int, List[int]]:
return list(range(10))[key]
def test_a():
a = GetItemTest()
a["asdf"] # <- Why isn't this a typing error?
Runtime:
% python --version
Python 3.9.6
% pip list
Package Version
----------------- --------
mypy 0.910
mypy-extensions 0.4.3
pip 21.2.1
setuptools 57.4.0
toml 0.10.2
typing-extensions 3.10.0.0
% mypy --version
mypy 0.910
% mypy --config=/dev/null test_case1.py
/dev/null: No [mypy] section in config file
Success: no issues found in 1 source file
I can't prove it, but I feel like this used to work. It seems pretty basic.
Metadata
Metadata
Assignees
Labels
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
posita commentedon Jul 30, 2021
With
--verbose
if helpful:[-]No (longer any?) error when passing non-compliant type to overloaded __getitem__[/-][+]No (longer any?) error when passing non-compliant type to @overload-ed __getitem__[/+][-]No (longer any?) error when passing non-compliant type to @overload-ed __getitem__[/-][+]No (longer any?) error when passing non-compliant type to __getitem__ with typed key: Union[int, slice] parameter[/+][-]No (longer any?) error when passing non-compliant type to __getitem__ with typed key: Union[int, slice] parameter[/-][+]No (longer any?) error when passing non-compliant type to __getitem__ in function body?[/+][-]No (longer any?) error when passing non-compliant type to __getitem__ in function body?[/-][+]No (longer any?) error when passing non-compliant type to __getitem__ inside function body, but same statement generates error at module level[/+][-]No (longer any?) error when passing non-compliant type to __getitem__ inside function body, but same statement generates error at module level[/-][+]Regression: no error when passing non-compliant type to __getitem__ inside function body, but same statement generates error at module level[/+][-]Regression: no error when passing non-compliant type to __getitem__ inside function body, but same statement generates error at module level[/-][+]Regression(?): no error when passing non-compliant type to __getitem__ inside function body, but same statement generates error at module level[/+]posita commentedon Jul 30, 2021
I have now verified this happens with Python versions 3.6.14, 3.7.11, 3.8.2, 3.8.11, and 3.9.6.
pranavrajpal commentedon Jul 30, 2021
I think this is because of https://mypy.readthedocs.io/en/stable/common_issues.html#no-errors-reported-for-obviously-wrong-code. Does running mypy with
--check-untyped-defs
fix this?posita commentedon Jul 30, 2021
--check-untyped-defs
"fixes" this (in a sense):I still think this is a bug, for two reasons. First, the fact that it works at the module level and not the function level is just weird. Second, I swear this used to work with classes that defined their own
__getitem__
methods. (See mytest_case2.py
example in the original report.) Also, this still doesn't work without--check-untyped-defs
:Runtime:
posita commentedon Jul 30, 2021
Ugh, talk about a super sharp edge. This works as expected (since I typed the enclosing function):
posita commentedon Jul 30, 2021
As does this:
[-]Regression(?): no error when passing non-compliant type to __getitem__ inside function body, but same statement generates error at module level[/-][+]No errors on typed function internals if function itself is untyped; I'd argue that's probably incorrect behavior, but at the very least it's *super* confusing and *very* hard to diagnose when it happens[/+]erictraut commentedon Jul 30, 2021
This is yet another example that supports my thinking that
--check-untyped-defs
should default to on. See discussion here.[-]No errors on typed function internals if function itself is untyped; I'd argue that's probably incorrect behavior, but at the very least it's *super* confusing and *very* hard to diagnose when it happens[/-][+]No errors on typed function internals if function definition itself is untyped; I'd argue that's probably incorrect behavior, but at the very least it's *super* confusing and *very* hard to diagnose when it happens[/+]posita commentedon Jul 30, 2021
Maybe as a work-around, but functions seem like pretty arbitrary boundaries to try and walk this particular line, especially where bodies contain explicit type annotations. I can't see how ignoring those can be considered correct under any setting. In other words, yeah, totally make the sane thing the default thing, but I'm pretty sure this is still a bug.
JelleZijlstra commentedon Jul 30, 2021
It's documented that mypy doesn't type check unannotated functions (https://mypy.readthedocs.io/en/stable/common_issues.html#no-errors-reported-for-obviously-wrong-code). I don't disagree with you that this is unintuitive, but the other issue is a sufficient place to discuss that.
posita commentedon Jul 30, 2021
Yes, this appears to be a dupe of #3948.
But I don't think the documentation is even accurate. Consider:
According to the docs,
_untyped_init_a
shouldn't error, but it does. Un-annotated function bodies are treated inconsistently whereuntyped_defs
isFalse
.