12
12
import re
13
13
import sys
14
14
import tokenize
15
+ from inspect import Signature
15
16
from token import NAME , NEWLINE , INDENT , DEDENT , NUMBER , OP , STRING
16
17
from tokenize import COMMENT , NL
17
18
from typing import Any , Dict , List , Optional , Tuple
18
19
19
20
from sphinx .pycode .ast import ast # for py37 or older
20
21
from sphinx .pycode .ast import parse , unparse
22
+ from sphinx .util .inspect import signature_from_ast
21
23
22
24
23
25
comment_re = re .compile ('^\\ s*#: ?(.*)\r ?\n ?$' )
@@ -232,8 +234,10 @@ def __init__(self, buffers: List[str], encoding: str) -> None:
232
234
self .previous = None # type: ast.AST
233
235
self .deforders = {} # type: Dict[str, int]
234
236
self .finals = [] # type: List[str]
237
+ self .overloads = {} # type: Dict[str, List[Signature]]
235
238
self .typing = None # type: str
236
239
self .typing_final = None # type: str
240
+ self .typing_overload = None # type: str
237
241
super ().__init__ ()
238
242
239
243
def get_qualname_for (self , name : str ) -> Optional [List [str ]]:
@@ -257,6 +261,12 @@ def add_final_entry(self, name: str) -> None:
257
261
if qualname :
258
262
self .finals .append ("." .join (qualname ))
259
263
264
+ def add_overload_entry (self , func : ast .FunctionDef ) -> None :
265
+ qualname = self .get_qualname_for (func .name )
266
+ if qualname :
267
+ overloads = self .overloads .setdefault ("." .join (qualname ), [])
268
+ overloads .append (signature_from_ast (func ))
269
+
260
270
def add_variable_comment (self , name : str , comment : str ) -> None :
261
271
qualname = self .get_qualname_for (name )
262
272
if qualname :
@@ -285,6 +295,22 @@ def is_final(self, decorators: List[ast.expr]) -> bool:
285
295
286
296
return False
287
297
298
+ def is_overload (self , decorators : List [ast .expr ]) -> bool :
299
+ overload = []
300
+ if self .typing :
301
+ overload .append ('%s.overload' % self .typing )
302
+ if self .typing_overload :
303
+ overload .append (self .typing_overload )
304
+
305
+ for decorator in decorators :
306
+ try :
307
+ if unparse (decorator ) in overload :
308
+ return True
309
+ except NotImplementedError :
310
+ pass
311
+
312
+ return False
313
+
288
314
def get_self (self ) -> ast .arg :
289
315
"""Returns the name of first argument if in function."""
290
316
if self .current_function and self .current_function .args .args :
@@ -310,6 +336,8 @@ def visit_Import(self, node: ast.Import) -> None:
310
336
self .typing = name .asname or name .name
311
337
elif name .name == 'typing.final' :
312
338
self .typing_final = name .asname or name .name
339
+ elif name .name == 'typing.overload' :
340
+ self .typing_overload = name .asname or name .name
313
341
314
342
def visit_ImportFrom (self , node : ast .ImportFrom ) -> None :
315
343
"""Handles Import node and record it to definition orders."""
@@ -318,6 +346,8 @@ def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
318
346
319
347
if node .module == 'typing' and name .name == 'final' :
320
348
self .typing_final = name .asname or name .name
349
+ elif node .module == 'typing' and name .name == 'overload' :
350
+ self .typing_overload = name .asname or name .name
321
351
322
352
def visit_Assign (self , node : ast .Assign ) -> None :
323
353
"""Handles Assign node and pick up a variable comment."""
@@ -417,6 +447,8 @@ def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
417
447
self .add_entry (node .name ) # should be called before setting self.current_function
418
448
if self .is_final (node .decorator_list ):
419
449
self .add_final_entry (node .name )
450
+ if self .is_overload (node .decorator_list ):
451
+ self .add_overload_entry (node )
420
452
self .context .append (node .name )
421
453
self .current_function = node
422
454
for child in node .body :
@@ -518,6 +550,7 @@ def __init__(self, code: str, encoding: str = 'utf-8') -> None:
518
550
self .deforders = {} # type: Dict[str, int]
519
551
self .definitions = {} # type: Dict[str, Tuple[str, int, int]]
520
552
self .finals = [] # type: List[str]
553
+ self .overloads = {} # type: Dict[str, List[Signature]]
521
554
522
555
def parse (self ) -> None :
523
556
"""Parse the source code."""
@@ -533,6 +566,7 @@ def parse_comments(self) -> None:
533
566
self .comments = picker .comments
534
567
self .deforders = picker .deforders
535
568
self .finals = picker .finals
569
+ self .overloads = picker .overloads
536
570
537
571
def parse_definition (self ) -> None :
538
572
"""Parse the location of definitions from the code."""
0 commit comments