@@ -35,7 +35,7 @@ def foo(bar: int, baz=True):
35
35
36
36
37
37
import inspect
38
- from typing import Any , Callable , Iterable
38
+ from typing import Any , Callable , Iterable , Protocol , Optional , Dict , cast
39
39
40
40
from qutebrowser .utils import qtutils
41
41
from qutebrowser .commands import command , cmdexc
@@ -90,7 +90,21 @@ def check_exclusive(flags: Iterable[bool], names: Iterable[str]) -> None:
90
90
raise CommandError ("Only one of {} can be given!" .format (argstr ))
91
91
92
92
93
- _CmdHandlerType = Callable [..., Any ]
93
+ _CmdHandlerFunc = Callable [..., Any ]
94
+
95
+
96
+ class _CmdHandlerType (Protocol ):
97
+
98
+ """A qutebrowser command function, which had qute_args patched on it.
99
+
100
+ Applying @cmdutils.argument to a function will patch it with a qute_args attribute.
101
+ Below, we cast the decorated function to _CmdHandlerType to make mypy aware of this.
102
+ """
103
+
104
+ qute_args : Optional [Dict [str , command .ArgInfo ]]
105
+
106
+ def __call__ (self , * args : Any , ** kwargs : Any ) -> Any :
107
+ ...
94
108
95
109
96
110
class register : # noqa: N801,N806 pylint: disable=invalid-name
@@ -118,7 +132,7 @@ def __init__(self, *,
118
132
# The arguments to pass to Command.
119
133
self ._kwargs = kwargs
120
134
121
- def __call__ (self , func : _CmdHandlerType ) -> _CmdHandlerType :
135
+ def __call__ (self , func : _CmdHandlerFunc ) -> _CmdHandlerType :
122
136
"""Register the command before running the function.
123
137
124
138
Gets called when a function should be decorated.
@@ -158,7 +172,8 @@ def __call__(self, func: _CmdHandlerType) -> _CmdHandlerType:
158
172
159
173
# This is checked by future @cmdutils.argument calls so they fail
160
174
# (as they'd be silently ignored otherwise)
161
- func .qute_args = None # type: ignore[attr-defined]
175
+ func = cast (_CmdHandlerType , func )
176
+ func .qute_args = None
162
177
163
178
return func
164
179
@@ -210,19 +225,21 @@ def __init__(self, argname: str, **kwargs: Any) -> None:
210
225
self ._argname = argname # The name of the argument to handle.
211
226
self ._kwargs = kwargs # Valid ArgInfo members.
212
227
213
- def __call__ (self , func : _CmdHandlerType ) -> _CmdHandlerType :
228
+ def __call__ (self , func : _CmdHandlerFunc ) -> _CmdHandlerType :
214
229
funcname = func .__name__
215
230
216
231
if self ._argname not in inspect .signature (func ).parameters :
217
232
raise ValueError ("{} has no argument {}!" .format (funcname ,
218
233
self ._argname ))
234
+
235
+ func = cast (_CmdHandlerType , func )
219
236
if not hasattr (func , 'qute_args' ):
220
- func .qute_args = {} # type: ignore[attr-defined]
237
+ func .qute_args = {}
221
238
elif func .qute_args is None :
222
239
raise ValueError ("@cmdutils.argument got called above (after) "
223
240
"@cmdutils.register for {}!" .format (funcname ))
224
241
225
242
arginfo = command .ArgInfo (** self ._kwargs )
226
- func .qute_args [self ._argname ] = arginfo # type: ignore[attr-defined]
243
+ func .qute_args [self ._argname ] = arginfo
227
244
228
245
return func
0 commit comments