Hello community, here is the log from the commit of package python-autodocsumm for openSUSE:Factory checked in at 2020-09-04 11:10:47 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-autodocsumm (Old) and /work/SRC/openSUSE:Factory/.python-autodocsumm.new.3399 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-autodocsumm" Fri Sep 4 11:10:47 2020 rev:2 rq:831600 version:0.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-autodocsumm/python-autodocsumm.changes 2020-04-27 23:36:52.431347066 +0200 +++ /work/SRC/openSUSE:Factory/.python-autodocsumm.new.3399/python-autodocsumm.changes 2020-09-04 11:11:26.479010510 +0200 @@ -1,0 +2,6 @@ +Thu Sep 3 04:27:24 UTC 2020 - Steve Kowalik <[email protected]> + +- Update to 0.2.0: + * No upstream changelog + +------------------------------------------------------------------- Old: ---- v0.1.13.tar.gz New: ---- v0.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-autodocsumm.spec ++++++ --- /var/tmp/diff_new_pack.WX8cAv/_old 2020-09-04 11:11:26.987010765 +0200 +++ /var/tmp/diff_new_pack.WX8cAv/_new 2020-09-04 11:11:26.991010767 +0200 @@ -17,12 +17,12 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} +%define skip_python2 1 Name: python-autodocsumm -Version: 0.1.13 +Version: 0.2.0 Release: 0 Summary: Extended sphinx autodoc including automatic autosummaries License: GPL-2.0-only -Group: Development/Languages/Python URL: https://github.com/Chilipp/autodocsumm Source: https://github.com/Chilipp/autodocsumm/archive/v%{version}.tar.gz BuildRequires: %{python_module devel} ++++++ v0.1.13.tar.gz -> v0.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/.travis.yml new/autodocsumm-0.2.0/.travis.yml --- old/autodocsumm-0.1.13/.travis.yml 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/.travis.yml 2020-08-21 23:20:13.000000000 +0200 @@ -6,55 +6,14 @@ - "3.8" - "3.7" - "3.6" - - "2.7" env: - SPHINX_VERSION="" + - SPHINX_VERSION=3.2.* + - SPHINX_VERSION=3.1.* + - SPHINX_VERSION=3.0.* - SPHINX_VERSION=2.4.* - SPHINX_VERSION=2.3.* - SPHINX_VERSION=2.2.* - - SPHINX_VERSION=2.1.* - - SPHINX_VERSION=2.0.* - - SPHINX_VERSION=1.8.* - - SPHINX_VERSION=1.7.* - - SPHINX_VERSION=1.6.* - - SPHINX_VERSION=1.5.* - - SPHINX_VERSION=1.4.* - - SPHINX_VERSION=1.3.* -matrix: - exclude: - - python: "2.7" - env: SPHINX_VERSION=2.0.* - - python: "2.7" - env: SPHINX_VERSION=2.1.* - - python: "2.7" - env: SPHINX_VERSION=2.2.* - - python: "2.7" - env: SPHINX_VERSION=2.3.* - - python: "2.7" - env: SPHINX_VERSION=2.4.* - - python: "3.7" - env: SPHINX_VERSION=1.3.* - - python: "3.7" - env: SPHINX_VERSION=1.4.* - - python: "3.7" - env: SPHINX_VERSION=1.5.* - - python: "3.7" - env: SPHINX_VERSION=1.6.* - - python: "3.7" - env: SPHINX_VERSION=1.3.* - - python: "3.8" - env: SPHINX_VERSION=1.4.* - - python: "3.8" - env: SPHINX_VERSION=1.5.* - - python: "3.8" - env: SPHINX_VERSION=1.6.* - - python: "3.8" - env: SPHINX_VERSION=1.7.* - - python: "3.8" - env: SPHINX_VERSION=1.8.* - - python: "3.8" - env: SPHINX_VERSION=1.9.* - install: - pip install coveralls diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/autodocsumm/__init__.py new/autodocsumm-0.2.0/autodocsumm/__init__.py --- old/autodocsumm-0.1.13/autodocsumm/__init__.py 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/autodocsumm/__init__.py 2020-08-21 23:20:13.000000000 +0200 @@ -1,52 +1,47 @@ -"""Sphinx extension that defines a new automodule directive with autosummary +"""Sphinx extension that defines new auto documenters with autosummary. -The :class:`AutoSummDirective` defined in this extension module allows the -same functionality as the automodule and autoclass directives of the -:mod:`sphinx.ext.autodoc` module but with an additional `autosummary` option. -This option puts a autosummary in the style of the -:mod:`sphinx.ext.autosummary` module at the beginning of the class or module. -The content of this autosummary is automatically determined by the results of -the automodule (or autoclass) directive. +The :class:`AutoSummModuleDocumenter` and :class:`AutoSummClassDocumenter` +classes defined here enable an autosummary-style listing of the corresponding +members. This extension gives also the possibility to choose which data shall be shown and to include the docstring of the ``'__call__'`` attribute. """ -import logging +from itertools import chain + +from sphinx.util import logging import re import six + +from docutils import nodes + import sphinx + +from sphinx.util.docutils import SphinxDirective + from sphinx.ext.autodoc import ( ClassDocumenter, ModuleDocumenter, ALL, PycodeError, ModuleAnalyzer, bool_option, AttributeDocumenter, DataDocumenter, Options, prepare_docstring) import sphinx.ext.autodoc as ad -from sphinx.ext.autosummary import Autosummary, mangle_signature -from docutils import nodes -from docutils.statemachine import ViewList signature = Signature = None -if sphinx.__version__ >= '1.7': - from sphinx.ext.autodoc import get_documenters - from sphinx.ext.autodoc.directive import ( - AutodocDirective, AUTODOC_DEFAULT_OPTIONS, DocumenterBridge, - process_documenter_options) - try: - from sphinx.util.inspect import signature, stringify_signature - except ImportError: - from sphinx.ext.autodoc import Signature +from sphinx.ext.autodoc.directive import ( + AutodocDirective, AUTODOC_DEFAULT_OPTIONS, process_documenter_options, + DocumenterBridge +) + +from sphinx.ext.autodoc import get_documenters -else: - from sphinx.ext.autodoc import ( - getargspec, formatargspec, AutoDirective as AutodocDirective, - AutoDirective as AutodocRegistry) +try: + from sphinx.util.inspect import signature, stringify_signature +except ImportError: + from sphinx.ext.autodoc import Signature sphinx_version = list(map(float, re.findall(r'\d+', sphinx.__version__)[:3])) -if sphinx_version >= [2, 0]: - from sphinx.util import force_decode -else: - from sphinx.ext.autodoc import force_decode +from sphinx.util import force_decode try: @@ -60,7 +55,7 @@ if six.PY2: from itertools import imap as map -__version__ = '0.1.13' +__version__ = '0.2.0' __author__ = "Philipp S. Sommer" @@ -87,27 +82,18 @@ else: args = args.replace('\\', '\\\\') return args -else: - def process_signature(obj): - try: - argspec = getargspec(obj) - except TypeError: - # still not possible: happens e.g. for old-style classes - # with __call__ in C - return None - if argspec[0] and argspec[0][0] in ('cls', 'self'): - del argspec[0][0] - if sphinx_version < [1, 4]: - return formatargspec(*argspec) - else: - return formatargspec(obj, *argspec) + + +def list_option(option): + """Transform a string to a list by splitting at ;;.""" + return [s.strip() for s in option.split(";;")] class AutosummaryDocumenter(object): """Abstract class for for extending Documenter methods This classed is used as a base class for Documenters in order to provide - the necessary methods for the :class:`AutoSummDirective`.""" + the necessary methods for generating the autosummary.""" #: List of functions that may filter the members filter_funcs = [] @@ -134,15 +120,15 @@ 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 + check should be made describes an attribute or not. 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.""" + use_sections = self.options.autosummary_sections + self.parse_name() self.import_object() # If there is no real module defined, figure out which to use. @@ -172,6 +158,13 @@ if self.objpath: self.env.temp_data['autodoc:class'] = self.objpath[0] + if not self.options.autosummary_force_inline: + docstring = self.get_doc() + autodocsumm_directive = '.. auto%ssumm::' % self.objtype + for s in chain.from_iterable(docstring): + if autodocsumm_directive in s: + return {} + # set the members from the autosummary member options options_save = {} for option in member_options.intersection(self.option_spec): @@ -192,10 +185,8 @@ # document non-skipped members memberdocumenters = [] - if sphinx_version < [1, 7]: - registry = AutodocRegistry._registry - else: - registry = get_documenters(self.env.app) + 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)] @@ -223,18 +214,43 @@ 'autodocsumm-grouper', self.objtype, e[0].object_name, e[0].object, section, self.object) section = user_section or section - documenters.setdefault(section, []).append(e) + if not use_sections or section in use_sections: + documenters.setdefault(section, []).append(e) self.options.update(options_save) return documenters + def add_autosummary(self): + """Add the autosammary table of this documenter.""" + if self.options.autosummary: + + grouped_documenters = self.get_grouped_documenters() + + sourcename = self.get_sourcename() + + for section, documenters in grouped_documenters.items(): + if not self.options.autosummary_no_titles: + self.add_line('**%s:**' % section, sourcename) + + self.add_line('', sourcename) + + self.add_line('.. autosummary::', sourcename) + self.add_line('', sourcename) + indent = ' ' + + for (documenter, _) in documenters: + self.add_line( + indent + '~' + documenter.fullname, sourcename) + self.add_line('', sourcename) + class AutoSummModuleDocumenter(ModuleDocumenter, AutosummaryDocumenter): - """Module documentor suitable for the :class:`AutoSummDirective` + """Module documentor with autosummary tables of its members. This class has the same functionality as the base :class:`sphinx.ext.autodoc.ModuleDocumenter` class but with an additional - `autosummary` and the :meth:`get_grouped_documenters` method. - It's priority is slightly higher than the one of the ModuleDocumenter.""" + `autosummary`. + It's priority is slightly higher than the one of the ModuleDocumenter. + """ #: slightly higher priority than #: :class:`sphinx.ext.autodoc.ModuleDocumenter` @@ -245,6 +261,9 @@ option_spec = ModuleDocumenter.option_spec.copy() option_spec['autosummary'] = bool_option option_spec['autosummary-no-nesting'] = bool_option + option_spec['autosummary-sections'] = list_option + option_spec['autosummary-no-titles'] = bool_option + option_spec['autosummary-force-inline'] = bool_option #: Add options for members for the autosummary for _option in member_options.intersection(option_spec): @@ -263,15 +282,24 @@ values correspond to the :attr:`sphinx.ext.autodoc.Documenter.member_order` attribute that shall be used for each section.""" + def add_content(self, *args, **kwargs): + super().add_content(*args, **kwargs) + + self.add_autosummary() + + if self.options.autosummary_no_nesting: + self.options.autosummary = False + class AutoSummClassDocumenter(ClassDocumenter, AutosummaryDocumenter): - """Class documentor suitable for the :class:`AutoSummDirective` + """Class documentor with autosummary tables for its members. This class has the same functionality as the base :class:`sphinx.ext.autodoc.ClassDocumenter` class but with an additional `autosummary` option to provide the ability to provide a summary of all - methods and attributes at the beginning. - It's priority is slightly higher than the one of the ClassDocumenter""" + methods and attributes. + It's priority is slightly higher than the one of the ClassDocumenter + """ #: slightly higher priority than #: :class:`sphinx.ext.autodoc.ClassDocumenter` @@ -282,6 +310,9 @@ option_spec = ClassDocumenter.option_spec.copy() option_spec['autosummary'] = bool_option option_spec['autosummary-no-nesting'] = bool_option + option_spec['autosummary-sections'] = list_option + option_spec['autosummary-no-titles'] = bool_option + option_spec['autosummary-force-inline'] = bool_option #: Add options for members for the autosummary for _option in member_options.intersection(option_spec): @@ -299,6 +330,11 @@ values correspond to the :attr:`sphinx.ext.autodoc.Documenter.member_order` attribute that shall be used for each section.""" + def add_content(self, *args, **kwargs): + super().add_content(*args, **kwargs) + + self.add_autosummary() + class CallableDataDocumenter(DataDocumenter): """:class:`sphinx.ext.autodoc.DataDocumenter` that uses the __call__ attr @@ -311,10 +347,7 @@ callmeth = self.get_attr(self.object, '__call__', None) if callmeth is None: return None - if sphinx_version < [1, 7]: - pass - else: - return process_signature(callmeth) + return process_signature(callmeth) def get_doc(self, encoding=None, ignore=1): """Reimplemented to include data from the call method""" @@ -390,332 +423,6 @@ return doc -class AutoSummDirective(AutodocDirective, Autosummary): - """automodule directive that makes a summary at the beginning of the module - - This directive combines the - :class:`sphinx.ext.autodoc.directives.AutodocDirective` and - :class:`sphinx.ext.autosummary.Autosummary` directives to put a summary of - the specified module at the beginning of the module documentation.""" - - if sphinx_version < [1, 7]: - _default_flags = AutodocDirective._default_flags.union( - {'autosummary', 'autosummary-no-nesting'} | set(map('autosummary-{}'.format, member_options)) - ) - else: - AUTODOC_DEFAULT_OPTIONS.extend(['autosummary', 'autosummary-no-nesting']) - AUTODOC_DEFAULT_OPTIONS.extend( - map('autosummary-{}'.format, member_options)) - - @property - def autosummary_documenter(self): - """Returns the AutosummaryDocumenter subclass that can be used""" - try: - return self._autosummary_documenter - except AttributeError: - pass - objtype = self.name[4:] - env = self.state.document.settings.env - if sphinx_version < [1, 7]: - doc_class = self._registry[objtype] - params = self - else: - reporter = self.state.document.reporter - try: - lineno = reporter.get_source_and_line(self.lineno)[1] - except AttributeError: - lineno = None - doc_class = get_documenters(self.env.app)[objtype] - args = (self.state, ) if sphinx_version >= [2, 1] else () - params = DocumenterBridge( - env, reporter, - process_documenter_options(doc_class, env.config, - self.options), - lineno, *args) - documenter = doc_class(params, self.arguments[0]) - if hasattr(documenter, 'get_grouped_documenters'): - self._autosummary_documenter = documenter - return documenter - # in case the has been changed in the registry, we decide manually - if objtype == 'module': - documenter = AutoSummModuleDocumenter(params, self.arguments[0]) - elif objtype == 'class': - documenter = AutoSummClassDocumenter(params, self.arguments[0]) - else: - raise ValueError( - "Could not find a valid documenter for the object type %s" % ( - objtype)) - self._autosummary_documenter = documenter - return documenter - - def run(self): - """Run method for the directive""" - options_save = self.options.copy() - doc_nodes = AutodocDirective.run(self) - self.options.update(options_save) - if 'autosummary' not in self.options: - return doc_nodes - try: - self.env = self.state.document.settings.env - except AttributeError: - pass # is set automatically with sphinx >= 1.8.0 - if sphinx_version < [2, 0]: - self.warnings = [] - self.result = ViewList() - documenter = self.autosummary_documenter - grouped_documenters = documenter.get_grouped_documenters() - nested = 'autosummary-no-nesting' not in self.options - summ_nodes = self.autosumm_nodes(documenter, grouped_documenters, nested) - - dn = summ_nodes.pop(documenter.fullname) - if self.name == 'automodule': - doc_nodes = self.inject_summ_nodes(doc_nodes, summ_nodes) - # insert the nodes directly after the paragraphs - if self.name == 'autoclass': - for node in dn[::-1]: - self._insert_after_paragraphs(doc_nodes[1], node) - dn = [] - elif self.name == 'automodule': - # insert table before the documentation of the members - istart = 2 if 'noindex' not in self.options else 0 - # if we have a title in the module, we look for the section - if (len(doc_nodes) >= istart + 1 and - isinstance(doc_nodes[istart], nodes.section)): - others = doc_nodes[istart] - istart = 2 # skip the title - else: - others = doc_nodes - found = False - if len(others[istart:]) >= 2: - for i in range(istart, len(others)): - if isinstance(others[i], sphinx.addnodes.index): - found = True - break - if found: - for node in dn[::-1]: - others.insert(i, node) - dn = [] - if sphinx_version < [2, 0]: - return self.warnings + dn + doc_nodes - else: - return dn + doc_nodes - - def _insert_after_paragraphs(self, node, insertion): - """Inserts the given `insertion` node after the paragraphs in `node` - - This method inserts the `insertion` node after the instances of - nodes.paragraph in the given `node`. - Usually the node of one documented class is set up like - - Name of the documented item (allways) (nodes.Element) - Summary (sometimes) (nodes.paragraph) - description (sometimes) (nodes.paragraph) - Parameters section (sometimes) (nodes.rubric) - - We want to be below the description, so we loop until we - are below all the paragraphs. IF that does not work, - we simply put it at the end""" - found = False - if len(node) >= 2: - for i in range(len(node[1])): - if not isinstance(node[1][i], nodes.paragraph): - node[1].insert(i + 1, insertion) - found = True - break - if not found: - node.insert(1, insertion) - - def inject_summ_nodes(self, doc_nodes, summ_nodes): - """Method to inject the autosummary nodes into the autodoc nodes - - Parameters - ---------- - doc_nodes: list - The list of nodes as they are generated by the - :meth:`sphinx.ext.autodoc.AutodocDirective.run` method - summ_nodes: dict - The generated autosummary nodes as they are generated by the - :meth:`autosumm_nodes` method. Note that `summ_nodes` must only - contain the members autosummary tables! - - Returns - ------- - doc_nodes: list - The modified `doc_nodes` - - Notes - ----- - `doc_nodes` are modified in place and not copied!""" - def inject_summary(node): - if isinstance(node, nodes.section): - for sub in node: - inject_summary(sub) - return - if (len(node) and (isinstance(node, nodes.section) or ( - isinstance(node[0], nodes.Element) and - node[0].get('module') and node[0].get('fullname')))): - node_summ_nodes = summ_nodes.get("%s.%s" % ( - node[0]['module'], node[0]['fullname'])) - if not node_summ_nodes: - return - for summ_node in node_summ_nodes[::-1]: - self._insert_after_paragraphs(node, summ_node) - for node in doc_nodes: - inject_summary(node) - return doc_nodes - - def autosumm_nodes(self, documenter, grouped_documenters, nested): - """Create the autosummary nodes based on the documenter content - - Parameters - ---------- - documenter: sphinx.ext.autodoc.Documenter - The base (module or class) documenter for which to generate the - autosummary tables of its members - grouped_documenters: dict - The dictionary as it is returned from the - :meth:`AutosummaryDocumenter.get_grouped_documenters` method - nested: bool - If true, autosummary tables will also be created for members. - - Returns - ------- - dict - a mapping from the objects fullname to the corresponding - autosummary tables of its members. The objects include the main - object of the given `documenter` and the classes that are defined - in it - - See Also - -------- - AutosummaryDocumenter.get_grouped_documenters, inject_summ_nodes""" - - summ_nodes = {} - this_nodes = [] - for section, documenters in six.iteritems(grouped_documenters): - items = self.get_items_from_documenters(documenters) - if not items: - continue - node = nodes.rubric() - # create note for the section title (we could also use .. rubric - # but that causes problems for latex documentations) - self.state.nested_parse( - ViewList(['**%s**' % section]), 0, node) - this_nodes += node - this_nodes += self.get_table(items) - if nested: - for mdocumenter, check_module in documenters: - if (mdocumenter.objtype == 'class' and - not (check_module and not mdocumenter.check_module())): - if hasattr(mdocumenter, 'get_grouped_documenters'): - summ_nodes.update(self.autosumm_nodes( - mdocumenter, mdocumenter.get_grouped_documenters(), nested) - ) - summ_nodes[documenter.fullname] = this_nodes - return summ_nodes - - 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 dont_document_data(config, fullname): """Check whether the given object should be documented @@ -775,34 +482,91 @@ self.options.annotation = ' ' +class AutoDocSummDirective(SphinxDirective): + """A directive to generate an autosummary. + + Usage:: + + .. autoclasssum:: <Class> + + .. automodsum:: <module> + + The directive additionally supports all options of the ``autoclass`` or + ``automod`` directive respectively. Sections can be a list of section titles + to be included. If ommitted, all sections are used. + """ + + has_content = False + + option_spec = AutodocDirective.option_spec + + required_arguments = 1 + optional_arguments = 0 + + def run(self): + reporter = self.state.document.reporter + + try: + source, lineno = reporter.get_source_and_line(self.lineno) + except AttributeError: + source, lineno = (None, None) + + # look up target Documenter + objtype = self.name[4:-4] # strip prefix (auto-) and suffix (-summ). + doccls = self.env.app.registry.documenters[objtype] + + self.options['autosummary-force-inline'] = True + self.options['autosummary'] = True + if 'no-members' not in self.options: + self.options['members'] = True + + # process the options with the selected documenter's option_spec + try: + documenter_options = process_documenter_options(doccls, self.config, + self.options) + except (KeyError, ValueError, TypeError) as exc: + # an option is either unknown or has a wrong type + logger.error( + f'An option to {self.name} is either unknown or has an invalid ' + f'value: {exc}', + location=(self.env.docname, lineno)) + return [] + + # generate the output + params = DocumenterBridge(self.env, reporter, documenter_options, + lineno, self.state) + documenter = doccls(params, self.arguments[0]) + documenter.add_autosummary() + + node = nodes.paragraph() + node.document = self.state.document + self.state.nested_parse(params.result, 0, node) + + return node.children + + def setup(app): """setup function for using this module as a sphinx extension""" app.setup_extension('sphinx.ext.autosummary') app.setup_extension('sphinx.ext.autodoc') + app.add_directive('autoclasssumm', AutoDocSummDirective) + app.add_directive('automodulesumm', AutoDocSummDirective) + + AUTODOC_DEFAULT_OPTIONS.extend( + [option for option in AutoSummModuleDocumenter.option_spec + if option not in AUTODOC_DEFAULT_OPTIONS]) + + AUTODOC_DEFAULT_OPTIONS.extend( + [option for option in AutoSummClassDocumenter.option_spec + if option not in AUTODOC_DEFAULT_OPTIONS]) # make sure to allow inheritance when registering new documenters - if sphinx_version < [1, 7]: - registry = AutodocRegistry._registry - else: - registry = get_documenters(app) + registry = get_documenters(app) for cls in [AutoSummClassDocumenter, AutoSummModuleDocumenter, CallableAttributeDocumenter, NoDataDataDocumenter, NoDataAttributeDocumenter]: if not issubclass(registry.get(cls.objtype), cls): - if sphinx_version >= [2, 2]: - app.add_autodocumenter(cls, override=True) - elif sphinx_version >= [0, 6]: - app.add_autodocumenter(cls) - else: - app.add_documenter(cls) - - # directives - if sphinx_version >= [1, 8]: - app.add_directive('automodule', AutoSummDirective, override=True) - app.add_directive('autoclass', AutoSummDirective, override=True) - else: - app.add_directive('automodule', AutoSummDirective) - app.add_directive('autoclass', AutoSummDirective) + app.add_autodocumenter(cls, override=True) # group event app.add_event('autodocsumm-grouper') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/docs/conf_settings.rst new/autodocsumm-0.2.0/docs/conf_settings.rst --- old/autodocsumm-0.1.13/docs/conf_settings.rst 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/docs/conf_settings.rst 2020-08-21 23:20:13.000000000 +0200 @@ -38,15 +38,47 @@ - ``autosummary-imported-members`` - ``autosummary-ignore-module-all`` - ``autosummary-members`` -- ``autosummary-no-nesting`` They are essentially the same as the options for :mod:`~sphinx.ext.autodoc` (i.e. ``private-members`` or ``members``), but they only affect the autosummary table (see the example in :ref:`summary-table-example`). -The new additional flag ``autosummary-no-nesting`` only generates -autosummary tables for a module, but not for members within. See -:ref:`no-nesting-example`. +``autosummary-no-nesting`` + The new additional flag ``autosummary-no-nesting`` only generates + autosummary tables for a module, but not for members within. See + example about :ref:`no-nesting-example`. +``autosummary-sections`` + Select which sections to generate the autosummary for. Usage is like + ``:autosummary-sections: Methods ;; Attributes``. When omitted, all sections + are generated. See the example about :ref:`select-sections-example` +``autosummary-no-titles`` + Do not add section titles above each autosummary table +``autosummary-force-inline`` + Force adding the autosummary, even it is already contained in the class + or module docstring. See the example about :ref:`autosummary-position-example` + + +.. _directives: + +Directives +---------- + +.. rst:directive:: autoclasssumm + + This class generates the autosummary tables for the given class. You can + use the same options as for the ``autoclass`` directive. You can select a + specific section and omit the title via:: + + .. autoclasssumm:: MyClass + :autosummary-sections: Methods + :autosummary-no-titles: + + By default, this directives also sets the `:members:` option unless you + specify `:no-members`. + +.. rst:directive:: automodulesumm + + The same as the ``autoclasssumm`` directive, just for a module. .. _confvals: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/docs/examples.rst new/autodocsumm-0.2.0/docs/examples.rst --- old/autodocsumm-0.1.13/docs/examples.rst 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/docs/examples.rst 2020-08-21 23:20:13.000000000 +0200 @@ -138,3 +138,68 @@ :members: :autosummary: :autosummary-no-nesting: + + +.. _select-sections-example: + +Select the sections to document +------------------------------- +You can select, which sections to document. If you only want the *Methods* +section of a class, you can specify:: + + .. autoclass:: dummy.MyClass + :members: + :autosummary: + :autosummary-sections: Methods + +Multiple sections might be separated by `;;`, e.g. +``:autosummary-sections: Methods ;; Attributes``. + +This also works for the ``autoclasssumm`` and ``automodulesumm`` directives, +e.g.:: + + .. autoclasssumm:: dummy.SomeClass + :autosummary-sections: Methods + +.. autoclasssumm:: dummy.MyClass + :autosummary-sections: Methods + + +.. _autosummary-position-example: + +Positioning of the autosummary table +------------------------------------ +By default, the autosummary tables are put at the end of the docstring sections +for classes and methods, i.e. something like:: + + class-name + class-docstring + autosummary-tables + class-members + +You can customize this positioning by calling the ``.. autoclasssumm::`` +directive inside the class docstring, e.g. + +.. literalinclude:: inline_autoclasssumm.py + +Documenting this, with ``.. autoclass:: MyClass`` creates + +.. autoclass:: inline_autoclasssumm.MyClass + :noindex: + :members: + +Note that this omits the `Attributes` section as we specified the +``:autosummary-sections:`` options here. If you want to list this section +anyway at the end of the docstring, you can use the ``autosummary-force-inline`` +option, e.g.:: + + .. autoclass:: inline_autoclasssumm.MyClass + :members: + :autosummary-force-inline: + :autosummary-sections: Attributes + +.. autoclass:: inline_autoclasssumm.MyClass + :members: + :noindex: + :autosummary-force-inline: + :autosummary-sections: Attributes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/docs/inline_autoclasssumm.py new/autodocsumm-0.2.0/docs/inline_autoclasssumm.py --- old/autodocsumm-0.1.13/docs/inline_autoclasssumm.py 1970-01-01 01:00:00.000000000 +0100 +++ new/autodocsumm-0.2.0/docs/inline_autoclasssumm.py 2020-08-21 23:20:13.000000000 +0200 @@ -0,0 +1,15 @@ +class MyClass(object): + """Some class + + .. autoclasssumm:: MyClass + :autosummary-sections: Methods + + This will be after the autosummary table. + """ + + def do_something(self): + """Do something""" + pass + + #: Any instance attribute + some_attr = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/setup.py new/autodocsumm-0.2.0/setup.py --- old/autodocsumm-0.1.13/setup.py 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/setup.py 2020-08-21 23:20:13.000000000 +0200 @@ -11,7 +11,7 @@ setup(name='autodocsumm', - version='0.1.13', + version='0.2.0', description='Extended sphinx autodoc including automatic autosummaries', long_description=readme(), long_description_content_type='text/x-rst', @@ -20,9 +20,8 @@ 'Intended Audience :: Developers', 'Topic :: Documentation', 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', @@ -36,7 +35,7 @@ license="GPLv2", packages=find_packages(exclude=['docs', 'tests*', 'examples']), install_requires=[ - 'sphinx', + 'sphinx>=2.2', ], setup_requires=pytest_runner, tests_require=['pytest', 'sphinx-testing'], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/dummy.py new/autodocsumm-0.2.0/tests/sphinx_supp/dummy.py --- old/autodocsumm-0.1.13/tests/sphinx_supp/dummy.py 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/dummy.py 2020-08-21 23:20:13.000000000 +0200 @@ -72,6 +72,19 @@ """Class test for inherited attributes""" +class TestClassWithInlineAutoClassSumm: + """Class test for the autodocsummary inline + + .. autoclasssumm:: TestClassWithInlineAutoClassSumm + + This is after the summary. + """ + + def test_method_of_inline_test(self): + """A test method.""" + pass + + #: data to be skipped large_data = 'Should also be skipped' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/index.rst new/autodocsumm-0.2.0/tests/sphinx_supp/index.rst --- old/autodocsumm-0.1.13/tests/sphinx_supp/index.rst 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/index.rst 2020-08-21 23:20:13.000000000 +0200 @@ -10,3 +10,8 @@ test_inherited test_module_title test_module_no_nesting + test_autoclasssumm + test_autoclasssumm_some_sections + test_autoclasssumm_no_titles + test_automodulesumm + test_automodulesumm_some_sections diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm.rst new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm.rst --- old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm.rst 2020-08-21 23:20:13.000000000 +0200 @@ -0,0 +1,4 @@ +Autoclasssumm of Dummy Class +============================ + +.. autoclasssumm:: dummy.TestClass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm_inline.rst new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm_inline.rst --- old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm_inline.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm_inline.rst 2020-08-21 23:20:13.000000000 +0200 @@ -0,0 +1,4 @@ +Inline Autoclasssumm of Dummy Class +=================================== + +.. autoclass:: dummy.TestClassWithInlineAutoClassSumm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm_no_titles.rst new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm_no_titles.rst --- old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm_no_titles.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm_no_titles.rst 2020-08-21 23:20:13.000000000 +0200 @@ -0,0 +1,5 @@ +Autoclasssumm of Dummy Class without section titles +=================================================== + +.. autoclasssumm:: dummy.TestClass + :autosummary-no-titles: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm_some_sections.rst new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm_some_sections.rst --- old/autodocsumm-0.1.13/tests/sphinx_supp/test_autoclasssumm_some_sections.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/test_autoclasssumm_some_sections.rst 2020-08-21 23:20:13.000000000 +0200 @@ -0,0 +1,5 @@ +Autoclasssumm of Dummy Class with some sections only +==================================================== + +.. autoclasssumm:: dummy.TestClass + :autosummary-sections: Attributes ;; DummySection diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/test_automodulesumm.rst new/autodocsumm-0.2.0/tests/sphinx_supp/test_automodulesumm.rst --- old/autodocsumm-0.1.13/tests/sphinx_supp/test_automodulesumm.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/test_automodulesumm.rst 2020-08-21 23:20:13.000000000 +0200 @@ -0,0 +1,4 @@ +Automodulesumm of dummy test module +=================================== + +.. automodulesumm:: dummy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/sphinx_supp/test_automodulesumm_some_sections.rst new/autodocsumm-0.2.0/tests/sphinx_supp/test_automodulesumm_some_sections.rst --- old/autodocsumm-0.1.13/tests/sphinx_supp/test_automodulesumm_some_sections.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/sphinx_supp/test_automodulesumm_some_sections.rst 2020-08-21 23:20:13.000000000 +0200 @@ -0,0 +1,5 @@ +Automodulesumm of dummy test module with some sections only +=========================================================== + +.. automodulesumm:: dummy + :autosummary-sections: Data ;; Functions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/autodocsumm-0.1.13/tests/test_autodocsumm.py new/autodocsumm-0.2.0/tests/test_autodocsumm.py --- old/autodocsumm-0.1.13/tests/test_autodocsumm.py 2020-03-05 09:52:58.000000000 +0100 +++ new/autodocsumm-0.2.0/tests/test_autodocsumm.py 2020-08-21 23:20:13.000000000 +0200 @@ -1,4 +1,5 @@ import sys +import re import os.path as osp import unittest from sphinx_testing import with_app @@ -118,7 +119,14 @@ app.build() html = get_html(app, '/test_class.html') - self.assertIn('<span class="pre">instance_attribute</span>', html) + if sphinx_version[:2] > [3, 1]: + self.assertIn( + '<span class="pre">instance_attribute</span>', + html) + elif sphinx_version[:2] < [3, 1]: + self.assertIn( + '<span class="pre">dummy.TestClass.instance_attribute</span>', + html) self.assertIn('<span class="pre">test_method</span>', html) self.assertIn('<span class="pre">test_attr</span>', html) @@ -158,7 +166,14 @@ app.build() html = get_html(app, '/test_class_summary_only.html') - self.assertIn('<span class="pre">instance_attribute</span>', html) + if sphinx_version[:2] > [3, 1]: + self.assertIn( + '<span class="pre">instance_attribute</span>', + html) + elif sphinx_version[:2] < [3, 1]: + self.assertIn( + '<span class="pre">dummy.TestClass.instance_attribute</span>', + html) self.assertIn('<span class="pre">test_method</span>', html) self.assertIn('<span class="pre">test_attr</span>', html) @@ -191,6 +206,111 @@ r'(?s).*Autosummary.warnings'): app.build() + @with_app(buildername='html', srcdir=sphinx_supp, + copy_srcdir_to_tmpdir=True) + def test_autoclasssumm_inline(self, app, status, warning): + """Test an AutoDocSummDirective inline.""" + app.build() + + html = get_html(app, '/test_autoclasssumm_inline.html') + + methods_title = "<strong>Methods:</strong>" + + num_section_findings = len(re.findall(methods_title, html)) + + self.assertEqual(num_section_findings, 1) + + methods_start = html.index(methods_title) + docstring_end = html.index("This is after the summary") + + self.assertGreater(docstring_end, methods_start) + + +class TestAutoDocSummDirective(unittest.TestCase): + """Test case for the :class:`autodocsumm.AutoDocSummDirective`.""" + + @with_app(buildername='html', srcdir=sphinx_supp, + copy_srcdir_to_tmpdir=True) + def test_autoclasssumm(self, app, status, warning): + """Test building the autosummary of a class.""" + app.build() + + html = get_html(app, '/test_autoclasssumm.html') + + # the class docstring must not be in the html + self.assertNotIn("Class test for autosummary", html) + + # test if the methods and attributes are there in a table + self.assertIn('<span class="pre">test_method</span>', html) + self.assertIn('<span class="pre">test_attr</span>', html) + + @with_app(buildername='html', srcdir=sphinx_supp, + copy_srcdir_to_tmpdir=True) + def test_autoclasssumm_no_titles(self, app, status, warning): + """Test building the autosummary of a class.""" + app.build() + + html = get_html(app, '/test_autoclasssumm_no_titles.html') + + # the class docstring must not be in the html + self.assertNotIn("Class test for autosummary", html) + + # test if the methods and attributes are there in a table + self.assertIn('<span class="pre">test_method</span>', html) + self.assertIn('<span class="pre">test_attr</span>', html) + + self.assertNotIn("<strong>Methods</strong>", html) + + @with_app(buildername='html', srcdir=sphinx_supp, + copy_srcdir_to_tmpdir=True) + def test_autoclasssumm_some_sections(self, app, status, warning): + """Test building the autosummary of a class with some sections only.""" + app.build() + + html = get_html(app, '/test_autoclasssumm_some_sections.html') + + # the class docstring must not be in the html + self.assertNotIn("Class test for autosummary", html) + + # test if the methods and attributes are there in a table + self.assertNotIn('<span class="pre">test_method</span>', html) + self.assertIn('<span class="pre">class_caller</span>', html) + self.assertIn('<span class="pre">test_attr</span>', html) + + @with_app(buildername='html', srcdir=sphinx_supp, + copy_srcdir_to_tmpdir=True) + def test_automodulesumm(self, app, status, warning): + """Test building the autosummary of a module.""" + app.build() + + html = get_html(app, '/test_automodulesumm.html') + + # the class docstring must not be in the html + self.assertNotIn("Module for testing the autodocsumm", html) + + # test if the classes, data and functions are there in a table + self.assertIn('<span class="pre">Class_CallTest</span>', html) + self.assertIn('<span class="pre">large_data</span>', html) + self.assertIn('<span class="pre">test_func</span>', html) + + @with_app(buildername='html', srcdir=sphinx_supp, + copy_srcdir_to_tmpdir=True) + def test_automodulesumm_some_sections(self, app, status, warning): + """Test building the autosummary of a module with some sections only.""" + app.build() + + html = get_html(app, '/test_automodulesumm_some_sections.html') + + # the class docstring must not be in the html + self.assertNotIn("Module for testing the autodocsumm", html) + + # test if the classes, data and functions are there in a table + self.assertNotIn('<span class="pre">Class_CallTest</span>', html) + self.assertIn('<span class="pre">large_data</span>', html) + self.assertIn('<span class="pre">test_func</span>', html) + + + if __name__ == '__main__': unittest.main()
