Skip to content

mypy doesn't understand that *args: P.args implies that args is a tuple#19663

@randolf-scholz

Description

@randolf-scholz
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.

Footnotes

  1. For instance, pyright says as_tuple(*args) is illegal. Code sample in pyright playground

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-callsFunction calls, *args, **kwargs, defaultstopic-paramspecPEP 612, ParamSpec, Concatenate

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions