What is the correct way to add type hints to the following function?
from typing import Callable
def format_callback(f: Callable) -> Callable:
"""Function to wrap a function to use as a click callback.
Taken from https://stackoverflow.com/a/42110044/8056572
"""
return lambda _, __, x: f(x)
Now mypy
is complaining with Missing type parameters for generic type "Callable"
The code needs to be compatible with both Python 3.9 and 3.10. I can use typing_extensions
if needed.
Edit:
The following passes mypy
but has too many Any
's for my taste. Is there a better way?
from typing import Any
from typing import Callable
import click
def format_callback(f: Callable[[Any], Any]) -> Callable[[click.Context, dict[str, Any], Any], Any]:
"""Function to wrap a function to use as a click callback.
Taken from https://stackoverflow.com/a/42110044/8056572
"""
return lambda _, __, x: f(x)
Without looking at click
, the immediate fix you can do is to provide type variables that match f(x)
:
from typing import Any, Callable, TypeVar
import click
ArgT = TypeVar("ArgT")
ReturnT = TypeVar("ReturnT")
def format_callback(
f: Callable[[ArgT], ReturnT]
) -> Callable[[click.Context, dict[str, Any], ArgT], ReturnT]:
return lambda _, __, x: f(x)
This will guard you against bad typing in the internal body of format_callback
.
A brief scan of click
seems to indicate that you want to pass the return value of format_callback
to one of the following class constructors or their subclass constructors:
click.core.Parameter.__init__::callback
:
callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]]
click.core.Command.__init__::callback
callback: t.Optional[t.Callable[..., t.Any]]
Now, based on the other answer that you linked to, which passes the keyword argument callback
to @click.argument
and @click.option
, it seems like you'd actually want to use click.core.Parameter.__init__
, because the decorators' fallback classes are ArgumentClass = click.core.Argument
and OptionClass = click.core.Option
, respectively, which are both subclasses of click.Core.Parameter
. This means that the second argument to the return Callable
type cannot be dict[str, Any]
, according to the type annotation for click.core.Parameter.__init__::callback
. Then, you really should have this instead:
def format_callback(
f: Callable[[ArgT], ReturnT]
) -> Callable[[click.Context, click.Parameter, ArgT], ReturnT]:
return lambda _, __, x: f(x)
Since you're discarding click.Context
and click.Parameter
as _, __
in your lambda
, providing these are only for documentation purposes, of course. They could easily be object, object
instead.