MyPy / python type hints doesn't catch called function that can return multiple types

788 Views Asked by At

The attrgetter function can return different types based on the arguments you give it. If you pass an iterable with one item, it will return simply the given field of an object; if you pass it an iterable with multiple items, it returns a tuple of these fields of an object.

However, when using type hints + MyPy, this discrepancy is not picked up by MyPy (it throws no errors):

from operator import attrgetter


class OneThing:
    foobar = "hello"
    fields = ['foobar']


class TwoThings:
    foobar = "hello"
    goodbye = "potatoes"
    fields = ['foobar', 'goodbye']


def attrgettertest(thing) -> tuple:
    return attrgetter(*thing.fields)(thing)


def main():
    onething = OneThing()
    twothings = TwoThings()

    t1 = attrgettertest(onething)
    t2 = attrgettertest(twothings)

    print("Attrgettertest on 'onething' returned  {} with type {}".format(
        t1, type(t1)))
    print("Attrgettertest on 'twothings' returned  {} with type {}".format(
        t2, type(t2)))


if __name__ == "__main__":
    main()

And the output:

$ python attrgettrtest.py 
Attrgettertest on 'onething' returned  hello with type <class 'str'>
Attrgettertest on 'twothings' returned  ('hello', 'potatoes') with type <class 'tuple'>
$ mypy attrgettrtest.py 
$ 

The expected result would be something like this:

import random    

def test() -> tuple:
    if random.choice([0, 1]):
        return ("foo", "bar")
    return "foo"

if __name__ == "__main__":
    for n in range(20):
        print(test())

$ mypy test.py 
test.py:8: error: Incompatible return value type (got "str", expected Tuple[Any, ...])

Is this a bug in MyPy?

1

There are 1 best solutions below

0
Josh P On BEST ANSWER

It seems that the issue here is that attrgetter has return type Any, and mypy doesn't catch this.

I posted this to the mypy repo and got the following answer:

I think the problem is that attrgetter has return type Any, so that your code passes. In principle, precise type checking would be difficult in such cases, however, there is a newly added flag --warn-return-any that will issue warnings in such situations (it will be available in 0.480, see PR #2854 for details).