[New-bugs-announce] [issue44919] TypedDict subtypes ignore any other metaclasses in 3.9+
Nikita Sobolev
report at bugs.python.org
Sun Aug 15 08:23:36 EDT 2021
New submission from Nikita Sobolev <mail at 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 <report at bugs.python.org>
<https://bugs.python.org/issue44919>
_______________________________________
More information about the New-bugs-announce
mailing list