Remove almost empty sphinx.directives.desc module.

This commit is contained in:
Georg Brandl 2009-09-07 22:57:46 +02:00
parent fa7f8812cd
commit 9101593b01
2 changed files with 265 additions and 277 deletions

View File

@ -9,11 +9,17 @@
:license: BSD, see LICENSE for details.
"""
import re
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.parsers.rst.directives import images
from sphinx import addnodes
from sphinx.locale import l_
from sphinx.util.compat import Directive, directive_dwim
# import and register directives
from sphinx.directives.desc import *
from sphinx.directives.code import *
from sphinx.directives.other import *
@ -25,3 +31,261 @@ try:
except AttributeError:
images.figure.options['figwidth'] = \
directives.length_or_percentage_or_unitless
def _is_only_paragraph(node):
"""True if the node only contains one paragraph (and system messages)."""
if len(node) == 0:
return False
elif len(node) > 1:
for subnode in node[1:]:
if not isinstance(subnode, nodes.system_message):
return False
if isinstance(node[0], nodes.paragraph):
return True
return False
# RE to strip backslash escapes
strip_backslash_re = re.compile(r'\\(?=[^\\])')
class ObjectDescription(Directive):
"""
Directive to describe a class, function or similar object. Not used
directly, but subclassed to add custom behavior.
"""
has_content = True
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {
'noindex': directives.flag,
'module': directives.unchanged,
}
doc_fields_with_arg = {
'param': '%param',
'parameter': '%param',
'arg': '%param',
'argument': '%param',
'keyword': '%param',
'kwarg': '%param',
'kwparam': '%param',
'type': '%type',
'raises': l_('Raises'),
'raise': l_('Raises'),
'exception': l_('Raises'),
'except': l_('Raises'),
'var': l_('Variable'),
'ivar': l_('Variable'),
'cvar': l_('Variable'),
'returns': l_('Returns'),
'return': l_('Returns'),
}
doc_fields_with_linked_arg = ('raises', 'raise', 'exception', 'except')
doc_fields_without_arg = {
'returns': l_('Returns'),
'return': l_('Returns'),
'rtype': l_('Return type'),
}
def handle_doc_fields(self, node):
"""
Convert field lists with known keys inside the description content into
better-looking equivalents.
"""
# don't traverse, only handle field lists that are immediate children
for child in node.children:
if not isinstance(child, nodes.field_list):
continue
params = []
pfield = None
param_nodes = {}
param_types = {}
new_list = nodes.field_list()
for field in child:
fname, fbody = field
try:
typ, obj = fname.astext().split(None, 1)
typdesc = self.doc_fields_with_arg[typ]
if _is_only_paragraph(fbody):
children = fbody.children[0].children
else:
children = fbody.children
if typdesc == '%param':
if not params:
# add the field that later gets all the parameters
pfield = nodes.field()
new_list += pfield
dlitem = nodes.list_item()
dlpar = nodes.paragraph()
dlpar += nodes.emphasis(obj, obj)
dlpar += nodes.Text(' -- ', ' -- ')
dlpar += children
param_nodes[obj] = dlpar
dlitem += dlpar
params.append(dlitem)
elif typdesc == '%type':
typenodes = fbody.children
if _is_only_paragraph(fbody):
typenodes = ([nodes.Text(' (')] +
typenodes[0].children +
[nodes.Text(')')])
param_types[obj] = typenodes
else:
fieldname = typdesc + ' '
nfield = nodes.field()
nfieldname = nodes.field_name(fieldname, fieldname)
nfield += nfieldname
node = nfieldname
if typ in self.doc_fields_with_linked_arg:
# XXX currmodule/currclass
node = addnodes.pending_xref(
obj, reftype='obj', refcaption=False,
reftarget=obj)
#, modname=self.env.currmodule
#, classname=self.env.currclass
nfieldname += node
node += nodes.Text(obj, obj)
nfield += nodes.field_body()
nfield[1] += fbody.children
new_list += nfield
except (KeyError, ValueError):
fnametext = fname.astext()
try:
typ = self.doc_fields_without_arg[fnametext]
except KeyError:
# at least capitalize the field name
typ = fnametext.capitalize()
fname[0] = nodes.Text(typ)
new_list += field
if params:
if len(params) == 1:
pfield += nodes.field_name('', _('Parameter'))
pfield += nodes.field_body()
pfield[1] += params[0][0]
else:
pfield += nodes.field_name('', _('Parameters'))
pfield += nodes.field_body()
pfield[1] += nodes.bullet_list()
pfield[1][0].extend(params)
for param, type in param_types.iteritems():
if param in param_nodes:
param_nodes[param][1:1] = type
child.replace_self(new_list)
def get_signatures(self):
"""
Retrieve the signatures to document from the directive arguments.
"""
# remove backslashes to support (dummy) escapes; helps Vim highlighting
return [strip_backslash_re.sub('', sig.strip())
for sig in self.arguments[0].split('\n')]
def parse_signature(self, sig, signode):
"""
Parse the signature *sig* into individual nodes and append them to
*signode*. If ValueError is raised, parsing is aborted and the whole
*sig* is put into a single desc_name node.
"""
raise ValueError
def add_target_and_index(self, name, sig, signode):
"""
Add cross-reference IDs and entries to self.indexnode, if applicable.
"""
return # do nothing by default
def before_content(self):
"""
Called before parsing content. Used to set information about the current
directive context on the build environment.
"""
pass
def after_content(self):
"""
Called after parsing content. Used to reset information about the
current directive context on the build environment.
"""
pass
def run(self):
if ':' in self.name:
self.domain, self.objtype = self.name.split(':', 1)
else:
self.domain, self.objtype = '', self.name
self.env = self.state.document.settings.env
self.indexnode = addnodes.index(entries=[])
node = addnodes.desc()
node.document = self.state.document
node['domain'] = self.domain
# 'desctype' is a backwards compatible attribute
node['objtype'] = node['desctype'] = self.objtype
node['noindex'] = noindex = ('noindex' in self.options)
self.names = []
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
# add a signature node for each signature in the current unit
# and add a reference target for it
signode = addnodes.desc_signature(sig, '')
signode['first'] = False
node.append(signode)
try:
# name can also be a tuple, e.g. (classname, objname)
name = self.parse_signature(sig, signode)
except ValueError, err:
# signature parsing failed
signode.clear()
signode += addnodes.desc_name(sig, sig)
continue # we don't want an index entry here
if not noindex and name not in self.names:
# only add target and index entry if this is the first
# description of the object with this name in this desc block
self.names.append(name)
self.add_target_and_index(name, sig, signode)
contentnode = addnodes.desc_content()
node.append(contentnode)
if self.names:
# needed for association of version{added,changed} directives
self.env.doc_read_data['object'] = self.names[0]
self.before_content()
self.state.nested_parse(self.content, self.content_offset, contentnode)
self.handle_doc_fields(contentnode)
self.env.doc_read_data['object'] = None
self.after_content()
return [self.indexnode, node]
# backwards compatible old name
DescDirective = ObjectDescription
class DefaultDomain(Directive):
"""
Directive to (re-)set the default domain for this source file.
"""
has_content = False
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = False
option_spec = {}
def run(self):
env = self.state.document.settings.env
domain_name = arguments[0]
env.default_domain = env.domains.get(domain_name)
directives.register_directive('default-domain', directive_dwim(DefaultDomain))
directives.register_directive('describe', directive_dwim(ObjectDescription))
# new, more consistent, name
directives.register_directive('object', directive_dwim(ObjectDescription))

View File

@ -1,276 +0,0 @@
# -*- coding: utf-8 -*-
"""
sphinx.directives.desc
~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import re
import string
from docutils import nodes
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.locale import l_
from sphinx.util.compat import Directive, directive_dwim
def _is_only_paragraph(node):
"""True if the node only contains one paragraph (and system messages)."""
if len(node) == 0:
return False
elif len(node) > 1:
for subnode in node[1:]:
if not isinstance(subnode, nodes.system_message):
return False
if isinstance(node[0], nodes.paragraph):
return True
return False
# RE to strip backslash escapes
strip_backslash_re = re.compile(r'\\(?=[^\\])')
class ObjectDescription(Directive):
"""
Directive to describe a class, function or similar object. Not used
directly, but subclassed to add custom behavior.
"""
has_content = True
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {
'noindex': directives.flag,
'module': directives.unchanged,
}
doc_fields_with_arg = {
'param': '%param',
'parameter': '%param',
'arg': '%param',
'argument': '%param',
'keyword': '%param',
'kwarg': '%param',
'kwparam': '%param',
'type': '%type',
'raises': l_('Raises'),
'raise': l_('Raises'),
'exception': l_('Raises'),
'except': l_('Raises'),
'var': l_('Variable'),
'ivar': l_('Variable'),
'cvar': l_('Variable'),
'returns': l_('Returns'),
'return': l_('Returns'),
}
doc_fields_with_linked_arg = ('raises', 'raise', 'exception', 'except')
doc_fields_without_arg = {
'returns': l_('Returns'),
'return': l_('Returns'),
'rtype': l_('Return type'),
}
def handle_doc_fields(self, node):
"""
Convert field lists with known keys inside the description content into
better-looking equivalents.
"""
# don't traverse, only handle field lists that are immediate children
for child in node.children:
if not isinstance(child, nodes.field_list):
continue
params = []
pfield = None
param_nodes = {}
param_types = {}
new_list = nodes.field_list()
for field in child:
fname, fbody = field
try:
typ, obj = fname.astext().split(None, 1)
typdesc = self.doc_fields_with_arg[typ]
if _is_only_paragraph(fbody):
children = fbody.children[0].children
else:
children = fbody.children
if typdesc == '%param':
if not params:
# add the field that later gets all the parameters
pfield = nodes.field()
new_list += pfield
dlitem = nodes.list_item()
dlpar = nodes.paragraph()
dlpar += nodes.emphasis(obj, obj)
dlpar += nodes.Text(' -- ', ' -- ')
dlpar += children
param_nodes[obj] = dlpar
dlitem += dlpar
params.append(dlitem)
elif typdesc == '%type':
typenodes = fbody.children
if _is_only_paragraph(fbody):
typenodes = ([nodes.Text(' (')] +
typenodes[0].children +
[nodes.Text(')')])
param_types[obj] = typenodes
else:
fieldname = typdesc + ' '
nfield = nodes.field()
nfieldname = nodes.field_name(fieldname, fieldname)
nfield += nfieldname
node = nfieldname
if typ in self.doc_fields_with_linked_arg:
# XXX currmodule/currclass
node = addnodes.pending_xref(
obj, reftype='obj', refcaption=False,
reftarget=obj)
#, modname=self.env.currmodule
#, classname=self.env.currclass
nfieldname += node
node += nodes.Text(obj, obj)
nfield += nodes.field_body()
nfield[1] += fbody.children
new_list += nfield
except (KeyError, ValueError):
fnametext = fname.astext()
try:
typ = self.doc_fields_without_arg[fnametext]
except KeyError:
# at least capitalize the field name
typ = fnametext.capitalize()
fname[0] = nodes.Text(typ)
new_list += field
if params:
if len(params) == 1:
pfield += nodes.field_name('', _('Parameter'))
pfield += nodes.field_body()
pfield[1] += params[0][0]
else:
pfield += nodes.field_name('', _('Parameters'))
pfield += nodes.field_body()
pfield[1] += nodes.bullet_list()
pfield[1][0].extend(params)
for param, type in param_types.iteritems():
if param in param_nodes:
param_nodes[param][1:1] = type
child.replace_self(new_list)
def get_signatures(self):
"""
Retrieve the signatures to document from the directive arguments.
"""
# remove backslashes to support (dummy) escapes; helps Vim highlighting
return [strip_backslash_re.sub('', sig.strip())
for sig in self.arguments[0].split('\n')]
def parse_signature(self, sig, signode):
"""
Parse the signature *sig* into individual nodes and append them to
*signode*. If ValueError is raised, parsing is aborted and the whole
*sig* is put into a single desc_name node.
"""
raise ValueError
def add_target_and_index(self, name, sig, signode):
"""
Add cross-reference IDs and entries to self.indexnode, if applicable.
"""
return # do nothing by default
def before_content(self):
"""
Called before parsing content. Used to set information about the current
directive context on the build environment.
"""
pass
def after_content(self):
"""
Called after parsing content. Used to reset information about the
current directive context on the build environment.
"""
pass
def run(self):
if ':' in self.name:
self.domain, self.objtype = self.name.split(':', 1)
else:
self.domain, self.objtype = '', self.name
self.env = self.state.document.settings.env
self.indexnode = addnodes.index(entries=[])
node = addnodes.desc()
node.document = self.state.document
node['domain'] = self.domain
# 'desctype' is a backwards compatible attribute
node['objtype'] = node['desctype'] = self.objtype
node['noindex'] = noindex = ('noindex' in self.options)
self.names = []
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
# add a signature node for each signature in the current unit
# and add a reference target for it
signode = addnodes.desc_signature(sig, '')
signode['first'] = False
node.append(signode)
try:
# name can also be a tuple, e.g. (classname, objname)
name = self.parse_signature(sig, signode)
except ValueError, err:
# signature parsing failed
signode.clear()
signode += addnodes.desc_name(sig, sig)
continue # we don't want an index entry here
if not noindex and name not in self.names:
# only add target and index entry if this is the first
# description of the object with this name in this desc block
self.names.append(name)
self.add_target_and_index(name, sig, signode)
contentnode = addnodes.desc_content()
node.append(contentnode)
if self.names:
# needed for association of version{added,changed} directives
self.env.doc_read_data['object'] = self.names[0]
self.before_content()
self.state.nested_parse(self.content, self.content_offset, contentnode)
self.handle_doc_fields(contentnode)
self.env.doc_read_data['object'] = None
self.after_content()
return [self.indexnode, node]
# backwards compatible old name
DescDirective = ObjectDescription
class DefaultDomain(Directive):
"""
Directive to (re-)set the default domain for this source file.
"""
has_content = False
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = False
option_spec = {}
def run(self):
env = self.state.document.settings.env
domain_name = arguments[0]
env.default_domain = env.domains.get(domain_name)
directives.register_directive('default-domain', directive_dwim(DefaultDomain))
directives.register_directive('describe', directive_dwim(ObjectDescription))
# new, more consistent, name
directives.register_directive('object', directive_dwim(ObjectDescription))