runtype icon indicating copy to clipboard operation
runtype copied to clipboard

runtype does not properly handle OrderedDict

Open 27359794 opened this issue 1 month ago • 1 comments

Hi, thanks for this library!

First issue: runtype.issubclass disagrees with the built-in issubclass here:

>>> issubclass(collections.OrderedDict, dict)
True
>>> runtype.issubclass(collections.OrderedDict, dict)
False

Second issue: runtype.issubclass does not handle an OrderedDict with type parameters:

>>> issubclass(collections.OrderedDict[str, str], dict)
True
>>> runtype.issubclass(collections.OrderedDict[str, str], dict)
Traceback (most recent call last):
  File "<bla>/site-packages/runtype/pytypes.py", line 637, in to_canon
    return self.cache[t]
           ~~~~~~~~~~^^^
KeyError: collections.OrderedDict[str, str]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<bla>/site-packages/runtype/pytypes.py", line 640, in to_canon
    res = _type_cast_mapping[t]
          ~~~~~~~~~~~~~~~~~~^^^
KeyError: collections.OrderedDict[str, str]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<bla>/site-packages/runtype/validation.py", line 65, in issubclass
    return is_subtype(t1, t2)
           ^^^^^^^^^^^^^^^^^^
  File "<bla>/site-packages/runtype/validation.py", line 23, in is_subtype
    ct1 = type_caster.to_canon(t1)
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "<bla>//site-packages/runtype/pytypes.py", line 642, in to_canon
    res = self._to_canon(t)
          ^^^^^^^^^^^^^^^^^
  File "<bla>/site-packages/runtype/pytypes.py", line 633, in _to_canon
    raise NotImplementedError("No support for type:", t)
NotImplementedError: ('No support for type:', collections.OrderedDict[str, str])

Environment: Python 3.12, runtype version 0.5.3

27359794 avatar Dec 03 '25 16:12 27359794

Thanks for reporting. I added PR #75 to fix the issue. Now it will behave more like issubclass.

However... It's not really clear to me what is the behavior of issubclass.

For example, these seem to stand in contradiction to each other:

print(issubclass(dict, dict))       # True
print(issubclass(dict[str, str], dict)) # False
print(issubclass(collections.OrderedDict[str, str], dict))  # True
print(issubclass(collections.OrderedDict[str, str], collections.OrderedDict)) # False

Am I missing something?

erezsh avatar Dec 03 '25 22:12 erezsh