I'm relatively new to Pylance (VS Code's static type checker, based on Pyright) and just stumbled upon this type checking error with the count() infinite iterator. I have some code I've been playing with, which I reduced to the following basic version which reproduces the problem:
from itertools import count
def foo() -> int:
for i in count():
if i == 42:
return i
print(foo())
I'm using this loop over count() as essentially a variation of while True, to manage an index for me while I'm waiting for a condition to be satisfied. Given it's an infinite loop, the only code path out of this function is via that condition inside the loop which returns an int, but Pylance/Pyright is giving me the following type error:
Function with declared return type "int" must return value on all code paths
Type "None" cannot be assigned to type "int" Pylance(reportGeneralTypeIssues)
I saw that I can silence the issue by either of the following:
- Suppressing the warning with
# type: ignore, which could swallow unrelated issues. - Making the return type
Optional[int], which is strictly wrong. - Adding a
return -1(or whatever fake value) at the end, which works, but adds a confusing no-op extra line. - Or just avoiding the issue and just rewriting this as an explicit infinite loop, which Pylance handles correctly:
def foo() -> int:
i = 0
while True:
if i == 42:
return i
i += 1
But I'm wondering if there's a cleaner solution here to somehow correctly mark this loop as infinite.
I would also appreciate insight as to the cause - is it just a Pylance/Pyright bug (missing feature), or is there a deeper technical limitation with marking count() as an infinite iterator?
The type system doesn't know whether a generator is infinite or not. There is an issue in
mypyrelated to this (#7374), but it was created in 2019 and it is labeled as low priority.There is also issue #5992, where Guido van Rossum (yes, the creator of Python himself) commented the following:
So I would go for the approach of adding an
assert Falseafter the loop. Alternatively you could also do something like this (mentioned in #5992):