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?
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: