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
Unpacking an iterable with an __iter__ method that returns self leads to variable being silently inferred as Any #14819
@sobolevn, do you think this would be a reasonable fix? It makes me wonder why we have the iterable_item_type() method at all, and whether other uses of this method in checker.py should also be converted to analyze_iterable_item_type_without_expression()
I can't tell whether the required change to testInferringTypesFromIterable would be a feature or a bug. Mypy usually infers that unannotated methods return Any. It feels weird to me that this test case is currently asserting that mypy should infer a non-Any type here, despite both __iter__ and __next__ being unannotated.
It makes me wonder why we have the iterable_item_type() method at all, and whether other uses of this method in checker.py should also be converted to analyze_iterable_item_type_without_expression()
I don't really know. It was my first Iterable-related PR.
I can't tell whether the required change to testInferringTypesFromIterable would be a feature or a bug
It is really hard to tell whether your solution is a bug or an improvement (sadly, python's type system is not documented enough).
Is the behaviour in those two tests really expected? As per docs, all untyped methods should be treated as annotated with Any for all arguments and return type, while here this rule is violated (__iter__ is unannotated, so it's essentialy unpacking Any, which should give n-tuple of Anys of size corresponding to LHS). The inherited signature should not be taken into account. The proposed change fixes this behaviour and makes handling of such cases more consistent - what's the reasoning behind that tests?
@sterliakov, I don't disagree with anything you're saying. I'm just somewhat hesitant to make that change here, given that these tests have been in place for 10 years or more -- it could be the case that many people are depending on this being established mypy behaviour. The fact that two tests assert the same behaviour indicates that it was a deliberate decision, even if we might disagree with that decision now.
Fixing the original bug in this issue thread while maintaining the behaviour asserted in these two tests actually appears to be fairly trivial, so for now, I'm planning on opening a PR to do that. I'll open a followup issue after that to discuss whether the behaviour that's asserted in these two tests should be changed.
@sterliakov, the behaviour does appear to be consistent with some other parts of mypy also. For example:
fromtypingimportIterableclassFoo(Iterable[int]):
def__iter__(self):
yieldfromrange(5)
x=list(Foo())
reveal_type(x) # Revealed type is "builtins.list[builtins.int]"
I guess that this is a general principle applied by mypy that I wasn't aware of, where classes that directly inherit from protocols are assumed to have the more specific signature of their superclass, even if the method on the subclass is unannotated.
Activity
AlexWaygood commentedon Mar 2, 2023
This one-line change fixes the issue:
But it causes this test to fail:
mypy/test-data/unit/check-inference.test
Lines 377 to 389 in bed49ab
The test succeeds once again if we add annotations:
@sobolevn, do you think this would be a reasonable fix? It makes me wonder why we have the
iterable_item_type()method at all, and whether other uses of this method inchecker.pyshould also be converted toanalyze_iterable_item_type_without_expression()AlexWaygood commentedon Mar 2, 2023
I can't tell whether the required change to
testInferringTypesFromIterablewould be a feature or a bug. Mypy usually infers that unannotated methods returnAny. It feels weird to me that this test case is currently asserting that mypy should infer a non-Anytype here, despite both__iter__and__next__being unannotated.sobolevn commentedon Mar 2, 2023
I don't really know. It was my first
Iterable-related PR.It is really hard to tell whether your solution is a bug or an improvement (sadly, python's type system is not documented enough).
AlexWaygood commentedon Mar 2, 2023
Thanks! I guess I'll experiment with a broader refactor and see if anything (else) breaks :)
AlexWaygood commentedon Mar 2, 2023
The test was introduced in 2013, in 6ecbd1f
AlexWaygood commentedon Mar 2, 2023
There is another test in a different file that asserts the same behaviour, so I'm going for a slightly different approach:
mypy/test-data/unit/check-generic-subtyping.test
Lines 732 to 741 in 099500e
sterliakov commentedon Mar 2, 2023
Is the behaviour in those two tests really expected? As per docs, all untyped methods should be treated as annotated with
Anyfor all arguments and return type, while here this rule is violated (__iter__is unannotated, so it's essentialy unpackingAny, which should give n-tuple ofAnys of size corresponding to LHS). The inherited signature should not be taken into account. The proposed change fixes this behaviour and makes handling of such cases more consistent - what's the reasoning behind that tests?AlexWaygood commentedon Mar 2, 2023
@sterliakov, I don't disagree with anything you're saying. I'm just somewhat hesitant to make that change here, given that these tests have been in place for 10 years or more -- it could be the case that many people are depending on this being established mypy behaviour. The fact that two tests assert the same behaviour indicates that it was a deliberate decision, even if we might disagree with that decision now.
Fixing the original bug in this issue thread while maintaining the behaviour asserted in these two tests actually appears to be fairly trivial, so for now, I'm planning on opening a PR to do that. I'll open a followup issue after that to discuss whether the behaviour that's asserted in these two tests should be changed.
Fix `Any` inference when unpacking iterators that don't directly inhe…
AlexWaygood commentedon Mar 3, 2023
@sterliakov, the behaviour does appear to be consistent with some other parts of mypy also. For example:
https://mypy-play.net/?mypy=latest&python=3.11&gist=689e0a0950b2f48cf9608ffe03c47926
I guess that this is a general principle applied by mypy that I wasn't aware of, where classes that directly inherit from protocols are assumed to have the more specific signature of their superclass, even if the method on the subclass is unannotated.