python / python/mypy

Cryptic "object is not iterable" warning when __iter__ is incorrectly annotated.

Open
#18,425 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

One issue that has bitten me a couple times was when I incorrectly wrote def __iter__(self) -> Iterable[...] instead of def __iter__(self) -> Iterator[...]. With the former code mypy produces the warning object is not iterable [misc] and I could not figure out why that was the case for a while... until I learned my lesson and am making this bug report.

To Reproduce

Consider the code.

from typing import Iterable, Iterator

class Foo1:
    def __iter__(self):
        return iter((1, 2))

x01, x11 = Foo1()

class Foo2:
    def __iter__(self) -> Iterable[int]:
        return iter((1, 2))

x02, x12 = Foo2()

class Foo3:
    def __iter__(self) -> Iterator[int]:
        return iter((1, 2))

x03, x13 = Foo3()

Actual Behavior

This produces the warnings

a.py:4: error: Function is missing a type annotation  [no-untyped-def]
a.py:13: error: "Foo2" object is not iterable  [misc]

These warnings are ALL correct. However, "Foo2" object is not iterable is tricky to understand because it mislead the developer thinks that the __iter__ method is not enough and something else is missing, while the other two implementations without and with annotations are accepted.

Expected Behavior

Mypy should report the following error message instead, for the line with def __iter__.

a.py:10: error: The return type of "Foo2.__iter__" should be "Iterator" or one of its supertypes  [misc]

And this check is enforced at runtime, e.g., returning a tuple from __iter__ crashes.

The error message is already being used for other cases, e.g. this

def a() -> types.GeneratorType:
    yield 1

produces

a.py:1: error: The return type of a generator function should be "Generator" or one of its supertypes  [misc]

Your Environment

  • Mypy version used: 1.13, 1.14
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): disallow_untyped_defs = true
  • Python version used: 3.11, 3.12

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the Python reproducer in the issue with mypy 1.13 or 1.14, then locate the type-checking path for incorrectly annotated iter methods. Add coverage for the Foo2 case and make the diagnostic identify the invalid return annotation; done means the misleading object-is-not-iterable error is replaced while the valid Foo1 and Foo3 cases remain accepted.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.