fromtypingimportCallabledefas_tuple[*Ts](*args: *Ts) ->tuple[*Ts]: returnargsdeftuple_identity[*Ts](t: tuple[*Ts]) ->tuple[*Ts]: returntdeftuple_identity2[T: tuple](t: T) ->T: returntdeftest_paramspec[**P](
dummy: Callable[P, None], # ensure P is bound/,
*args: P.args,
**kwargs: P.kwargs,
) ->None:
reveal_type(args) # N: "P.args`-1" reveal_type( (*args,) ) # N: "builtins.tuple[P.args`-1, ...]"reveal_type( tuple(args) ) # N: "builtins.tuple[builtins.object, ...]"reveal_type(as_tuple(*args)) # N: "builtins.tuple[P.args`-1, ...]"reveal_type(tuple_identity(args)) # N: "builtins.tuple[Never, ...]"# E: [arg-type]reveal_type(tuple_identity2(args)) # N: "P.args`-1" ✅ifisinstance(args, tuple):
passelse:
reveal_type(args) # false negative [warn-unreachable]
https://mypy-play.net/?mypy=latest&python=3.12&flags=warn-unreachable&gist=3eabd8f4ee599e272934c94080f02bd8
Ideally, all the reveal_types should show the same result (or raise errors if considered misuse of ParamSpec1), and the else-branch should trigger an unreachable warning.
https://mypy-play.net/?mypy=latest&python=3.12&flags=warn-unreachable&gist=3eabd8f4ee599e272934c94080f02bd8
Ideally, all the
reveal_typesshould show the same result (or raise errors if considered misuse ofParamSpec1), and theelse-branch should trigger anunreachablewarning.Footnotes
For instance,
pyrightsaysas_tuple(*args)is illegal. Code sample in pyright playground↩