@@ -588,74 +588,100 @@ def _inject_types_to_docstring(
588588 name : str ,
589589 lines : list [str ],
590590) -> None :
591-
592591 if signature is not None :
593- for arg_name in signature .parameters :
594- annotation = type_hints .get (arg_name , None )
592+ _inject_signature (type_hints , signature , app , lines )
593+ if "return" in type_hints :
594+ _inject_rtype (type_hints , original_obj , app , what , name , lines )
595595
596- default = signature .parameters [arg_name ].default
597596
598- if arg_name .endswith ("_" ):
599- arg_name = f"{ arg_name [:- 1 ]} \\ _"
597+ def _inject_signature (
598+ type_hints : dict [str , Any ],
599+ signature : inspect .Signature ,
600+ app : Sphinx ,
601+ lines : list [str ],
602+ ) -> None :
603+ for arg_name in signature .parameters :
604+ annotation = type_hints .get (arg_name , None )
600605
601- insert_index = None
602- for at , line in enumerate (lines ):
603- if _line_is_param_line_for_arg (line , arg_name ):
604- # Get the arg_name from the doc to match up for type in case it has a star prefix.
605- # Line is in the correct format so this is guaranteed to return tuple[str, str].
606- _ , arg_name = _get_sphinx_line_keyword_and_argument (line ) # type: ignore[assignment, misc]
607- insert_index = at
608- break
609-
610- if annotation is not None and insert_index is None and app .config .always_document_param_types :
611- lines .append (f":param { arg_name } :" )
612- insert_index = len (lines )
613-
614- if insert_index is not None :
615- if annotation is None :
616- type_annotation = f":type { arg_name } : "
617- else :
618- formatted_annotation = format_annotation (annotation , app .config )
619- type_annotation = f":type { arg_name } : { formatted_annotation } "
620-
621- if app .config .typehints_defaults :
622- formatted_default = format_default (app , default , annotation is not None )
623- if formatted_default :
624- if app .config .typehints_defaults .endswith ("after" ):
625- lines [insert_index ] += formatted_default
626- else : # add to last param doc line
627- type_annotation += formatted_default
628-
629- lines .insert (insert_index , type_annotation )
630-
631- if "return" in type_hints and not inspect .isclass (original_obj ) and not inspect .isdatadescriptor (original_obj ):
632- if what == "method" and name .endswith (".__init__" ): # avoid adding a return type for data class __init__
633- return
634- formatted_annotation = format_annotation (type_hints ["return" ], app .config )
635- insert_index = len (lines )
606+ default = signature .parameters [arg_name ].default
607+
608+ if arg_name .endswith ("_" ):
609+ arg_name = f"{ arg_name [:- 1 ]} \\ _"
610+
611+ insert_index = None
636612 for at , line in enumerate (lines ):
637- if line .startswith (":rtype:" ):
638- insert_index = None
639- break
640- elif line .startswith (":return:" ) or line .startswith (":returns:" ):
641- if " -- " in line and not app .config .typehints_use_rtype :
642- insert_index = None
643- break
644- insert_index = at
645- elif line .startswith (".." ):
646- # Make sure that rtype comes before any usage or examples section
613+ if _line_is_param_line_for_arg (line , arg_name ):
614+ # Get the arg_name from the doc to match up for type in case it has a star prefix.
615+ # Line is in the correct format so this is guaranteed to return tuple[str, str].
616+ _ , arg_name = _get_sphinx_line_keyword_and_argument (line ) # type: ignore[assignment, misc]
647617 insert_index = at
648618 break
649619
650- if insert_index is not None and app .config .typehints_document_rtype :
651- if insert_index == len (lines ): # ensure that :rtype: doesn't get joined with a paragraph of text
652- lines .append ("" )
653- insert_index += 1
654- if app .config .typehints_use_rtype or insert_index == len (lines ):
655- lines .insert (insert_index , f":rtype: { formatted_annotation } " )
620+ if annotation is not None and insert_index is None and app .config .always_document_param_types :
621+ lines .append (f":param { arg_name } :" )
622+ insert_index = len (lines )
623+
624+ if insert_index is not None :
625+ if annotation is None :
626+ type_annotation = f":type { arg_name } : "
627+ else :
628+ formatted_annotation = format_annotation (annotation , app .config )
629+ type_annotation = f":type { arg_name } : { formatted_annotation } "
630+
631+ if app .config .typehints_defaults :
632+ formatted_default = format_default (app , default , annotation is not None )
633+ if formatted_default :
634+ if app .config .typehints_defaults .endswith ("after" ):
635+ lines [insert_index ] += formatted_default
636+ else : # add to last param doc line
637+ type_annotation += formatted_default
638+
639+ lines .insert (insert_index , type_annotation )
640+
641+
642+ def _inject_rtype (
643+ type_hints : dict [str , Any ],
644+ original_obj : Any ,
645+ app : Sphinx ,
646+ what : str ,
647+ name : str ,
648+ lines : list [str ],
649+ ) -> None :
650+ if inspect .isclass (original_obj ) or inspect .isdatadescriptor (original_obj ):
651+ return
652+ if what == "method" and name .endswith (".__init__" ): # avoid adding a return type for data class __init__
653+ return
654+ formatted_annotation = format_annotation (type_hints ["return" ], app .config )
655+ insert_index : int | None = len (lines )
656+ extra_newline = False
657+ for at , line in enumerate (lines ):
658+ if line .startswith (":rtype:" ):
659+ insert_index = None
660+ break
661+ if line .startswith (":return:" ) or line .startswith (":returns:" ):
662+ if " -- " in line and not app .config .typehints_use_rtype :
663+ insert_index = None
664+ break
665+ insert_index = at
666+ elif line .startswith (".." ):
667+ # Make sure that rtype comes before any usage or examples section, with a blank line between.
668+ insert_index = at
669+ extra_newline = True
670+ break
671+
672+ if insert_index is not None and app .config .typehints_document_rtype :
673+ if insert_index == len (lines ): # ensure that :rtype: doesn't get joined with a paragraph of text
674+ lines .append ("" )
675+ insert_index += 1
676+ if app .config .typehints_use_rtype or insert_index == len (lines ):
677+ line = f":rtype: { formatted_annotation } "
678+ if extra_newline :
679+ lines [insert_index :insert_index ] = [line , "\n " ]
656680 else :
657- line = lines [insert_index ]
658- lines [insert_index ] = f":return: { formatted_annotation } --{ line [line .find (' ' ):]} "
681+ lines .insert (insert_index , line )
682+ else :
683+ line = lines [insert_index ]
684+ lines [insert_index ] = f":return: { formatted_annotation } --{ line [line .find (' ' ):]} "
659685
660686
661687def validate_config (app : Sphinx , env : BuildEnvironment , docnames : list [str ]) -> None : # noqa: U100
0 commit comments