Currently, when retrieving TypedDict.__annotations__
with a base that has total=False
, you need to compare with __optional_keys__
to ensure the keys are not required. Since total=False
means that keys are not required by default, does it make sense to annotate them as such beforehand? Otherwise __annotations__
ends up with keys that are annotated as NotRequired
and Required
as well as keys without NotRequired
from total=False
, which seems odd?
Semantically total=False
means the same as annotating every key with NotRequired
.
Are you suggesting that __annotations__
should be transformed automatically to add NotRequired[]
to every key in that case? I would oppose that; in my experience, it’s generally better to keep processing of things like __annotations__
to a minimum at runtime. That way, it’s easier for any tools that want to know exactly what the user wrote. For example, if the runtime has a bug and puts the wrong thing in __annotations__
, such tools might not know what to do any more.
In that case, would you expect get_type_hints
to return the total=False keys annotated correctly?
I think there’s a difference there between what I expect and what I want. I expect get_type_hints()
do all kinds of weird things to the types (turning None into NoneType?). I want it to not do that. Therefore, I have learned to avoid using it.
My main concern now is that if we change get_type_hints()
, that’s likely to break some users. Those users might then get upset at me as I’m one of the maintainers of typing.py
, and I don’t like it when users get upset at me. Also, if we make get_type_hints()
more complicated, that makes it harder to maintain in the future.
Come to think of it, is there a formal reason for why None becomes type(None)? I went sleuthing around for the commit history and didn’t find anything definitive for this behaviour.
None
is such a common annotation we made an exception for it in the syntax, letting users write x: None
instead of x: NoneType
.
But we assumed that this irregularity would be annoying when inspecting annotations at runtime – it’d be more consistent if the runtime types to always be instances of type
. I think we were wrong there, and runtime introspectors are more likely to be surprised than delighted by this choice. But it’s too late to change.
Currently, when retrieving annotations, I’m finding it necessary to cross-reference with __optional_keys__
to ensure keys aren’t considered required. The challenge here is that it results in a mix of keys annotated as NotRequired, Required, and those without NotRequired from total=False
.