I want to validate a dictionary with a key whose value is another dictionary.
Therefore, I have a parent TypedDict with a key targeting another TypedDict.
The thing is, I am using the NotRequired
clause, which is available in Python 3.10 through the typing_extensions
package (4.4.0 being the latest version for now).
As seen at https://peps.python.org/pep-0655/#usage-in-python-3-11 , in Python 3.10, when using the NotRequired
clause, it is recommended to use the TypedDict class from typing_extensions
from typing_extensions import TypedDict
# instead of
from typing import TypedDict
But trying to validate this dict with this configuration gives me the following error:
root@340bf78f3c82:/$ python script.py
Traceback (most recent call last):
File "/f/.local/lib/python3.10/site-packages/strongtyping/strong_typing_utils.py", line 489, in check_type
is_instance = isinstance(argument, type_of) or argument == type_of
File "/f/.local/lib/python3.10/site-packages/typing_extensions.py", line 671, in _check_fails
raise TypeError('TypedDict does not support instance and class checks')
TypeError: TypedDict does not support instance and class checks
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/f/src/script.py", line 17, in <module>
ParentType(parent)
File "/f/.local/lib/python3.10/site-packages/strongtyping/strong_typing.py", line 182, in __call__
if not checking_typing_typedict_values(arguments, self.__annotations__, self.__total__):
File "/f/.local/lib/python3.10/site-packages/strongtyping/strong_typing_utils.py", line 268, in checking_typing_typedict_values
return all(check_type(args.get(key), val) for key, val in required_types.items())
File "/f/.local/lib/python3.10/site-packages/strongtyping/strong_typing_utils.py", line 268, in <genexpr>
return all(check_type(args.get(key), val) for key, val in required_types.items())
File "/f/.local/lib/python3.10/site-packages/strongtyping/strong_typing_utils.py", line 491, in check_type
return isinstance(argument, type_of._subs_tree()[1:])
File "/f/.local/lib/python3.10/site-packages/strongtyping/strong_typing.py", line 136, in __getattr__
return getattr(self.cls, item)
AttributeError: type object 'ChildType' has no attribute '_subs_tree'
Python Version used
Python 3.10.4 (main, May 28 2022, 13:25:38) [GCC 10.2.1 20210110] on linux
Package Version used
strongtyping==3.10.3
Addon in use
strongtyping_modules [yes/no] : no
To Reproduce
Steps to reproduce the behavior:
- Run a container of this docker image
python:3.10.4-slim-bullseye
docker run -it --rm python:3.10.4-slim-bullseye bash
- In this container, install the following :
pip install typing-extensions==4.4.0
pip install strongtyping==3.10.3
- In this container, run the following script:
from typing_extensions import NotRequired, TypedDict
from strongtyping.strong_typing import match_class_typing
@match_class_typing
class ChildType(TypedDict):
key_a: int
key_b: int
@match_class_typing
class ParentType(TypedDict):
child: ChildType
not_required: NotRequired[int]
parent = {"child": {"key_a": 1, "key_b": 2}}
ParentType(parent)
Expected behavior
Should exit without error.
Desktop (please complete the following information):
$ uname -a
Linux c 5.13.0-25-generic #26~20.04.1-Ubuntu SMP Fri Jan 7 16:27:40 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Additional context
It is to note that the following works as expected though:
from typing import TypedDict
from typing_extensions import NotRequired
from strongtyping.strong_typing import match_class_typing
@match_class_typing
class ChildType(TypedDict):
key_a: int
key_b: int
@match_class_typing
class ParentType(TypedDict):
child: ChildType
not_required: NotRequired[int]
parent = {"child": {"key_a": 1, "key_b": 2}}
ParentType(parent)
But then, in this case, the NotRequired
clause is not respected, the following will error with a TypeMisMatch error, and it should not:
parent = {"not_required": 3, "child": {"key_a": 1, "key_b": "2"}}
ParentType(parent)
Incorrect parameter: `{'child': {'key_a': 1,
'key_b': '2'},
'not_required': 3}`
required: {'child': <strongtyping.strong_typing.MatchTypedDict object at 0x7f169c29eb90>, 'not_required': typing_extensions.NotRequired[int]}
Traceback (most recent call last):
File "/f/src/script.py", line 24, in <module>
ParentType(parent)
File "/f/.local/lib/python3.10/site-packages/strongtyping/strong_typing.py", line 183, in __call__
raise self.excep_raise(self.create_error_msg(arguments))
strongtyping.strong_typing_utils.TypeMisMatch
It is an edge case, but I thought it was worth reporting it because NotRequired
brings a lot for typing.
Thanks for your work!