2424import sphinx
2525import inspect
2626import collections
27+ import hashlib
2728
2829if sphinx .__version__ < '1.0.1' :
2930 raise RuntimeError ("Sphinx 1.0.1 or newer is required" )
3637 sixu = lambda s : unicode (s , 'unicode_escape' )
3738
3839
39- def rename_references (app , what , name , obj , options , lines ,
40- reference_offset = [ 0 ]):
41- # replace reference numbers so that there are no duplicates
40+ def rename_references (app , what , name , obj , options , lines ):
41+ # decorate reference numbers so that there are no duplicates
42+ # these are later undecorated in the doctree, in relabel_references
4243 references = []
4344 for line in lines :
4445 line = line .strip ()
@@ -48,18 +49,41 @@ def rename_references(app, what, name, obj, options, lines,
4849 references .append (m .group (1 ))
4950
5051 if references :
52+ # we use a hash to mangle the reference name to avoid invalid names
53+ sha = hashlib .sha256 ()
54+ sha .update (name .encode ('utf8' ))
55+ prefix = 'R' + sha .hexdigest ()
56+
5157 for i , line in enumerate (lines ):
5258 for r in references :
53- if re .match (sixu ('^\\ d+$' ), r ):
54- new_r = sixu ("R%d" ) % (reference_offset [0 ] + int (r ))
55- else :
56- new_r = sixu ("%s%d" ) % (r , reference_offset [0 ])
59+ new_r = prefix + '-' + r
5760 lines [i ] = lines [i ].replace (sixu ('[%s]_' ) % r ,
5861 sixu ('[%s]_' ) % new_r )
5962 lines [i ] = lines [i ].replace (sixu ('.. [%s]' ) % r ,
6063 sixu ('.. [%s]' ) % new_r )
6164
62- reference_offset [0 ] += len (references )
65+
66+ def relabel_references (app , doc ):
67+ # Change name_ref to ref in label text
68+ from docutils .nodes import citation , Text
69+ from sphinx .addnodes import pending_xref
70+ for citation_node in doc .traverse (citation ):
71+ label_node = citation_node [0 ]
72+ new_text = Text (citation_node ['names' ][0 ].split ('-' )[- 1 ])
73+ label_node .replace (label_node [0 ], new_text )
74+
75+ for id in citation_node ['backrefs' ]:
76+ ref = doc .ids [id ]
77+ ref_text = ref [0 ]
78+
79+ # Sphinx has created pending_xref nodes with [reftext] text.
80+ def matching_pending_xref (node ):
81+ return (isinstance (node , pending_xref ) and
82+ node [0 ].astext () == '[%s]' % ref_text )
83+
84+ for xref_node in ref .parent .traverse ():
85+ xref_node .replace (xref_node [0 ], Text ('[%s]' % new_text ))
86+ ref .replace (ref_text , new_text .copy ())
6387
6488
6589DEDUPLICATION_TAG = ['..' , ' processed by numpydoc' ]
@@ -136,6 +160,7 @@ def setup(app, get_doc_object_=get_doc_object):
136160
137161 app .connect ('autodoc-process-docstring' , mangle_docstrings )
138162 app .connect ('autodoc-process-signature' , mangle_signature )
163+ app .connect ('doctree-read' , relabel_references )
139164 app .add_config_value ('numpydoc_edit_link' , None , False )
140165 app .add_config_value ('numpydoc_use_plots' , None , False )
141166 app .add_config_value ('numpydoc_show_class_members' , True , True )
0 commit comments