PEP-589 TypedDict inheritance rules and typing.Literal / PEP-586
![](https://secure.gravatar.com/avatar/a1240953d48ea069b77d5f62036bf7ca.jpg?s=120&d=mm&r=g)
Note: this was originally posted on the Discourse forum (https://discuss.python.org/t/7721), but it was recommended that I post here instead. In PEP-589: “Inheritance”, it is stated:
Changing a field type of a parent TypedDict class in a subclass is not allowed.
However, this restriction seems perhaps too restrictive in the presence of typing.Literal and PEP-586. Consider a situation like the following, which might describe some polymorphic data returned from a web API: from typing import Literal, TypedDict # Assume these all have several other fields class BaseDatum(TypedDict): id: str datumType: str class Thing(BaseDatum): datumType: Literal["thing"] class Widget(BaseDatum): datumType: Literal["widget"] This seems like a reasonable thing that someone might want to do, especially in a context where you can’t use something like Marshmallow for runtime validation & deserialization (don’t want performance overhead, restricted from using 3rd-party dependencies, etc). However, in the above example, MyPy emits:
tmp1.py:10: error: Overwriting TypedDict field "datumType" while extending tmp1.py:13: error: Overwriting TypedDict field "datumType" while extending Found 2 errors in 1 file (checked 1 source file)
Typically, Literal["widget"] is considered a subclass of str, as in: from typing import Literal x: Literal["hello"] = "hello" y: str = x It appears that the MyPy devs faithfully honored the restriction on changing type that is stated in PEP-589, but I think in this specific case the restriction is excessive. Should there be a revision to the TypedDict specification to allow this particular case? For that matter, why shouldn’t TypedDict members be covariant in general? Or is there a good reason why the restriction is what it is?
![](https://secure.gravatar.com/avatar/57da4d2e2a527026baaaab35e6872fa5.jpg?s=120&d=mm&r=g)
El vie, 19 mar 2021 a las 12:42, Greg Werbin (<outthere@me.gregwerbin.com>) escribió:
Note: this was originally posted on the Discourse forum ( https://discuss.python.org/t/7721), but it was recommended that I post here instead.
In PEP-589: “Inheritance”, it is stated:
Changing a field type of a parent TypedDict class in a subclass is not allowed.
However, this restriction seems perhaps too restrictive in the presence of typing.Literal and PEP-586.
Consider a situation like the following, which might describe some polymorphic data returned from a web API:
from typing import Literal, TypedDict
# Assume these all have several other fields
class BaseDatum(TypedDict): id: str datumType: str
class Thing(BaseDatum): datumType: Literal["thing"]
class Widget(BaseDatum): datumType: Literal["widget"]
This seems like a reasonable thing that someone might want to do, especially in a context where you can’t use something like Marshmallow for runtime validation & deserialization (don’t want performance overhead, restricted from using 3rd-party dependencies, etc).
However, in the above example, MyPy emits:
tmp1.py:10: error: Overwriting TypedDict field "datumType" while extending tmp1.py:13: error: Overwriting TypedDict field "datumType" while extending Found 2 errors in 1 file (checked 1 source file)
Typically, Literal["widget"] is considered a subclass of str, as in:
from typing import Literal x: Literal["hello"] = "hello" y: str = x
It appears that the MyPy devs faithfully honored the restriction on changing type that is stated in PEP-589, but I think in this specific case the restriction is excessive.
Should there be a revision to the TypedDict specification to allow this particular case? For that matter, why shouldn’t TypedDict members be covariant in general? Or is there a good reason why the restriction is what it is?
Changing the type in a child is unsafe because TypedDicts are mutable: def f(datum: BaseDatum): datum["datumType"] = "some string" w: Widget f(w) assert w["datumType"] == "widget" # boom We could get around that if we had a notion of an immutable TypedDict, but that's not currently a part of the type system. We could add something like `class BaseDatum(TypedDict, immutable=True)` to disallow modifications; this would make it safe to allow covariance in child classes.
_______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: jelle.zijlstra@gmail.com
![](https://secure.gravatar.com/avatar/a1240953d48ea069b77d5f62036bf7ca.jpg?s=120&d=mm&r=g)
I see, that makes sense. Maybe, in addition to or instead of the immutable=True (or frozen=True) kwarg, we should have TypedMapping or TypedFrozenMap, as part of (or in addition to) the "frozenmap" proposed in PEP-603, "Adding a frozenmap type to collections" (https://www.python.org/dev/peps/pep-0603/).
participants (2)
-
Greg Werbin
-
Jelle Zijlstra