On Sat, 2021-02-27 at 09:29 -0800, David Foster wrote:
On 2/26/21 7:43 PM, Paul Bryan wrote:
Q1. Though the intent is to use in TypedDict, is it necessary to
preclude its use elsewhere by making its use outside of TypedDict an error?

Well, what would it mean to have Required[] somewhere else? For example:

     def identity(x: Required[int]) -> int: ...

A type checker is going to have to apply *some* meaning to Required[]
used in a parameter type. Should it be ignored? Feels pretty strongly
like an error to me that should be flagged.

Is there a useful reason to allow Required[] in other positions that I'm
not thinking of?

My thought is admittedly pretty weak at this point: dynamically defining a as required prior to its use in TypeDict. Is the following valid?

TD = TypedDict("TD", {"a": Required[int] if some_condition else NotRequired[int], "b": str}, total=False)

If so, why not the following?

SomeType = Required[int] if some_condition else NotRequired[int]
TD = TypedDict("TD", {"a": SomeType, "b": str}, total=False)


Q2. Can the PEP explicitly address how Required[...] and
NotRequired[...] will manifest in TypedDict state? Namely, its effect on
__required_keys__ and __optional_keys__?

Sure.

Required[] applied to a key means it will definitely appear in
__required_keys__ at runtime. Similarly NotRequired[] applied to a key
means it will definitely appear in __optional_keys__.

Neither  __required_keys__ nor __optional_keys__ are mentioned in PEP
589 (TypedDict) [1] or  the "typing" module documentation [2] but I
think an earlier post to the list suggested that was an oversight and
that these runtime-available keys should be documented (presumably in
one of those locations) as well.

[1]: https://www.python.org/dev/peps/pep-0589/
[2]: https://docs.python.org/3/library/typing.html#typing.TypedDict

I'll create a PR to update [2].

I wonder if it would be useful to ban confusing combinations of both
Required[] and NotRequired[] at the same time, like:

     class Movie(TypedDict):
         year: Required[NotRequired[...]]  # um; error?; does Required[]
win?

The options that make sense to me:

1. Combining them is an error.
2. Outer always wins.

I lean toward option 1, as I can't think of a good reason they might wrap each other.

Q3. How will get_type_hints(...), get_options(...) and get_args(...)
behave with TypedDicts (and their __annotations__ values) where keys are
explicitly marked Required[...] or NotRequired[...]?

Good question. Presumably they would became similarly to how they treat
other type qualifiers like Final[] and Annotated[] (whatever that
behavior is), but I'll do some further research/thinking here.

Suggestions:

>>> TD = TypedDict("TD", {"a": Required[int]}, total=False)
>>> get_type_hints(TD)
{'a': typing.Required[int]}
>>> a = get_type_hints(TD)["a"]
>>> get_origin(a)
typing.Required
>>> get_args(a)
(<class 'int'>,)

Paul