尝试将 "pending_xref" 节点追加到 signnode 时发生异常
An exception occured when trying append "pending_xref" node to signode
我正在尝试将 pending_xref 节点附加到 handle_signature[ 的 signnode 函数,但在 docutils 脚本中出现异常:
Exception occurred:
File "\python\python37-32\lib\site-packages\docutils\nodes.py", line 569, in __getitem__
return self.children[key] IndexError: list index out of range
我的代码:
def handle_signature(self, sig, signode):
if 'mod' in self.options:
signode += nodes.Text(self.options['mod'] + ' ')
signode += nodes.Text('Some text ')
names, _, _ = Obj.parse_signature(sig)
if names:
ns = names.strip().split('.')
for cl in ns:
# because off this, i'm get an error
signode += addnodes.pending_xref('', refdomain='mydomain',
reftype='ahg', reftarget=cl, modname=None, classname=None)
return sig
在没有 += addnode.pending_xref() 的情况下一切正常(并且其他节点成功追加,除了这个)。
In nodes.py when exception occures, index equals to 0 (but it's nothing tells me).
您可以在 pastebin 上使用我的脚本重现此内容。对于测试,只需使用指令 .. sphinxtest:recipe:: TestRecipe
。在我的例子中 make html
之后,我得到了上面的错误。
完整代码:
import re
from docutils import nodes
from docutils.parsers import rst
from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
from sphinx.locale import _
from sphinx.domains import Domain, Index, ObjType
from sphinx.domains.std import StandardDomain
from sphinx.roles import XRefRole
from sphinx.directives import ObjectDescription
from sphinx.util.docfields import DocFieldTransformer
from sphinx.util.nodes import make_refnode, nested_parse_with_titles
from sphinx import addnodes
class RecipeObject(ObjectDescription):
has_content = True
required_arguments = 1
option_spec = {}
final_argument_whitespace = False
def run(self):
# Default run function, but added: before_sig
if ':' in self.name:
self.domain, self.objtype = self.name.split(':', 1)
else:
self.domain, self.objtype = '', self.name
self.indexnode = addnodes.index(entries=[])
node = addnodes.desc()
node.document = self.state.document
node['domain'] = self.domain
node['objtype'] = node['desctype'] = self.objtype
node['noindex'] = noindex = ('noindex' in self.options)
self.names = [] # type: List[unicode]
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
beforesignode = nodes.container(sig)
signode = addnodes.desc_signature(sig, '')
signode['first'] = False
node.append(beforesignode)
node.append(signode)
self.before_sig(beforesignode)
try:
name = self.handle_signature(sig, signode)
except ValueError:
signode.clear()
signode += addnodes.desc_name(sig, sig)
continue
if name not in self.names:
self.names.append(name)
if not noindex:
self.add_target_and_index(name, sig, signode)
contentnode = addnodes.desc_content()
node.append(contentnode)
if self.names:
self.env.temp_data['object'] = self.names[0]
self.before_content()
self.state.nested_parse(self.content, self.content_offset, contentnode)
DocFieldTransformer(self).transform_all(contentnode)
self.env.temp_data['object'] = None
self.after_content()
return [self.indexnode, node]
def before_sig(self, signode):
"""
Called before main ``signode`` appends
"""
pass
def handle_signature(self, sig, signode):
signode += nodes.Text('recipe ')
names = sig.strip().split('.')
for nm in names:
print(nm)
signode += addnodes.pending_xref('', refdomain='sphinxtest', reftype='rec',
reftarget=nm, modname=None, classname=None)
return sig
def add_target_and_index(self, name, sig, signode):
anchor = '{}-{}'.format(self.objtype, sig)
full_name = self.get_full_name(name)
if anchor not in self.state.document.ids:
signode['names'].append(anchor)
signode['ids'].append(anchor)
signode['first'] = not self.names
self.state.document.note_explicit_target(signode)
objects = self.env.domaindata['sphinxtest']['objects']
objects[name] = (self.env.docname, self.objtype, anchor)
index_text = self.get_index_text(name)
if index_text:
self.indexnode['entries'].append(('single', index_text, full_name, full_name, None))
def get_full_name(self, name):
return '{}.{}'.format(self.objtype, name)
def get_index_text(self, cls_name):
name = _('{} (Recipe)').format(cls_name)
return name
class RecipeDomain(Domain):
name = 'sphinxtest'
label = 'Test'
roles = {
'rec': XRefRole(),
}
object_types = {
'recipe': ObjType(_('recipe'), 'rec', 'obj'),
}
directives = {
'recipe': RecipeObject,
}
initial_data = {
'objects': {}
}
def clear_doc(self, docname):
for name, (doc, objtype, anchor) in self.data['objects'].copy().items():
if doc == docname:
del self.data['objects'][name]
def get_objects(self):
for name, (docname, objtype, anchor) in self.data['objects'].items():
yield (name, name, objtype, docname, anchor, 1)
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
print('Resolving xref of target: ' + target)
match = [(name, sig, typ, docname, anchor, prio)
for name, sig, typ, docname, anchor, prio
in self.get_objects() if sig == target]
if len(match) > 0:
print('Match = {}'.format(match))
todocname = match[0][3]
targ = match[0][4]
refnode = make_refnode(builder, fromdocname, todocname, targ, contnode, targ)
print('RefNode: {}'.format(refnode))
return make_refnode(builder, fromdocname, todocname, targ, contnode, targ)
return None
def merge_domaindata(self, docnames, otherdata):
pass
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
pass
def setup(app):
app.add_domain(RecipeDomain)
return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}
通过添加一些文本元素作为子元素解决:
refnode = addnodes.pending_xref('', refdomain='mydomain', reftype='typ', reftarget=t, modname=None, classname=None)
refnode += nodes.Text('Title')
我正在尝试将 pending_xref 节点附加到 handle_signature[ 的 signnode 函数,但在 docutils 脚本中出现异常:
Exception occurred: File "\python\python37-32\lib\site-packages\docutils\nodes.py", line 569, in __getitem__
return self.children[key] IndexError: list index out of range
我的代码:
def handle_signature(self, sig, signode):
if 'mod' in self.options:
signode += nodes.Text(self.options['mod'] + ' ')
signode += nodes.Text('Some text ')
names, _, _ = Obj.parse_signature(sig)
if names:
ns = names.strip().split('.')
for cl in ns:
# because off this, i'm get an error
signode += addnodes.pending_xref('', refdomain='mydomain',
reftype='ahg', reftarget=cl, modname=None, classname=None)
return sig
在没有 += addnode.pending_xref() 的情况下一切正常(并且其他节点成功追加,除了这个)。
In nodes.py when exception occures, index equals to 0 (but it's nothing tells me).
您可以在 pastebin 上使用我的脚本重现此内容。对于测试,只需使用指令 .. sphinxtest:recipe:: TestRecipe
。在我的例子中 make html
之后,我得到了上面的错误。
完整代码:
import re
from docutils import nodes
from docutils.parsers import rst
from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
from sphinx.locale import _
from sphinx.domains import Domain, Index, ObjType
from sphinx.domains.std import StandardDomain
from sphinx.roles import XRefRole
from sphinx.directives import ObjectDescription
from sphinx.util.docfields import DocFieldTransformer
from sphinx.util.nodes import make_refnode, nested_parse_with_titles
from sphinx import addnodes
class RecipeObject(ObjectDescription):
has_content = True
required_arguments = 1
option_spec = {}
final_argument_whitespace = False
def run(self):
# Default run function, but added: before_sig
if ':' in self.name:
self.domain, self.objtype = self.name.split(':', 1)
else:
self.domain, self.objtype = '', self.name
self.indexnode = addnodes.index(entries=[])
node = addnodes.desc()
node.document = self.state.document
node['domain'] = self.domain
node['objtype'] = node['desctype'] = self.objtype
node['noindex'] = noindex = ('noindex' in self.options)
self.names = [] # type: List[unicode]
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
beforesignode = nodes.container(sig)
signode = addnodes.desc_signature(sig, '')
signode['first'] = False
node.append(beforesignode)
node.append(signode)
self.before_sig(beforesignode)
try:
name = self.handle_signature(sig, signode)
except ValueError:
signode.clear()
signode += addnodes.desc_name(sig, sig)
continue
if name not in self.names:
self.names.append(name)
if not noindex:
self.add_target_and_index(name, sig, signode)
contentnode = addnodes.desc_content()
node.append(contentnode)
if self.names:
self.env.temp_data['object'] = self.names[0]
self.before_content()
self.state.nested_parse(self.content, self.content_offset, contentnode)
DocFieldTransformer(self).transform_all(contentnode)
self.env.temp_data['object'] = None
self.after_content()
return [self.indexnode, node]
def before_sig(self, signode):
"""
Called before main ``signode`` appends
"""
pass
def handle_signature(self, sig, signode):
signode += nodes.Text('recipe ')
names = sig.strip().split('.')
for nm in names:
print(nm)
signode += addnodes.pending_xref('', refdomain='sphinxtest', reftype='rec',
reftarget=nm, modname=None, classname=None)
return sig
def add_target_and_index(self, name, sig, signode):
anchor = '{}-{}'.format(self.objtype, sig)
full_name = self.get_full_name(name)
if anchor not in self.state.document.ids:
signode['names'].append(anchor)
signode['ids'].append(anchor)
signode['first'] = not self.names
self.state.document.note_explicit_target(signode)
objects = self.env.domaindata['sphinxtest']['objects']
objects[name] = (self.env.docname, self.objtype, anchor)
index_text = self.get_index_text(name)
if index_text:
self.indexnode['entries'].append(('single', index_text, full_name, full_name, None))
def get_full_name(self, name):
return '{}.{}'.format(self.objtype, name)
def get_index_text(self, cls_name):
name = _('{} (Recipe)').format(cls_name)
return name
class RecipeDomain(Domain):
name = 'sphinxtest'
label = 'Test'
roles = {
'rec': XRefRole(),
}
object_types = {
'recipe': ObjType(_('recipe'), 'rec', 'obj'),
}
directives = {
'recipe': RecipeObject,
}
initial_data = {
'objects': {}
}
def clear_doc(self, docname):
for name, (doc, objtype, anchor) in self.data['objects'].copy().items():
if doc == docname:
del self.data['objects'][name]
def get_objects(self):
for name, (docname, objtype, anchor) in self.data['objects'].items():
yield (name, name, objtype, docname, anchor, 1)
def resolve_xref(self, env, fromdocname, builder,
typ, target, node, contnode):
print('Resolving xref of target: ' + target)
match = [(name, sig, typ, docname, anchor, prio)
for name, sig, typ, docname, anchor, prio
in self.get_objects() if sig == target]
if len(match) > 0:
print('Match = {}'.format(match))
todocname = match[0][3]
targ = match[0][4]
refnode = make_refnode(builder, fromdocname, todocname, targ, contnode, targ)
print('RefNode: {}'.format(refnode))
return make_refnode(builder, fromdocname, todocname, targ, contnode, targ)
return None
def merge_domaindata(self, docnames, otherdata):
pass
def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
pass
def setup(app):
app.add_domain(RecipeDomain)
return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}
通过添加一些文本元素作为子元素解决:
refnode = addnodes.pending_xref('', refdomain='mydomain', reftype='typ', reftarget=t, modname=None, classname=None)
refnode += nodes.Text('Title')