Can mypy recognise custom unpacking?

Viewed 253

I have a class that provides __getitem__ - which python is happy to use for unpacking, but when I run mypy on the code I get List or tuple expected as variable arguments.

Here's a minimal reproducer

from typing import Any

class Foo:
    def __getitem__(self, idx: int) -> Any:
        if idx == 0:
            return 1
        if idx == 1:
            return "bye"
        else:
            raise IndexError


f = Foo()
t = ("hello", *f)

print(t)  # prints ("hello", 1, "bye")

I don't want to have to add an error suppression to each point that I do *f, that defeats the whole purpose of the class.

Is there some way to make mypy understand that unpacking a Foo is OK?

If it matters, I'm currently using mypy 0.800, and Python 3.7.6.

1 Answers

It looks like MyPy is expecting unpackable objects to have an __iter__ method — which is fair enough, in a way, since it's fairly rare for an object to implement __getitem__ and not implement __iter__. You can get the MyPy error to go away through a little bit of lying: tell MyPy there's an __iter__ method even though you have no intention of implementing one. Seems to work on python 3.7/MyPy 0.800 as well as python 3.10/MyPy 0.910.

from typing import Any, Callable, Iterator

class Foo:
    __iter__: Callable[["Foo"], Iterator[Any]]
    
    def __getitem__(self, idx: int) -> Any:
        if idx == 0:
            return 1
        if idx == 1:
            return "bye"
        else:
            raise IndexError


f = Foo()
t = ("hello", *f)

print(t)  # prints ("hello", 1, "bye")
Related