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.