New submission from Nikita Sobolev <m...@sobolevn.me>:
Some context. I have a `User` class defined as a `TypedDict`: ```python from typing import TypedDict class User(TypedDict): name: str registered: bool ``` Now, I want to check if some `dict` is an instance of `User` like so: `isinstance(my_dict, User)`. But, I can't. Because it raises `TypeError('TypedDict does not support instance and class checks')`. Ok. Let's change `__instancecheck__` method then. We can only do this in a metaclass: ```python from typing import _TypedDictMeta class UserDictMeta(_TypedDictMeta): def __instancecheck__(cls, arg: object) -> bool: return ( isinstance(arg, dict) and isinstance(arg.get('name'), str) and isinstance(arg.get('registered'), bool) ) class UserDict(User, metaclass=UserDictMeta): ... ``` It looks like it should work. It used to work like this in Python3.7 and Python3.8. But since Python3.9 it does not work. Let's try to debug what happens: ```python print(type(UserDict)) # <class 'typing._TypedDictMeta'> print(UserDict.__instancecheck__(UserDict, {})) # TypeError: TypedDict does not support instance and class checks ``` It looks like my custom `UserDictMeta` is completely ignored. And I cannot change how `__instancecheck__` behaves. I suspect that the reason is in these 2 lines: https://github.com/python/cpython/blob/ad0a8a9c629a7a0fa306fbdf019be63c701a8028/Lib/typing.py#L2384-L2385 What's the most unclear in this behavior is that it does not match regular Python subclass patterns. Simplified example of the same behavior, using only primite types: ```python class FirstMeta(type): def __instancecheck__(cls, arg: object) -> bool: raise TypeError('You cannot use this type in isinstance() call') class First(object, metaclass=FirstMeta): ... # User space: class MyClass(First): # this looks like a user-define TypedDict subclass ... class MySubClassMeta(FirstMeta): def __instancecheck__(cls, arg: object) -> bool: return True # just an override example class MySubClass(MyClass, metaclass=MySubClassMeta): ... print(isinstance(1, MySubClass)) # True print(isinstance(1, MyClass)) # TypeError ``` As you can see our `MySubClassMeta` works perfectly fine this way. I suppose that this is a bug in `TypedDict`, not a desired behavior. Am I correct? ---------- components: Library (Lib) messages: 399615 nosy: sobolevn priority: normal severity: normal status: open title: TypedDict subtypes ignore any other metaclasses in 3.9+ type: behavior versions: Python 3.10, Python 3.11, Python 3.9 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue44919> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com