Allow a leading dot in x-reference roles, marking reversed search order for targets.

This commit is contained in:
Georg Brandl
2007-08-15 18:05:01 +00:00
parent 2192e92ec9
commit 11cab438b8
3 changed files with 48 additions and 22 deletions

View File

@@ -116,7 +116,7 @@ py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
def parse_py_signature(signode, sig, desctype, env): def parse_py_signature(signode, sig, desctype, env):
""" """
Transform a python signature into RST nodes. Transform a python signature into RST nodes.
Return the fully qualified name of the thing. Return (fully qualified name of the thing, classname if any).
If inside a class, the current class name is handled intelligently: If inside a class, the current class name is handled intelligently:
* it is stripped from the displayed name if present * it is stripped from the displayed name if present
@@ -153,7 +153,7 @@ def parse_py_signature(signode, sig, desctype, env):
if desctype in ('function', 'method'): if desctype in ('function', 'method'):
# for callables, add an empty parameter list # for callables, add an empty parameter list
signode += addnodes.desc_parameterlist() signode += addnodes.desc_parameterlist()
return fullname return fullname, classname
signode += addnodes.desc_parameterlist() signode += addnodes.desc_parameterlist()
stack = [signode[-1]] stack = [signode[-1]]
@@ -171,7 +171,7 @@ def parse_py_signature(signode, sig, desctype, env):
token = token.strip() token = token.strip()
stack[-1] += addnodes.desc_parameter(token, token) stack[-1] += addnodes.desc_parameter(token, token)
if len(stack) != 1: raise ValueError if len(stack) != 1: raise ValueError
return fullname return fullname, classname
c_sig_re = re.compile( c_sig_re = re.compile(
@@ -280,6 +280,7 @@ def desc_directive(desctype, arguments, options, content, lineno,
noindex = ('noindex' in options) noindex = ('noindex' in options)
signatures = map(lambda s: s.strip(), arguments[0].split('\n')) signatures = map(lambda s: s.strip(), arguments[0].split('\n'))
names = [] names = []
clsname = None
for i, sig in enumerate(signatures): for i, sig in enumerate(signatures):
# add a signature node for each signature in the current unit # add a signature node for each signature in the current unit
# and add a reference target for it # and add a reference target for it
@@ -290,7 +291,7 @@ def desc_directive(desctype, arguments, options, content, lineno,
try: try:
if desctype in ('function', 'data', 'class', 'exception', if desctype in ('function', 'data', 'class', 'exception',
'method', 'attribute'): 'method', 'attribute'):
name = parse_py_signature(signode, sig, desctype, env) name, clsname = parse_py_signature(signode, sig, desctype, env)
elif desctype in ('cfunction', 'cmember', 'cmacro', 'ctype', 'cvar'): elif desctype in ('cfunction', 'cmember', 'cmacro', 'ctype', 'cvar'):
name = parse_c_signature(signode, sig, desctype) name = parse_c_signature(signode, sig, desctype)
elif desctype == 'opcode': elif desctype == 'opcode':
@@ -323,13 +324,18 @@ def desc_directive(desctype, arguments, options, content, lineno,
if desctype == 'cfunction': if desctype == 'cfunction':
add_refcount_annotation(env, subnode, name) add_refcount_annotation(env, subnode, name)
# needed for automatic qualification of members # needed for automatic qualification of members
clsname_set = False
if desctype == 'class' and names: if desctype == 'class' and names:
env.currclass = names[0] env.currclass = names[0]
clsname_set = True
elif desctype in ('method', 'attribute') and clsname and not env.currclass:
env.currclass = clsname.strip('.')
clsname_set = True
# needed for association of version{added,changed} directives # needed for association of version{added,changed} directives
if names: if names:
env.currdesc = names[0] env.currdesc = names[0]
state.nested_parse(content, content_offset, subnode) state.nested_parse(content, content_offset, subnode)
if desctype == 'class': if clsname_set:
env.currclass = None env.currclass = None
env.currdesc = None env.currdesc = None
node.append(subnode) node.append(subnode)

View File

@@ -621,7 +621,8 @@ class BuildEnvironment:
builder.get_relative_uri(docfilename, filename) + anchor) builder.get_relative_uri(docfilename, filename) + anchor)
newnode.append(contnode) newnode.append(contnode)
else: else:
name, desc = self.find_desc(modname, clsname, target, typ) searchorder = 1 if node.hasattr('refspecific') else 0
name, desc = self.find_desc(modname, clsname, target, typ, searchorder)
if not desc: if not desc:
newnode = contnode newnode = contnode
else: else:
@@ -742,13 +743,16 @@ class BuildEnvironment:
# --------- QUERYING ------------------------------------------------------- # --------- QUERYING -------------------------------------------------------
def find_desc(self, modname, classname, name, type): def find_desc(self, modname, classname, name, type, searchorder=0):
"""Find a description node matching "name", perhaps using """Find a description node matching "name", perhaps using
the given module and/or classname.""" the given module and/or classname."""
# skip parens # skip parens
if name[-2:] == '()': if name[-2:] == '()':
name = name[:-2] name = name[:-2]
if not name:
return None, None
# don't add module and class names for C things # don't add module and class names for C things
if type[0] == 'c' and type not in ('class', 'const'): if type[0] == 'c' and type not in ('class', 'const'):
# skip trailing star and whitespace # skip trailing star and whitespace
@@ -757,22 +761,32 @@ class BuildEnvironment:
return name, self.descrefs[name] return name, self.descrefs[name]
return None, None return None, None
if name in self.descrefs: newname = None
newname = name if searchorder == 1:
elif modname and modname + '.' + name in self.descrefs: if modname and classname and \
newname = modname + '.' + name modname + '.' + classname + '.' + name in self.descrefs:
elif modname and classname and \ newname = modname + '.' + classname + '.' + name
modname + '.' + classname + '.' + name in self.descrefs: elif modname and modname + '.' + name in self.descrefs:
newname = modname + '.' + classname + '.' + name newname = modname + '.' + name
# special case: builtin exceptions have module "exceptions" set elif name in self.descrefs:
elif type == 'exc' and '.' not in name and \ newname = name
'exceptions.' + name in self.descrefs:
newname = 'exceptions.' + name
# special case: object methods
elif type in ('func', 'meth') and '.' not in name and \
'object.' + name in self.descrefs:
newname = 'object.' + name
else: else:
if name in self.descrefs:
newname = name
elif modname and modname + '.' + name in self.descrefs:
newname = modname + '.' + name
elif modname and classname and \
modname + '.' + classname + '.' + name in self.descrefs:
newname = modname + '.' + classname + '.' + name
# special case: builtin exceptions have module "exceptions" set
elif type == 'exc' and '.' not in name and \
'exceptions.' + name in self.descrefs:
newname = 'exceptions.' + name
# special case: object methods
elif type in ('func', 'meth') and '.' not in name and \
'object.' + name in self.descrefs:
newname = 'object.' + name
if newname is None:
return None, None return None, None
return newname, self.descrefs[newname] return newname, self.descrefs[newname]

View File

@@ -100,6 +100,12 @@ def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
text += '()' text += '()'
pnode = addnodes.pending_xref(rawtext) pnode = addnodes.pending_xref(rawtext)
pnode['reftype'] = typ pnode['reftype'] = typ
# if the first character is a dot, search more specific namespaces first
# else search builtins first
if text[0:1] == '.' and \
typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth'):
text = text[1:]
pnode['refspecific'] = True
pnode['reftarget'] = ws_re.sub('', text) pnode['reftarget'] = ws_re.sub('', text)
pnode['modname'] = env.currmodule pnode['modname'] = env.currmodule
pnode['classname'] = env.currclass pnode['classname'] = env.currclass