1

When I use a dict where members have different types, mypy accepts my type definitions within the class but not outside.

The access of member 'first' in

ExampleClass.__str__()

does not produce an error from mypy when I iterate over it.

But when I get same data outside the class, iterating over 'first' causes mypy to generate an error.

What is going on?

from typing import Union, List, Dict
from collections import namedtuple

class ExampleClass:
    PrimeOption = namedtuple('PrimeOption', ['value1', 'value2'])
    PrimeList = List[PrimeOption]
    ExampleData = Dict[str, Union[bool, PrimeOption]]

    def __init__(self):
        self.data:ExampleData = {'flag':False,
                                 'first': [ExampleClass.PrimeOption.value1]}

    def get(self) -> ExampleData:
        return self.data

    def __str__(self):
        t = self.get()
        out = 'ExampleClass:'
        for i in t['first']:
            out += str(i)
        return out

if __name__ == "__main__":
    obj = ExampleClass()
    print(obj)

    t = obj.get()
    for i in t['first']:
        print(i)

This produces one error from mypy:

$ mypy union.py
union.py:33: error: Item "bool" of "Union[bool, PrimeOption]" has no attribute "__iter__" (not iterable)
Found 1 error in 1 file (checked 1 source file)

I am using python3.8.8 and mypy 0.812.

Edit: This needs to work with python3.6.

ahnkle
  • 467
  • 6
  • 17
  • what you probably need is a [`TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict) – Azat Ibrakov Apr 01 '21 at 11:03
  • Some targets of this code use python 3.6 (which doesn't have TypedDict). Using ExampleData = TypedDict('ExampleData', {'flag': bool, 'first': PrimeOption}) does fix error. – ahnkle Apr 01 '21 at 11:12
  • `TypedDict` was backported to Python3.6 with [`typing_extensions` package](https://pypi.org/project/typing-extensions) – Azat Ibrakov Apr 01 '21 at 11:14
  • I will flag the comment of [Azat Ibrakov](https://stackoverflow.com/users/5997596/azat-ibrakov) as the answer. – ahnkle Apr 01 '21 at 11:27

1 Answers1

0

As Azat Ibrakov says, in a comment above, TypedDict is ported to python3.6 in the typing extension package.

By adding

from typing_extensions import TypedDict

and replacing ExampleData with

    ExampleData = TypedDict('ExampleData', {'flag': bool, 'first': PrimeOption})

no error is reported.

The changes work for python3.6 and python3.8.

ahnkle
  • 467
  • 6
  • 17
  • we can also add in `requirements.txt` (or whatever dependencies list is used) line with [environment marker](https://www.python.org/dev/peps/pep-0496/) like `typing-extensions; python_version < '3.8'` and after that import `try: from typing import TypedDict\ except ImportError: from typing_extensions import TypedDict` – Azat Ibrakov Apr 01 '21 at 13:04