Commits

georg.brandl  committed d87f6b3

Add static method support.

  • Participants
  • Parent commits b9522ac

Comments (0)

Files changed (8)

 * Sphinx now interprets field lists with fields like ``:param foo:``
   in description units.
 
+* The new `staticmethod` directive can be used to mark methods as
+  static methods.
+  
 * HTML output:
 
   - The "previous" and "next" links have a more logical structure, so

File doc/markup/desc.rst

    parameter.  The description should include similar information to that
    described for ``function``.  See also :ref:`signatures`.
 
+.. directive:: .. staticmethod:: name(signature)
+
+   Like :dir:`method`, but indicates that the method is a static method.
+
+   .. versionadded:: 0.4
+   
 .. directive:: .. opcode:: name
 
    Describes a Python bytecode instruction (this is not very useful for projects

File sphinx/addnodes.py

 class desc_addname(nodes.Part, nodes.Inline, nodes.TextElement): pass
 # compatibility alias
 desc_classname = desc_addname
-# return type (C), object type (Python)
+# return type (C); object type, e.g. -> annotation (Python)
 class desc_type(nodes.Part, nodes.Inline, nodes.TextElement): pass
 # main name of object
 class desc_name(nodes.Part, nodes.Inline, nodes.TextElement): pass
     child_text_separator = ', '
     def astext(self):
         return '[' + nodes.TextElement.astext(self) + ']'
+# annotation (not Python 3-style annotations)
+class desc_annotation(nodes.Part, nodes.Inline, nodes.TextElement): pass
 
 # node for content
 class desc_content(nodes.General, nodes.Element): pass

File sphinx/directives/desc.py

             return '%s() (%s.%s method)' % (methname, module, clsname)
         else:
             return '%s() (%s method)' % (methname, clsname)
+    elif desctype == 'staticmethod':
+        try:
+            clsname, methname = name.rsplit('.', 1)
+        except ValueError:
+            if module:
+                return '%s() (in module %s)' % (name, module)
+            else:
+                return '%s()' % name
+        if module:
+            return '%s() (%s.%s static method)' % (methname, module, clsname)
+        else:
+            return '%s() (%s static method)' % (methname, clsname)
     elif desctype == 'attribute':
         try:
             clsname, attrname = name.rsplit('.', 1)
     'var': 'Variable',
     'ivar': 'Variable',
     'cvar': 'Variable',
+    'returns': 'Returns',
+    'return': 'Returns',
 }
 
 doc_fields_without_arg = {
                     nfield = nodes.field()
                     nfield += nodes.field_name(typ, typ)
                     nfield += nodes.field_body()
-                    nfield[1] += children
+                    nfield[1] += fbody.children
                     new_list += nfield
             except (KeyError, ValueError):
                 fnametext = fname.astext()
         add_module = True
         fullname = classname and classname + name or name
 
+    if desctype == 'staticmethod':
+        signode += addnodes.desc_annotation('static ', 'static ')
+
     if classname:
         signode += addnodes.desc_addname(classname, classname)
     # exceptions are a special case, since they are documented in the
 
     signode += addnodes.desc_name(name, name)
     if not arglist:
-        if desctype in ('function', 'method'):
+        if desctype in ('function', 'method', 'staticmethod'):
             # for callables, add an empty parameter list
             signode += addnodes.desc_parameterlist()
         return fullname, classname
         node.append(signode)
         try:
             if desctype in ('function', 'data', 'class', 'exception',
-                            'method', 'attribute'):
+                            'method', 'staticmethod', 'attribute'):
                 name, clsname = parse_py_signature(signode, sig, desctype, module, env)
             elif desctype in ('cfunction', 'cmember', 'cmacro', 'ctype', 'cvar'):
                 name = parse_c_signature(signode, sig, desctype)
     if desctype in ('class', 'exception') and names:
         env.currclass = names[0]
         clsname_set = True
-    elif desctype in ('method', 'attribute') and clsname and not env.currclass:
+    elif desctype in ('method', 'staticmethod', 'attribute') and \
+             clsname and not env.currclass:
         env.currclass = clsname.strip('.')
         clsname_set = True
     # needed for association of version{added,changed} directives
     'data',
     'class',
     'method',
+    'staticmethod',
     'attribute',
     'exception',
     # the C ones

File sphinx/ext/autodoc.py

 def generate_rst(what, name, members, options, add_content, document, lineno,
                  indent=u'', filename_set=None, check_module=False):
     env = document.settings.env
-    is_static = False
 
     result = None
 

File sphinx/htmlwriter.py

     def depart_desc_optional(self, node):
         self.body.append('<span class="optional">]</span>')
 
+    def visit_desc_annotation(self, node):
+        self.body.append(self.starttag(node, 'em', CLASS='property'))
+    def depart_desc_annotation(self, node):
+        self.body.append('</em>')
+
     def visit_desc_content(self, node):
         self.body.append(self.starttag(node, 'dd', ''))
     def depart_desc_content(self, node):

File sphinx/latexwriter.py

     def __init__(self, node):
         self.env = LaTeXTranslator.desc_map.get(node['desctype'], 'describe')
         self.ni = node['noindex']
-        self.type = self.cls = self.name = self.params = ''
+        self.type = self.cls = self.name = self.params = self.annotation = ''
         self.count = 0
 
 
         'function' : 'funcdesc',
         'class': 'classdesc',
         'method': 'methoddesc',
+        'staticmethod': 'staticmethoddesc',
         'exception': 'excdesc',
         'data': 'datadesc',
         'attribute': 'memberdesc',
             t2 = "{%s}{%s}" % (d.name, d.params)
         elif d.env in ('datadesc', 'classdesc*', 'excdesc', 'csimplemacrodesc'):
             t2 = "{%s}" % (d.name)
-        elif d.env == 'methoddesc':
+        elif d.env in ('methoddesc', 'staticmethoddesc'):
             if d.cls:
                 t2 = "[%s]{%s}{%s}" % (d.cls, d.name, d.params)
             else:
             self.descstack[-1].params = self.encode(node.astext().strip())
         raise nodes.SkipNode
 
+    def visit_desc_annotation(self, node):
+        d = self.descstack[-1]
+        if d.env == 'describe':
+            d.name += self.encode(node.astext())
+        else:
+            self.descstack[-1].annotation = self.encode(node.astext().strip())
+        raise nodes.SkipNode
+
     def visit_refcount(self, node):
         self.body.append("\\emph{")
     def depart_refcount(self, node):

File sphinx/texinputs/sphinx.sty

     \methodlineni{#2}{#3}
 }{\end{fulllineitems}}
 
+% static method ----------------------------------------------------------
+% \begin{staticmethoddesc}[classname]{methodname}{args}
+\newcommand{\staticmethodline}[3][\@undefined]{
+  \staticmethodlineni{#2}{#3}
+  \ifx\@undefined#1\relax
+    \index{#2@{\py@idxcode{#2()}} (\py@thisclass\ static method)}
+  \else
+    \index{#2@{\py@idxcode{#2()}} (#1 static method)}
+  \fi
+}
+\newenvironment{staticmethoddesc}[3][\@undefined]{
+  \begin{fulllineitems}
+    \ifx\@undefined#1\relax
+      \staticmethodline{#2}{#3}
+    \else
+      \def\py@thisclass{#1}
+      \staticmethodline{#2}{#3}
+    \fi
+}{\end{fulllineitems}}
+
+% similar to {staticmethoddesc}, but doesn't add to the index
+% (never actually uses the optional argument)
+\newcommand{\staticmethodlineni}[3][\py@classbadkey]{%
+  \py@sigline{static \bfcode{#2}}{#3}}
+\newenvironment{staticmethoddescni}[3][\py@classbadkey]{
+  \begin{fulllineitems}
+    \staticmethodlineni{#2}{#3}
+}{\end{fulllineitems}}
+
 % object data attribute --------------------------------------------------
 % \begin{memberdesc}[classname]{membername}
 \newcommand{\memberline}[2][\py@classbadkey]{%