'How do I specify OrderedDict K,V types for Mypy type annotation?

I am using Python 3.5 together with Mypy to have some basic static checking for my script. Recently I refactored some methods to return OrderedDict, but ran into "'type' object is not subscriptable" error, when I tried to use return annotation with Key and Value types specified.

Reduced example:

#!/usr/bin/env python3.5

from collections import OrderedDict

# this works
def foo() -> OrderedDict:
    result = OrderedDict() # type: OrderedDict[str, int]
    result['foo'] = 123
    return result

# this doesn't
def foo2() -> OrderedDict[str, int]:
    result = OrderedDict() # type: OrderedDict[str, int]
    result['foo'] = 123
    return result

print(foo())

And this is python output when it is run:

Traceback (most recent call last):
  File "./foo.py", line 12, in <module>
    def foo2() -> OrderedDict[str, int]:
TypeError: 'type' object is not subscriptable

Mypy however has no problem with the type annotation in comment and will in fact warn if I try to do result[123] = 123.

What is causing this?



Solution 1:[1]

As a workaround, you can also put the return type into a string to satisfy both Mypy and Python 3.6:

from collections import OrderedDict

def foo() -> 'OrderedDict[str, int]':
    result = OrderedDict()
    result['foo'] = 123
    return result

Solution 2:[2]

What you can also try is using MutableMapping (like in this Answer: https://stackoverflow.com/a/44167921/1386610)

from collections import OrderedDict
from typing import Dict

def foo() -> MutableMapping[str, int]:
    result = OrderedDict() # type: MutableMapping[str, int]
    result['foo'] = 123
    return result

Solution 3:[3]

I don't know which version allowed this, but a better solution as for March/24/2021, tested for Python 3.7.5:

from collections import OrderedDict
import typing

def foo() -> typing.OrderedDict[str, int]:
    result: typing.OrderedDict[str, int] = OrderedDict()
    result['two'] = 2
    return result

Enjoy all worlds!

Solution 4:[4]

collections.OrderedDict is not the same that typing.OrderedDict

from collections import OrderedDict as collections_OrderedDict
from typing import OrderedDict

# this works
def foo() -> OrderedDict[str, int]:
    result = collections_OrderedDict()
    result['foo'] = 123
    return result

print(foo())

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dion
Solution 2 Arany
Solution 3 Gulzar
Solution 4 xxxyxxx16