Ticket #8244: trac_8244-conf-autodoc.patch

File trac_8244-conf-autodoc.patch, 11.6 KB (added by jhpalmieri, 11 years ago)

apply on top of other patch

  • doc/common/conf.py

    # HG changeset patch
    # User J. H. Palmieri <palmieri@math.washington.edu>
    # Date 1266614491 28800
    # Node ID 23f8091165aac046a4c57991e7c3667cec78c2d8
    # Parent  0866a6715cb2778990ad8a4b3920c7e9914c1783
    trac #8244: conf, autodoc patches
    
    diff -r 0866a6715cb2 -r 23f8091165aa doc/common/conf.py
    a b  
    66# is relative to the documentation root, use os.path.abspath to make it
    77# absolute, like shown here.
    88#sys.path.append(os.path.abspath('.'))
     9sys.path.append(os.path.abspath(os.path.join(SAGE_DOC, 'common')))
    910
    1011# General configuration
    1112# ---------------------
    1213
    1314# Add any Sphinx extension module names here, as strings. They can be extensions
    1415# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
    15 extensions = ['sphinx.ext.autodoc']
     16extensions = ['sage_autodoc']
    1617
    1718if 'SAGE_DOC_JSMATH' in os.environ:
    1819    extensions.append('sphinx.ext.jsmath')
     
    292293    sage.misc.misc.)  Otherwise, abide by Sphinx's decision.
    293294    """
    294295    skip_nested = str(obj).find("sage.misc.misc") != -1 and name.find("MainClass.NestedClass") != -1
    295     return skip or skip_nested
    296        
     296    skip_download_worksheets = name.find("userchild_download_worksheets.zip") != -1
     297    return skip or skip_nested or skip_download_worksheets
     298
    297299def process_dollars(app, what, name, obj, options, docstringlines):
    298300    r"""
    299301    Replace dollar signs with backticks.
    300302    See sage.misc.sagedoc.process_dollars for more information
    301303    """
    302     if len(docstringlines) > 0:
     304    if len(docstringlines) > 0 and name.find("process_dollars") == -1:
    303305        from sage.misc.sagedoc import process_dollars as sagedoc_dollars
    304306        s = sagedoc_dollars("\n".join(docstringlines))
    305307        lines = s.split("\n")
     
    311313    Replace \mathtt{BLAH} with \verb|BLAH| if using jsMath.
    312314    See sage.misc.sagedoc.process_mathtt for more information
    313315    """
    314     if len(docstringlines) > 0 and 'SAGE_DOC_JSMATH' in os.environ:
     316    if (len(docstringlines) > 0 and 'SAGE_DOC_JSMATH' in os.environ
     317        and name.find("process_mathtt") == -1):
    315318        from sage.misc.sagedoc import process_mathtt as sagedoc_mathtt
    316319        s = sagedoc_mathtt("\n".join(docstringlines), True)
    317320        lines = s.split("\n")
  • new file doc/common/sage_autodoc.py

    diff -r 0866a6715cb2 -r 23f8091165aa doc/common/sage_autodoc.py
    - +  
     1# -*- coding: utf-8 -*-
     2"""
     3    sage_autodoc
     4    ~~~~~~~~~~~~
     5
     6    Derived from sphinx.ext.autodoc:
     7
     8    Automatically insert docstrings for functions, classes or whole modules into
     9    the doctree, thus avoiding duplication between docstrings and documentation
     10    for those who like elaborate docstrings.
     11"""
     12
     13from sphinx.ext.autodoc import *
     14
     15class FunctionDocumenter(ModuleLevelDocumenter):
     16    """
     17    Specialized Documenter subclass for functions.
     18    """
     19    objtype = 'function'
     20    member_order = 30
     21
     22    @classmethod
     23    def can_document_member(cls, member, membername, isattr, parent):
     24        return isinstance(member, (FunctionType, BuiltinFunctionType))
     25
     26    def format_args(self):
     27        if inspect.isbuiltin(self.object) or \
     28               inspect.ismethoddescriptor(self.object):
     29            # can never get arguments of a C function or method unless
     30            # a function to do so is supplied
     31            if self.env.config.autodoc_builtin_argspec:
     32                argspec = self.env.config.autodoc_builtin_argspec(self.object)
     33                return inspect.formatargspec(*argspec)
     34            else:
     35                return None
     36        try:
     37            argspec = inspect.getargspec(self.object)
     38        except TypeError:
     39            # if a class should be documented as function (yay duck
     40            # typing) we try to use the constructor signature as function
     41            # signature without the first argument.
     42            try:
     43                argspec = inspect.getargspec(self.object.__new__)
     44            except TypeError:
     45                argspec = inspect.getargspec(self.object.__init__)
     46                if argspec[0]:
     47                    del argspec[0][0]
     48        return inspect.formatargspec(*argspec)
     49
     50    def document_members(self, all_members=False):
     51        pass
     52
     53class ClassDocumenter(ModuleLevelDocumenter):
     54    """
     55    Specialized Documenter subclass for classes.
     56    """
     57    objtype = 'class'
     58    member_order = 20
     59    option_spec = {
     60        'members': members_option, 'undoc-members': bool_option,
     61        'noindex': bool_option, 'inherited-members': bool_option,
     62        'show-inheritance': bool_option, 'member-order': identity,
     63        'exclude-members': members_set_option,
     64    }
     65
     66    @classmethod
     67    def can_document_member(cls, member, membername, isattr, parent):
     68        return isinstance(member, (type, ClassType))
     69
     70    def import_object(self):
     71        ret = ModuleLevelDocumenter.import_object(self)
     72        # if the class is documented under another name, document it
     73        # as data/attribute
     74        if ret:
     75            if hasattr(self.object, '__name__'):
     76                self.doc_as_attr = (self.objpath[-1] != self.object.__name__)
     77            else:
     78                self.doc_as_attr = True
     79        return ret
     80
     81    def format_args(self):
     82        args = None
     83        # for classes, the relevant signature is the __init__ method's
     84        initmeth = self.get_attr(self.object, '__init__', None)
     85        # classes without __init__ method, default __init__ or
     86        # __init__ written in C?
     87        if initmeth is None or initmeth is object.__init__ or not \
     88               (inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
     89            return None
     90        try:
     91            argspec = inspect.getargspec(initmeth)
     92        except TypeError:
     93            # still not possible: happens e.g. for old-style classes
     94            # with __init__ in C
     95            return None
     96        if argspec[0] and argspec[0][0] in ('cls', 'self'):
     97            del argspec[0][0]
     98        return inspect.formatargspec(*argspec)
     99
     100    def format_signature(self):
     101        if self.doc_as_attr:
     102            return ''
     103        return ModuleLevelDocumenter.format_signature(self)
     104
     105    def add_directive_header(self, sig):
     106        if self.doc_as_attr:
     107            self.directivetype = 'attribute'
     108        Documenter.add_directive_header(self, sig)
     109
     110        # add inheritance info, if wanted
     111        if not self.doc_as_attr and self.options.show_inheritance:
     112            self.add_line(u'', '<autodoc>')
     113            if len(self.object.__bases__):
     114                bases = [b.__module__ == '__builtin__' and
     115                         u':class:`%s`' % b.__name__ or
     116                         u':class:`%s.%s`' % (b.__module__, b.__name__)
     117                         for b in self.object.__bases__]
     118                self.add_line(_(u'   Bases: %s') % ', '.join(bases),
     119                              '<autodoc>')
     120
     121    def get_doc(self, encoding=None):
     122        content = self.env.config.autoclass_content
     123
     124        docstrings = []
     125        docstring = self.get_attr(self.object, '__doc__', None)
     126        if docstring:
     127            docstrings.append(docstring)
     128
     129        # for classes, what the "docstring" is can be controlled via a
     130        # config value; the default is only the class docstring
     131        if content in ('both', 'init'):
     132            initdocstring = self.get_attr(
     133                self.get_attr(self.object, '__init__', None), '__doc__')
     134            # for new-style classes, no __init__ means default __init__
     135            if initdocstring == object.__init__.__doc__:
     136                initdocstring = None
     137            if initdocstring:
     138                if content == 'init':
     139                    docstrings = [initdocstring]
     140                else:
     141                    docstrings.append(initdocstring)
     142
     143        return [prepare_docstring(force_decode(docstring, encoding))
     144                for docstring in docstrings]
     145
     146    def add_content(self, more_content, no_docstring=False):
     147        if self.doc_as_attr:
     148            classname = safe_getattr(self.object, '__name__', None)
     149            if classname:
     150                content = ViewList(
     151                    [_('alias of :class:`%s`') % classname], source='')
     152                ModuleLevelDocumenter.add_content(self, content,
     153                                                  no_docstring=True)
     154        else:
     155            ModuleLevelDocumenter.add_content(self, more_content)
     156
     157    def document_members(self, all_members=False):
     158        if self.doc_as_attr:
     159            return
     160        ModuleLevelDocumenter.document_members(self, all_members)
     161
     162class MethodDocumenter(ClassLevelDocumenter):
     163    """
     164    Specialized Documenter subclass for methods (normal, static and class).
     165    """
     166    objtype = 'method'
     167    member_order = 50
     168
     169    @classmethod
     170    def can_document_member(cls, member, membername, isattr, parent):
     171        # other attributes are recognized via the module analyzer
     172        return inspect.isroutine(member) and \
     173               not isinstance(parent, ModuleDocumenter)
     174
     175    def import_object(self):
     176        ret = ClassLevelDocumenter.import_object(self)
     177        if isinstance(self.object, classmethod) or \
     178               (isinstance(self.object, MethodType) and
     179                self.object.im_self is not None):
     180            self.directivetype = 'classmethod'
     181            # document class and static members before ordinary ones
     182            self.member_order = self.member_order - 1
     183        elif isinstance(self.object, FunctionType) or \
     184             (isinstance(self.object, BuiltinFunctionType) and
     185              self.object.__self__ is not None):
     186            self.directivetype = 'staticmethod'
     187            # document class and static members before ordinary ones
     188            self.member_order = self.member_order - 1
     189        else:
     190            self.directivetype = 'method'
     191        return ret
     192
     193    def format_args(self):
     194        if inspect.isbuiltin(self.object) or \
     195               inspect.ismethoddescriptor(self.object):
     196            # can never get arguments of a C function or method unless
     197            # a function to do so is supplied
     198            if self.env.config.autodoc_builtin_argspec:
     199                argspec = self.env.config.autodoc_builtin_argspec(self.object)
     200            else:
     201                return None
     202        else:
     203            # The check above misses ordinary Python methods in Cython
     204            # files.
     205            try:
     206                argspec = inspect.getargspec(self.object)
     207            except TypeError:
     208                if (inspect.ismethod(self.object) and 
     209                    self.env.config.autodoc_builtin_argspec):
     210                    argspec = self.env.config.autodoc_builtin_argspec(self.object.im_func)
     211                else:
     212                    return None
     213        if argspec[0] and argspec[0][0] in ('cls', 'self'):
     214            del argspec[0][0]
     215        return inspect.formatargspec(*argspec)
     216
     217    def document_members(self, all_members=False):
     218        pass
     219
     220def setup(app):
     221    app.add_autodocumenter(ModuleDocumenter)
     222    app.add_autodocumenter(ClassDocumenter)
     223    app.add_autodocumenter(ExceptionDocumenter)
     224    app.add_autodocumenter(DataDocumenter)
     225    app.add_autodocumenter(FunctionDocumenter)
     226    app.add_autodocumenter(MethodDocumenter)
     227    app.add_autodocumenter(AttributeDocumenter)
     228
     229    app.add_config_value('autoclass_content', 'class', True)
     230    app.add_config_value('autodoc_member_order', 'alphabetic', True)
     231    app.add_config_value('autodoc_builtin_argspec', None, True)
     232    app.add_event('autodoc-process-docstring')
     233    app.add_event('autodoc-process-signature')
     234    app.add_event('autodoc-skip-member')