From a0bbbf2033c6b4eab480c53e6cbb0fd2d737badd Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 11 Mar 2022 10:28:42 +0100 Subject: [PATCH] correctly annotate return type of @command(cls=XYZ) --- CHANGES.rst | 2 ++ src/click/decorators.py | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 440589a55..866231642 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -43,6 +43,8 @@ Version 8.1.0 - It's possible to pass a list of ``params`` to ``@command``. Any params defined with decorators are appended to the passed params. :issue:`2131`. +- ``@command`` decorator is annotated as returning the correct type if + a ``cls`` argument is used. :issue:`2211` Version 8.0.4 diff --git a/src/click/decorators.py b/src/click/decorators.py index d7b172422..05d133443 100644 --- a/src/click/decorators.py +++ b/src/click/decorators.py @@ -121,19 +121,38 @@ def new_func(*args, **kwargs): # type: ignore return decorator +CmdType = t.TypeVar("CmdType", bound=Command) + + +@t.overload +def command( + name: t.Optional[str] = None, + cls: t.Type[CmdType] = ..., + **attrs: t.Any, +) -> t.Callable[..., CmdType]: + ... + + @t.overload def command( name: t.Optional[str] = None, - cls: t.Optional[t.Type[Command]] = None, **attrs: t.Any, -) -> t.Callable[[F], Command]: +) -> t.Callable[..., Command]: + ... + + +@t.overload +def command( + name: t.Callable, + cls: t.Type[CmdType] = ..., + **attrs: t.Any, +) -> CmdType: ... @t.overload def command( name: t.Callable, - cls: t.Optional[t.Type[Command]] = None, **attrs: t.Any, ) -> Command: ... @@ -143,7 +162,7 @@ def command( name: t.Union[str, t.Callable, None] = None, cls: t.Optional[t.Type[Command]] = None, **attrs: t.Any, -) -> t.Union[Command, t.Callable[[F], Command]]: +) -> t.Union[Command, t.Callable[..., Command]]: r"""Creates a new :class:`Command` and uses the decorated function as callback. This will also automatically attach all decorated :func:`option`\s and :func:`argument`\s as parameters to the command.