From c8272c0bb80ef219597a3968ae1e6182ebc8f943 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Mon, 10 May 2021 20:16:51 +0200 Subject: [PATCH] Sync autodoc with upstream to fix deprecation warnings --- src/sage_docbuild/ext/sage_autodoc.py | 56 +++++++++++++++++++-------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py index ac9f8538bc7..c4523f2a531 100644 --- a/src/sage_docbuild/ext/sage_autodoc.py +++ b/src/sage_docbuild/ext/sage_autodoc.py @@ -34,13 +34,12 @@ from docutils.statemachine import ViewList import sphinx -from sphinx.ext.autodoc import mock +from sphinx.ext.autodoc import mock, ObjectMember from sphinx.ext.autodoc.importer import import_object, get_object_members, get_module_members from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer from sphinx.errors import PycodeError from sphinx.util import logging -from sphinx.util import rpartition, force_decode from sphinx.util.docstrings import prepare_docstring from sphinx.util.inspect import isdescriptor, \ safe_getattr, object_description, is_builtin_class_method, \ @@ -488,10 +487,7 @@ def get_doc(self, encoding=None, ignore=1): # make sure we have Unicode docstrings, then sanitize and split # into lines if isinstance(docstring, str): - return [prepare_docstring(docstring, ignore)] - elif isinstance(docstring, str): # this will not trigger on Py3 - return [prepare_docstring(force_decode(docstring, encoding), - ignore)] + return [prepare_docstring(docstring)] # ... else it is something strange, let's ignore it return [] @@ -536,7 +532,7 @@ def add_content(self, more_content, no_docstring=False): # add content from docstrings if not no_docstring: - encoding = self.analyzer and self.analyzer._encoding + encoding = self.analyzer docstrings = self.get_doc(encoding) if not docstrings: # append at least a dummy docstring, so that the event @@ -876,13 +872,42 @@ def add_directive_header(self, sig): if self.options.deprecated: self.add_line(u' :deprecated:', sourcename) + def get_module_members(self): + """Get members of target module.""" + if self.analyzer: + attr_docs = self.analyzer.attr_docs + else: + attr_docs = {} + + members = {} # type: Dict[str, ObjectMember] + for name in dir(self.object): + try: + value = safe_getattr(self.object, name, None) + docstring = attr_docs.get(('', name), []) + members[name] = ObjectMember(name, value, docstring="\n".join(docstring)) + except AttributeError: + continue + + # annotation only member (ex. attr: int) + try: + for name in inspect.getannotations(self.object): + if name not in members: + docstring = attr_docs.get(('', name), []) + members[name] = ObjectMember(name, INSTANCEATTR, + docstring="\n".join(docstring)) + except AttributeError: + pass + + return members + def get_object_members(self, want_all): # type: (bool) -> Tuple[bool, List[Tuple[unicode, object]]] + members = self.get_module_members() if want_all: if not hasattr(self.object, '__all__'): # for implicit module members, check __module__ to avoid # documenting imported objects - return True, get_module_members(self.object) + return True, list(members.values()) else: memberlist = self.object.__all__ # Sometimes __all__ is broken... @@ -893,14 +918,14 @@ def get_object_members(self, want_all): '(in module %s) -- ignoring __all__' % (memberlist, self.fullname)) # fall back to all members - return True, get_module_members(self.object) + return True, list(members.values()) else: memberlist = self.options.members or [] ret = [] for mname in memberlist: - try: - ret.append((mname, safe_getattr(self.object, mname))) - except AttributeError: + if mname in members: + ret.append(members[mname]) + else: logger.warning( 'missing attribute mentioned in :members: or __all__: ' 'module %s, attribute %s' % @@ -951,7 +976,7 @@ def resolve_name(self, modname, parents, path, base): # ... if still None, there's no way to know if mod_cls is None: return None, [] - modname, cls = rpartition(mod_cls, '.') # type: ignore + modname, _, cls = mod_cls.rpartition('.') # type: ignore parents = [cls] # if the module name is still missing, get it like above if not modname: @@ -1275,10 +1300,7 @@ def get_doc(self, encoding=None, ignore=1): doc = [] for docstring in docstrings: if isinstance(docstring, str): - doc.append(prepare_docstring(docstring, ignore)) - elif isinstance(docstring, str): # this will not trigger on Py3 - doc.append(prepare_docstring(force_decode(docstring, encoding), - ignore)) + doc.append(prepare_docstring(docstring)) return doc def add_content(self, more_content, no_docstring=False):