def add_content(_wrapped, self, *args, **kwds): if not self._datadescriptor and self.analyzer and self.objpath: attr_docs = self.analyzer.find_attr_docs() key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) if key not in attr_docs: # look for parent class w/ correct attr if hasattr(self.parent, "__mro__"): for basecls in self.parent.__mro__[1:]: try: analyzer = ModuleAnalyzer.for_module(basecls.__module__) base_attr_docs = analyzer.find_attr_docs() except PycodeError as err: continue # FIXME: need qualname or equivalent for basecls base_key = (basecls.__name__, self.objpath[-1]) if base_key in base_attr_docs: # insert data into existing analyzer # XXX: might be prettier way to handle this, # (esp so actual source file was reported) # but would have to duplicate much of add_content() attr_docs[key] = base_attr_docs[base_key] break return _wrapped(self, *args, **kwds)
def add_content(_wrapped, self, *args, **kwds): if not self._datadescriptor and self.analyzer and self.objpath: attr_docs = self.analyzer.find_attr_docs() key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) if key not in attr_docs: # look for parent class w/ correct attr if hasattr(self.parent, "__mro__"): for basecls in self.parent.__mro__[1:]: try: analyzer = ModuleAnalyzer.for_module( basecls.__module__) base_attr_docs = analyzer.find_attr_docs() except PycodeError as err: continue # FIXME: need qualname or equivalent for basecls base_key = (basecls.__name__, self.objpath[-1]) if base_key in base_attr_docs: # insert data into existing analyzer # XXX: might be prettier way to handle this, # (esp so actual source file was reported) # but would have to duplicate much of add_content() attr_docs[key] = base_attr_docs[base_key] break return _wrapped(self, *args, **kwds)
def get_grouped_documenters(self, all_members=False): """Method to return the member documenters This method is somewhat like a combination of the :meth:`sphinx.ext.autodoc.ModuleDocumenter.generate` method and the :meth:`sphinx.ext.autodoc.ModuleDocumenter.document_members` method. Hence it initializes this instance by importing the object, etc. and it finds the documenters to use for the autosummary option in the same style as the document_members does it. Returns ------- dict dictionary whose keys are determined by the :attr:`member_sections` dictionary and whose values are lists of tuples. Each tuple consists of a documenter and a boolean to identify whether a module check should be made describes an attribute or not. The dictionary can be used in the :meth:`AutoSummDirective.get_items_from_documenters` method Notes ----- If a :class:`sphinx.ext.autodoc.Documenter.member_order` value is not in the :attr:`member_sections` dictionary, it will be put into an additional `Miscellaneous` section.""" self.parse_name() self.import_object() # If there is no real module defined, figure out which to use. # The real module is used in the module analyzer to look up the module # where the attribute documentation would actually be found in. # This is used for situations where you have a module that collects the # functions and classes of internal submodules. self.real_modname = None or self.get_real_modname() # try to also get a source code analyzer for attribute docs try: self.analyzer = ModuleAnalyzer.for_module(self.real_modname) # parse right now, to get PycodeErrors on parsing (results will # be cached anyway) self.analyzer.find_attr_docs() except PycodeError as err: logger.debug('[autodocsumm] module analyzer failed: %s', err) # no source file -- e.g. for builtin and C modules self.analyzer = None # at least add the module.__file__ as a dependency if hasattr(self.module, '__file__') and self.module.__file__: self.directive.filename_set.add(self.module.__file__) else: self.directive.filename_set.add(self.analyzer.srcname) self.env.temp_data['autodoc:module'] = self.modname if self.objpath: self.env.temp_data['autodoc:class'] = self.objpath[0] # set the members from the autosummary member options options_save = {} for option in member_options.intersection(self.option_spec): autopt = 'autosummary-' + option if getattr(self.options, autopt): options_save[option] = getattr(self.options, option) self.options[option] = getattr(self.options, autopt) want_all = all_members or self.options.inherited_members or \ self.options.members is ALL # find out which members are documentable members_check_module, members = self.get_object_members(want_all) # remove members given by exclude-members if self.options.exclude_members: members = [(membername, member) for (membername, member) in members if membername not in self.options.exclude_members] # document non-skipped members memberdocumenters = [] if sphinx_version < [1, 7]: registry = AutodocRegistry._registry else: registry = get_documenters(self.env.app) for (mname, member, isattr) in self.filter_members(members, want_all): classes = [cls for cls in six.itervalues(registry) if cls.can_document_member(member, mname, isattr, self)] if not classes: # don't know how to document this member continue # prefer the documenter with the highest priority classes.sort(key=lambda cls: cls.priority) # give explicitly separated module name, so that members # of inner classes can be documented full_mname = self.modname + '::' + \ '.'.join(self.objpath + [mname]) documenter = classes[-1](self.directive, full_mname, self.indent) memberdocumenters.append((documenter, members_check_module and not isattr)) documenters = OrderedDict() for e in memberdocumenters: section = self.member_sections.get( e[0].member_order, 'Miscellaneous') if self.env.app: e[0].parse_name() e[0].import_object() user_section = self.env.app.emit_firstresult( 'autodocsumm-grouper', self.objtype, e[0].object_name, e[0].object, section, self.object) section = user_section or section documenters.setdefault(section, []).append(e) self.options.update(options_save) return documenters
def get_items_from_documenters(self, documenters): """Return the items needed for creating the tables This method creates the items that are used by the :meth:`sphinx.ext.autosummary.Autosummary.get_table` method by what is taken from the values of the :meth:`AutoSummModuleDocumenter.get_grouped_documenters` method. Returns ------- list A list containing tuples like ``(name, signature, summary_string, real_name)`` that can be used for the :meth:`sphinx.ext.autosummary.Autosummary.get_table` method.""" items = [] max_item_chars = 50 base_documenter = self.autosummary_documenter try: base_documenter.analyzer = ModuleAnalyzer.for_module( base_documenter.real_modname) attr_docs = base_documenter.analyzer.find_attr_docs() except PycodeError as err: logger.debug('[autodocsumm] module analyzer failed: %s', err) # no source file -- e.g. for builtin and C modules base_documenter.analyzer = None attr_docs = {} # at least add the module.__file__ as a dependency if (hasattr(base_documenter.module, '__file__') and base_documenter.module.__file__): base_documenter.directive.filename_set.add( base_documenter.module.__file__) else: base_documenter.directive.filename_set.add( base_documenter.analyzer.srcname) for documenter, check_module in documenters: documenter.parse_name() documenter.import_object() documenter.real_modname = documenter.get_real_modname() real_name = documenter.fullname display_name = documenter.object_name if display_name is None: # for instance attributes display_name = documenter.objpath[-1] if check_module and not documenter.check_module(): continue # -- Grab the signature sig = documenter.format_signature() if not sig: sig = '' else: max_chars = max(10, max_item_chars - len(display_name)) sig = mangle_signature(sig, max_chars=max_chars) # sig = sig.replace('*', r'\*') # -- Grab the documentation no_docstring = False if documenter.objpath: key = ('.'.join(documenter.objpath[:-1]), documenter.objpath[-1]) try: doc = attr_docs[key] no_docstring = True except KeyError: pass if not no_docstring: documenter.add_content(None) doc = documenter.get_doc() if doc: doc = doc[0] else: continue while doc and not doc[0].strip(): doc.pop(0) # If there's a blank line, then we can assume the first sentence / # paragraph has ended, so anything after shouldn't be part of the # summary for i, piece in enumerate(doc): if not piece.strip(): doc = doc[:i] break # Try to find the "first sentence", which may span multiple lines m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(doc).strip()) if m: summary = m.group(1).strip() elif doc: summary = doc[0].strip() else: summary = '' items.append((display_name, sig, summary, real_name)) return items
def get_items_from_documenters(self, documenters): """Return the items needed for creating the tables This method creates the items that are used by the :meth:`sphinx.ext.autosummary.Autosummary.get_table` method by what is taken from the values of the :meth:`AutoSummModuleDocumenter.get_grouped_documenters` method. Returns ------- list A list containing tuples like ``(name, signature, summary_string, real_name)`` that can be used for the :meth:`sphinx.ext.autosummary.Autosummary.get_table` method.""" items = [] max_item_chars = 50 base_documenter = self.autosummary_documenter base_documenter.analyzer = ModuleAnalyzer.for_module( base_documenter.real_modname) attr_docs = base_documenter.analyzer.find_attr_docs() for documenter, check_module in documenters: documenter.parse_name() documenter.import_object() documenter.real_modname = documenter.get_real_modname() real_name = documenter.fullname display_name = documenter.object_name if check_module and not documenter.check_module(): continue # -- Grab the signature sig = documenter.format_signature() if not sig: sig = '' else: max_chars = max(10, max_item_chars - len(display_name)) sig = mangle_signature(sig, max_chars=max_chars) sig = sig.replace('*', r'\*') # -- Grab the documentation no_docstring = False if documenter.objpath: key = ('.'.join(documenter.objpath[:-1]), documenter.objpath[-1]) try: doc = attr_docs[key] no_docstring = True except KeyError: pass if not no_docstring: documenter.add_content(None) doc = documenter.get_doc() if doc: doc = doc[0] else: continue while doc and not doc[0].strip(): doc.pop(0) # If there's a blank line, then we can assume the first sentence / # paragraph has ended, so anything after shouldn't be part of the # summary for i, piece in enumerate(doc): if not piece.strip(): doc = doc[:i] break # Try to find the "first sentence", which may span multiple lines m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(doc).strip()) if m: summary = m.group(1).strip() elif doc: summary = doc[0].strip() else: summary = '' items.append((display_name, sig, summary, real_name)) return items
def get_grouped_documenters(self, all_members=False): """Method to return the member documenters This method is somewhat like a combination of the :meth:`sphinx.ext.autodoc.ModuleDocumenter.generate` method and the :meth:`sphinx.ext.autodoc.ModuleDocumenter.document_members` method. Hence it initializes this instance by importing the object, etc. and it finds the documenters to use for the autosummary option in the same style as the document_members does it. Returns ------- dict dictionary whose keys are determined by the :attr:`member_sections` dictionary and whose values are lists of tuples. Each tuple consists of a documenter and a boolean to identify whether a module check should be made describes an attribute or not. The dictionary can be used in the :meth:`AutoSummDirective.get_items_from_documenters` method Notes ----- If a :class:`sphinx.ext.autodoc.Documenter.member_order` value is not in the :attr:`member_sections` dictionary, it will be put into an additional `Miscallaneous` section.""" self.parse_name() self.import_object() # If there is no real module defined, figure out which to use. # The real module is used in the module analyzer to look up the module # where the attribute documentation would actually be found in. # This is used for situations where you have a module that collects the # functions and classes of internal submodules. self.real_modname = None or self.get_real_modname() if not self.options.get('show-formatoptions') or not hasattr( self.object, '_get_formatoptions'): def is_not_fmt(docu_tuple): return True else: fmt_keys = list(self.object._get_formatoptions()) def is_not_fmt(docu_tuple): return docu_tuple[0].name.split('.')[-1] not in fmt_keys # try to also get a source code analyzer for attribute docs try: self.analyzer = ModuleAnalyzer.for_module(self.real_modname) # parse right now, to get PycodeErrors on parsing (results will # be cached anyway) self.analyzer.find_attr_docs() except PycodeError as err: self.env.app.debug('[autodoc] module analyzer failed: %s', err) # no source file -- e.g. for builtin and C modules self.analyzer = None # at least add the module.__file__ as a dependency if hasattr(self.module, '__file__') and self.module.__file__: self.directive.filename_set.add(self.module.__file__) else: self.directive.filename_set.add(self.analyzer.srcname) self.env.temp_data['autodoc:module'] = self.modname if self.objpath: self.env.temp_data['autodoc:class'] = self.objpath[0] want_all = all_members or self.options.inherited_members or \ self.options.members is ALL # find out which members are documentable members_check_module, members = self.get_object_members(want_all) # remove members given by exclude-members if self.options.exclude_members: members = [(membername, member) for (membername, member) in members if membername not in self.options.exclude_members] # document non-skipped members memberdocumenters = [] for (mname, member, isattr) in self.filter_members(members, want_all): classes = [cls for cls in six.itervalues(AutoDirective._registry) if cls.can_document_member(member, mname, isattr, self)] if not classes: # don't know how to document this member continue # prefer the documenter with the highest priority classes.sort(key=lambda cls: cls.priority) # give explicitly separated module name, so that members # of inner classes can be documented full_mname = self.modname + '::' + \ '.'.join(self.objpath + [mname]) documenter = classes[-1](self.directive, full_mname, self.indent) memberdocumenters.append((documenter, members_check_module and not isattr)) documenters = self.member_sections.copy() for section, order in six.iteritems(documenters): documenters[section] = sorted( (e for e in memberdocumenters if e[0].member_order == order and is_not_fmt(e)), key=lambda e: e[0].member_order) fmts = defaultdict(set) for e in filterfalse(is_not_fmt, memberdocumenters): e[0].parse_name() e[0].import_object() fmts[e[0].object.groupname].add(e) for gname, l in sorted(fmts.items()): documenters[gname] = sorted( l, key=lambda e: e[0].object.key) remaining = sorted( (e for e in memberdocumenters if e[0].member_order not in six.itervalues(self.member_sections)), key=lambda e: e[0].name.split('::')[-1]) if remaining: documenters['Miscallaneous'] = remaining return documenters