8
8
9
9
import contextlib
10
10
import io
11
+ import keyword
11
12
import re
12
13
import tokenize
13
14
from typing import Any , Final , MutableMapping , MutableSequence , NamedTuple , Sequence , Tuple
14
15
from typing_extensions import TypeAlias as _TypeAlias
15
16
17
+ import mypy .util
18
+
16
19
# Type alias for signatures strings in format ('func_name', '(arg, opt_arg=False)').
17
20
Sig : _TypeAlias = Tuple [str , str ]
18
21
@@ -35,12 +38,16 @@ class ArgSig:
35
38
36
39
def __init__ (self , name : str , type : str | None = None , default : bool = False ):
37
40
self .name = name
38
- if type and not is_valid_type (type ):
39
- raise ValueError ("Invalid type: " + type )
40
41
self .type = type
41
42
# Does this argument have a default value?
42
43
self .default = default
43
44
45
+ def is_star_arg (self ) -> bool :
46
+ return self .name .startswith ("*" ) and not self .name .startswith ("**" )
47
+
48
+ def is_star_kwarg (self ) -> bool :
49
+ return self .name .startswith ("**" )
50
+
44
51
def __repr__ (self ) -> str :
45
52
return "ArgSig(name={}, type={}, default={})" .format (
46
53
repr (self .name ), repr (self .type ), repr (self .default )
@@ -59,7 +66,80 @@ def __eq__(self, other: Any) -> bool:
59
66
class FunctionSig (NamedTuple ):
60
67
name : str
61
68
args : list [ArgSig ]
62
- ret_type : str
69
+ ret_type : str | None
70
+
71
+ def is_special_method (self ) -> bool :
72
+ return bool (
73
+ self .name .startswith ("__" )
74
+ and self .name .endswith ("__" )
75
+ and self .args
76
+ and self .args [0 ].name in ("self" , "cls" )
77
+ )
78
+
79
+ def has_catchall_args (self ) -> bool :
80
+ """Return if this signature has catchall args: (*args, **kwargs)"""
81
+ if self .args and self .args [0 ].name in ("self" , "cls" ):
82
+ args = self .args [1 :]
83
+ else :
84
+ args = self .args
85
+ return (
86
+ len (args ) == 2
87
+ and all (a .type in (None , "Any" , "typing.Any" ) for a in args )
88
+ and args [0 ].is_star_arg ()
89
+ and args [1 ].is_star_kwarg ()
90
+ )
91
+
92
+ def is_identity (self ) -> bool :
93
+ """Return if this signature is the catchall identity: (*args, **kwargs) -> Any"""
94
+ return self .has_catchall_args () and self .ret_type in (None , "Any" , "typing.Any" )
95
+
96
+ def format_sig (
97
+ self ,
98
+ indent : str = "" ,
99
+ is_async : bool = False ,
100
+ any_val : str | None = None ,
101
+ docstring : str | None = None ,
102
+ ) -> str :
103
+ args : list [str ] = []
104
+ for arg in self .args :
105
+ arg_def = arg .name
106
+
107
+ if arg_def in keyword .kwlist :
108
+ arg_def = "_" + arg_def
109
+
110
+ if (
111
+ arg .type is None
112
+ and any_val is not None
113
+ and arg .name not in ("self" , "cls" )
114
+ and not arg .name .startswith ("*" )
115
+ ):
116
+ arg_type : str | None = any_val
117
+ else :
118
+ arg_type = arg .type
119
+ if arg_type :
120
+ arg_def += ": " + arg_type
121
+ if arg .default :
122
+ arg_def += " = ..."
123
+
124
+ elif arg .default :
125
+ arg_def += "=..."
126
+
127
+ args .append (arg_def )
128
+
129
+ retfield = ""
130
+ ret_type = self .ret_type if self .ret_type else any_val
131
+ if ret_type is not None :
132
+ retfield = " -> " + ret_type
133
+
134
+ prefix = "async " if is_async else ""
135
+ sig = "{indent}{prefix}def {name}({args}){ret}:" .format (
136
+ indent = indent , prefix = prefix , name = self .name , args = ", " .join (args ), ret = retfield
137
+ )
138
+ if docstring :
139
+ suffix = f"\n { indent } { mypy .util .quote_docstring (docstring )} "
140
+ else :
141
+ suffix = " ..."
142
+ return f"{ sig } { suffix } "
63
143
64
144
65
145
# States of the docstring parser.
@@ -176,17 +256,17 @@ def add_token(self, token: tokenize.TokenInfo) -> None:
176
256
177
257
# arg_name is empty when there are no args. e.g. func()
178
258
if self .arg_name :
179
- try :
259
+ if self .arg_type and not is_valid_type (self .arg_type ):
260
+ # wrong type, use Any
261
+ self .args .append (
262
+ ArgSig (name = self .arg_name , type = None , default = bool (self .arg_default ))
263
+ )
264
+ else :
180
265
self .args .append (
181
266
ArgSig (
182
267
name = self .arg_name , type = self .arg_type , default = bool (self .arg_default )
183
268
)
184
269
)
185
- except ValueError :
186
- # wrong type, use Any
187
- self .args .append (
188
- ArgSig (name = self .arg_name , type = None , default = bool (self .arg_default ))
189
- )
190
270
self .arg_name = ""
191
271
self .arg_type = None
192
272
self .arg_default = None
@@ -240,7 +320,7 @@ def args_kwargs(signature: FunctionSig) -> bool:
240
320
241
321
242
322
def infer_sig_from_docstring (docstr : str | None , name : str ) -> list [FunctionSig ] | None :
243
- """Convert function signature to list of TypedFunctionSig
323
+ """Convert function signature to list of FunctionSig
244
324
245
325
Look for function signatures of function in docstring. Signature is a string of
246
326
the format <function_name>(<signature>) -> <return type> or perhaps without
0 commit comments