Add static method support.

This commit is contained in:
Georg Brandl 2008-06-23 12:04:56 +00:00
parent 1cafce9101
commit 8b0f48a38b
8 changed files with 80 additions and 8 deletions

View File

@ -13,6 +13,9 @@ New features added
* 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

View File

@ -199,6 +199,12 @@ The directives are:
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

View File

@ -23,7 +23,7 @@ class desc(nodes.Admonition, nodes.Element): pass
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
@ -36,6 +36,8 @@ class desc_optional(nodes.Part, nodes.Inline, nodes.TextElement):
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

View File

@ -45,6 +45,18 @@ def desc_index_text(desctype, module, name):
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)
@ -91,6 +103,8 @@ doc_fields_with_arg = {
'var': 'Variable',
'ivar': 'Variable',
'cvar': 'Variable',
'returns': 'Returns',
'return': 'Returns',
}
doc_fields_without_arg = {
@ -140,7 +154,7 @@ def handle_doc_fields(node):
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()
@ -199,6 +213,9 @@ def parse_py_signature(signode, sig, desctype, module, env):
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
@ -210,7 +227,7 @@ def parse_py_signature(signode, sig, desctype, module, env):
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
@ -383,7 +400,7 @@ def desc_directive(desctype, arguments, options, content, lineno,
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)
@ -457,7 +474,8 @@ def desc_directive(desctype, arguments, options, content, lineno,
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
@ -482,6 +500,7 @@ desctypes = [
'data',
'class',
'method',
'staticmethod',
'attribute',
'exception',
# the C ones

View File

@ -254,7 +254,6 @@ def format_signature(what, obj):
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

View File

@ -113,6 +113,11 @@ class HTMLTranslator(BaseTranslator):
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):

View File

@ -86,7 +86,7 @@ class Desc(object):
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
@ -284,6 +284,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'function' : 'funcdesc',
'class': 'classdesc',
'method': 'methoddesc',
'staticmethod': 'staticmethoddesc',
'exception': 'excdesc',
'data': 'datadesc',
'attribute': 'memberdesc',
@ -325,7 +326,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
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:
@ -390,6 +391,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
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):

View File

@ -572,6 +572,35 @@
\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]{%