2
2
import inspect
3
3
import re
4
4
from contextlib import contextmanager
5
- from functools import singledispatch
5
+ from functools import partial , singledispatch
6
6
from inspect import Parameter
7
7
from itertools import count
8
8
from textwrap import indent
35
35
from .helpers import vuepress_slugify
36
36
37
37
_descr_role_re = re .compile (
38
- r"{(?P<name>\w+?)}`(?:(?P<text>[^{}]+?) <)?(?P<content>[\w\.]+)(?(text)>)`"
38
+ r"{(?P<name>\w+?)}`(?:(?P<text>[^{}]+?) <)?(?P<content>[\w\.\+\- ]+)(?(text)>)`"
39
39
)
40
40
41
41
@@ -178,6 +178,7 @@ def __init__(
178
178
self .add_heading_id = add_heading_id
179
179
self .indent_size = config ["markdown_indent_size" ]
180
180
self .builder = builder
181
+ self .is_auto_args : bool = False
181
182
self ._builder : list [str ] = []
182
183
self ._indent : int = 0
183
184
self ._level : int = 1
@@ -262,7 +263,7 @@ def _replace_descr(self, match: Match[str]) -> str:
262
263
matchtext = match .group ()
263
264
manager = self .current_module .manager
264
265
if name in ("version" , "ver" ):
265
- return get_version_badge (role [ " content" ] )
266
+ return get_version_badge (content )
266
267
elif name == "ref" :
267
268
if ":" in content :
268
269
modulename , qualname = content .split (":" )
@@ -290,7 +291,7 @@ def _resolve_args_from_sig(
290
291
self ,
291
292
* ,
292
293
args : Optional [nodes .Args ] = None ,
293
- sig : FunctionSignature ,
294
+ sig : Optional [ FunctionSignature ] = None ,
294
295
bind_module : Module ,
295
296
) -> nodes .Args :
296
297
doc_args_dict = None
@@ -299,37 +300,45 @@ def _resolve_args_from_sig(
299
300
doc_args_dict = _args_to_dict (args )
300
301
# turn signature into Args section
301
302
new_args = nodes .Args (
302
- name = "参数" , args = [], vararg = None , kwonlyargs = [], kwarg = None # TODO: i18n
303
+ name = args .name if args else "参数" , # TODO: i18n
304
+ args = [],
305
+ vararg = None ,
306
+ kwonlyargs = [],
307
+ kwarg = None ,
303
308
)
304
- for p in sig .parameters .values ():
305
- doc_arg = None
306
- if doc_args_dict :
307
- doc_arg = doc_args_dict .get (p .name )
308
- annotation = None
309
- # doc overridden annotation or parameter annotation
310
- if doc_arg and doc_arg .annotation :
311
- annotation = bind_module .build_static_ann (
312
- ast .parse (doc_arg .annotation , mode = "eval" ).body
313
- ).get_doc_linkify (self .add_link )
314
- elif p .annotation is not Parameter .empty :
315
- annotation = p .annotation .get_doc_linkify (self .add_link )
316
- arg = nodes .ColonArg (p .name , annotation , [], "" , "" )
317
- if doc_arg :
318
- arg .descr = doc_arg .descr
319
- arg .long_descr = doc_arg .long_descr
320
- if p .kind in (Parameter .POSITIONAL_ONLY , Parameter .POSITIONAL_OR_KEYWORD ):
321
- new_args .args .append (arg )
322
- elif p .kind is Parameter .VAR_POSITIONAL :
323
- new_args .vararg = arg
324
- elif p .kind is Parameter .KEYWORD_ONLY :
325
- new_args .kwonlyargs .append (arg )
326
- elif p .kind is Parameter .VAR_KEYWORD :
327
- new_args .kwarg = arg
309
+ if sig :
310
+ for p in sig .parameters .values ():
311
+ doc_arg = None
312
+ if doc_args_dict :
313
+ doc_arg = doc_args_dict .get (p .name )
314
+ annotation = None
315
+ # doc overridden annotation or parameter annotation
316
+ if doc_arg and doc_arg .annotation :
317
+ annotation = bind_module .build_static_ann (
318
+ ast .parse (doc_arg .annotation , mode = "eval" ).body
319
+ ).get_doc_linkify (self .add_link )
320
+ elif p .annotation is not Parameter .empty :
321
+ annotation = p .annotation .get_doc_linkify (self .add_link )
322
+ arg = nodes .ColonArg (p .name , annotation , [], "" , "" )
323
+ if doc_arg :
324
+ arg .descr = doc_arg .descr
325
+ arg .long_descr = doc_arg .long_descr
326
+ if p .kind in (
327
+ Parameter .POSITIONAL_ONLY ,
328
+ Parameter .POSITIONAL_OR_KEYWORD ,
329
+ ):
330
+ new_args .args .append (arg )
331
+ elif p .kind is Parameter .VAR_POSITIONAL :
332
+ new_args .vararg = arg
333
+ elif p .kind is Parameter .KEYWORD_ONLY :
334
+ new_args .kwonlyargs .append (arg )
335
+ elif p .kind is Parameter .VAR_KEYWORD :
336
+ new_args .kwarg = arg
328
337
if doc_args_dict :
329
338
# the docstring arg doesn't match signature
330
339
# we think these arguments are keyword-only
331
340
for name in doc_args_dict :
332
- if name in sig .parameters : # keep order
341
+ if sig and name in sig .parameters : # keep order
333
342
continue
334
343
doc_arg = doc_args_dict [name ]
335
344
annotation = None
@@ -348,10 +357,12 @@ def _resolve_rets_from_sig(
348
357
self ,
349
358
* ,
350
359
rets : Optional [nodes .Returns ] = None ,
351
- sig : FunctionSignature ,
360
+ sig : Optional [ FunctionSignature ] = None ,
352
361
bind_module : Module ,
353
362
) -> nodes .Returns :
354
- new_rets = nodes .Returns (name = "返回" , version = None ) # TODO: i18n
363
+ new_rets = nodes .Returns (
364
+ name = rets .name if rets else "返回" , version = None # TODO: i18n
365
+ )
355
366
new_rets .value = nodes .ColonArg (None , None , [], "" , "" )
356
367
annotation = None
357
368
if rets :
@@ -368,16 +379,14 @@ def _resolve_rets_from_sig(
368
379
long_descr = long_descr .strip ()
369
380
new_rets .value .descr = descr
370
381
new_rets .value .long_descr = long_descr
371
- if annotation is None and sig .return_annotation is not Parameter .empty :
382
+ if annotation is None and sig and sig .return_annotation is not Parameter .empty :
372
383
annotation = sig .return_annotation .get_doc_linkify (self .add_link )
373
384
elif annotation is None :
374
385
annotation = "untyped"
375
386
new_rets .value .annotation = annotation
376
387
return new_rets
377
388
378
389
def _resolve_doc_from_sig (self , dobj : Union [Function , Class ]) -> None :
379
- if not dobj .signature :
380
- return None
381
390
if not dobj .doctree :
382
391
dobj .doctree = nodes .Docstring (
383
392
roles = [], annotation = None , descr = "" , long_descr = "" , sections = []
@@ -507,19 +516,23 @@ def visit_Function(self, dobj: Function) -> None:
507
516
dobj .doctree .sections .insert (0 , overloads ) # type: ignore # mypy
508
517
else :
509
518
self ._resolve_doc_from_sig (dobj )
519
+ self .is_auto_args = bool (not dobj .signature )
510
520
if dobj .doctree :
511
521
self .newline ()
512
522
self .visit_Docstring (dobj .doctree )
523
+ self .is_auto_args = False
513
524
514
525
def visit_Class (self , dobj : Class ) -> None :
515
526
self .title (dobj )
516
527
if dobj .doctree :
517
528
# remove before resolve
518
529
_extract_inlinevalue (dobj .doctree )
519
530
self ._resolve_doc_from_sig (dobj )
531
+ self .is_auto_args = bool (not dobj .signature )
520
532
if dobj .doctree :
521
533
self .newline ()
522
534
self .visit_Docstring (dobj .doctree )
535
+ self .is_auto_args = False
523
536
ctx = self .block () if isenumclass (dobj .pyobj ) else self .heading ()
524
537
with ctx :
525
538
for member in self .member_iterator .iter_class (dobj ):
@@ -552,8 +565,17 @@ def visit_Docstring(
552
565
self .visit (section )
553
566
554
567
def visit_ColonArg (
555
- self , dsobj : nodes .ColonArg , isvar : bool = False , iskw : bool = False
568
+ self ,
569
+ dsobj : nodes .ColonArg ,
570
+ * ,
571
+ isvar : bool = False ,
572
+ iskw : bool = False ,
573
+ link_ann : bool = False ,
556
574
) -> None :
575
+ if link_ann and dsobj .annotation :
576
+ dsobj .annotation = self .current_module .build_static_ann (
577
+ ast .parse (dsobj .annotation , mode = "eval" ).body
578
+ ).get_doc_linkify (self .add_link )
557
579
self .fill ("- " )
558
580
if dsobj .name :
559
581
with self .delimit ("`" , "`" ):
@@ -582,6 +604,7 @@ def visit_Text(self, dsobj: nodes.Text) -> None:
582
604
self .write (dsobj .value )
583
605
584
606
def visit_Args (self , dsobj : nodes .Args ) -> None :
607
+ # NOTE: only function Args and Returns can have link (auto resolved)
585
608
self .fill (f"- **{ dsobj .name } **" )
586
609
rendered = False
587
610
with self .block ():
@@ -602,7 +625,10 @@ def visit_Args(self, dsobj: nodes.Args) -> None:
602
625
self .newline ()
603
626
self .visit_ColonArg (dsobj .kwarg , iskw = True )
604
627
if not rendered :
605
- self .newline ("empty" )
628
+ if self .is_auto_args :
629
+ self .newline ("auto" )
630
+ else :
631
+ self .newline ("empty" )
606
632
607
633
def visit_Overloads (self , dsobj : nodes .Overloads ) -> None :
608
634
self .fill ("- **重载**" ) # TODO: i18n
@@ -633,9 +659,11 @@ def visit_Raises(self, dsobj: nodes.Raises) -> None:
633
659
with self .block ():
634
660
for arg in dsobj .args :
635
661
self .newline ()
636
- self .visit_ColonArg (arg )
662
+ self .visit_ColonArg (arg , link_ann = True )
637
663
638
- def _visit_return_like (self , dsobj : Union [nodes .Returns , nodes .Yields ]) -> None :
664
+ def _visit_return_like (
665
+ self , dsobj : Union [nodes .Returns , nodes .Yields ], link_ann : bool = False
666
+ ) -> None :
639
667
self .fill (f"- **{ dsobj .name } **" )
640
668
if dsobj .version :
641
669
self .write (" " )
@@ -645,9 +673,10 @@ def _visit_return_like(self, dsobj: Union[nodes.Returns, nodes.Yields]) -> None:
645
673
self .newline (dsobj .value )
646
674
else :
647
675
self .newline ()
648
- self .visit_ColonArg (dsobj .value )
676
+ self .visit_ColonArg (dsobj .value , link_ann = link_ann )
649
677
650
- visit_Returns = visit_Yields = _visit_return_like
678
+ visit_Returns = _visit_return_like
679
+ visit_Yields = partial (_visit_return_like , link_ann = True )
651
680
652
681
def visit_Require (self , dsobj : nodes .Require ) -> None :
653
682
self .fill (f"- **{ dsobj .name } **" )
0 commit comments