assert get_origin(P.args) is P
    """
    if isinstance(tp, _AnnotatedAlias):
        return Annotated
    if isinstance(tp, (_BaseGenericAlias, GenericAlias,
                       ParamSpecArgs, ParamSpecKwargs)):
        return tp.__origin__
    if tp is Generic:
        return Generic
    if isinstance(tp, types.UnionType):
        return types.UnionType
    return None
def get_args(tp):
    """Get type arguments with all substitutions performed.
    For unions, basic simplifications used by Union constructor are performed.
    Examples::
        assert get_args(Dict[str, int]) == (str, int)
        assert get_args(int) == ()
        assert get_args(Union[int, Union[T, int], str][int]) == (int, str)
        assert get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
        assert get_args(Callable[[], T][int]) == ([], int)
    """
    if isinstance(tp, _AnnotatedAlias):
        return (tp.__origin__,) + tp.__metadata__
    if isinstance(tp, (_GenericAlias, GenericAlias)):
        res = tp.__args__
        if _should_unflatten_callable_args(tp, res):
            res = (list(res[:-1]), res[-1])
        return res
    if isinstance(tp, types.UnionType):
        return tp.__args__
    return ()
def is_typeddict(tp):
    """Check if an annotation is a TypedDict class.
    For example::
        class Film(TypedDict):
            title: str
            year: int
        is_typeddict(Film)              # => True
        is_typeddict(Union[list, str])  # => False