Search code examples
pythonpython-typing

annotate a NamedTuple for storing a function and its args and kwargs


I have a system where i want to store a function along with its arguments for later invocation. I have tried:

import typing

P = typing.ParamSpec("P")
class JobPayload(typing.NamedTuple):
    fn:     typing.Callable[P, None]
    args:   P.args
    kwargs: P.kwargs

but the types of args and kwargs is not accepted. How do I type this correctly?


Solution

  • Your code is invalid:

    [P.args and P.kwargs] can only be used as the annotated types for *args and **kwargs, accessed from a ParamSpec already in scope.

    — Generics § The components of a ParamSpec / Valid use locations | Python typing specification

    As noted by @wjandrea, Mypy doesn't point out any problems. This is due to a known bug, however.

    The best you can do is to use a TypeVarTuple to represent the type of the parameters. The downsides are that their names are lost, and you can't have keyword-only arguments.

    (playgrounds: Mypy, Pyright)

    from collections.abc import Callable
    from typing import NamedTuple
    
    class JobPayload[*Ts](NamedTuple):
        fn:   Callable[[*Ts], None]
        args: tuple[*Ts]
    
    def f(a: int, /, b: str, c: float) -> None: ...
    
    payload = JobPayload(f, (42, 'lorem'))  # error