From 49de4ab1a16664ebb343d353cf5d54d7dbd32318 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 1 Jun 2020 02:08:57 +0900 Subject: Support overloaded constructors (__call__, __init__ and __new__) --- sphinx/ext/autodoc/__init__.py | 46 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'sphinx') diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 4fb6a4ce9..31301e01e 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -1279,6 +1279,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: 'private-members': bool_option, 'special-members': members_option, } # type: Dict[str, Callable] + _signature_class = None # type: Any + _signature_method_name = None # type: str + def __init__(self, *args: Any) -> None: super().__init__(*args) merge_special_members_option(self.options) @@ -1299,7 +1302,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: self.doc_as_attr = True return ret - def _get_signature(self) -> Optional[Signature]: + def _get_signature(self) -> Tuple[Optional[Any], Optional[str], Optional[Signature]]: def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: """ Get the `attr` function or method from `obj`, if it is user-defined. """ if inspect.is_builtin_class_method(obj, attr): @@ -1323,7 +1326,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if call is not None: self.env.app.emit('autodoc-before-process-signature', call, True) try: - return inspect.signature(call, bound_method=True) + sig = inspect.signature(call, bound_method=True) + return type(self.object), '__call__', sig except ValueError: pass @@ -1332,7 +1336,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if new is not None: self.env.app.emit('autodoc-before-process-signature', new, True) try: - return inspect.signature(new, bound_method=True) + sig = inspect.signature(new, bound_method=True) + return self.object, '__new__', sig except ValueError: pass @@ -1341,7 +1346,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if init is not None: self.env.app.emit('autodoc-before-process-signature', init, True) try: - return inspect.signature(init, bound_method=True) + sig = inspect.signature(init, bound_method=True) + return self.object, '__init__', sig except ValueError: pass @@ -1351,20 +1357,21 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: # the signature from, so just pass the object itself to our hook. self.env.app.emit('autodoc-before-process-signature', self.object, False) try: - return inspect.signature(self.object, bound_method=False) + sig = inspect.signature(self.object, bound_method=False) + return None, None, sig except ValueError: pass # Still no signature: happens e.g. for old-style classes # with __init__ in C and no `__text_signature__`. - return None + return None, None, None def format_args(self, **kwargs: Any) -> str: if self.env.config.autodoc_typehints in ('none', 'description'): kwargs.setdefault('show_annotation', False) try: - sig = self._get_signature() + self._signature_class, self._signature_method_name, sig = self._get_signature() except TypeError as exc: # __signature__ attribute contained junk logger.warning(__("Failed to get a constructor signature for %s: %s"), @@ -1380,7 +1387,30 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: if self.doc_as_attr: return '' - return super().format_signature(**kwargs) + sig = super().format_signature() + + overloaded = False + qualname = None + # TODO: recreate analyzer for the module of class (To be clear, owner of the method) + if self._signature_class and self._signature_method_name and self.analyzer: + qualname = '.'.join([self._signature_class.__qualname__, + self._signature_method_name]) + if qualname in self.analyzer.overloads: + overloaded = True + + sigs = [] + if overloaded: + # Use signatures for overloaded methods instead of the implementation method. + for overload in self.analyzer.overloads.get(qualname): + parameters = list(overload.parameters.values()) + overload = overload.replace(parameters=parameters[1:], + return_annotation=Parameter.empty) + sig = stringify_signature(overload, **kwargs) + sigs.append(sig) + else: + sigs.append(sig) + + return "\n".join(sigs) def add_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() -- cgit v1.2.3