Skip to content

Commit e5df3de

Browse files
committed
Fix links to rcParams sample matplotlibrc
The anchor ID was changed, but as this was entered manually, it did not break the build. Instead, insert a pending cross-reference so that Sphinx will resolve it and warn if it breaks. The output changes minimally from `external` to `internal` class, and also gains `std std-ref` classes due to it being a standard reference.
1 parent a36e5a8 commit e5df3de

File tree

1 file changed

+55
-12
lines changed

1 file changed

+55
-12
lines changed

doc/sphinxext/custom_roles.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,57 @@
1+
from urllib.parse import urlsplit, urlunsplit
2+
13
from docutils import nodes
2-
from os.path import sep
4+
35
from matplotlib import rcParamsDefault
46

57

6-
def rcparam_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
7-
rendered = nodes.Text(f'rcParams["{text}"]')
8+
class QueryReference(nodes.Inline, nodes.TextElement):
9+
"""
10+
Wraps a reference or pending reference to add a query string.
11+
12+
The query string is generated from the attributes added to this node.
13+
14+
Also equivalent to a `~docutils.nodes.literal` node.
15+
"""
16+
17+
def to_query_string(self):
18+
"""Generate query string from node attributes."""
19+
return '&'.join(f'{name}={value}' for name, value in self.attlist())
20+
21+
22+
def visit_query_reference_node(self, node):
23+
"""
24+
Resolve *node* into query strings on its ``reference`` children.
825
9-
source = inliner.document.attributes['source'].replace(sep, '/')
10-
rel_source = source.split('/doc/', 1)[1]
26+
Then act as if this is a `~docutils.nodes.literal`.
27+
"""
28+
query = node.to_query_string()
29+
for refnode in node.findall(nodes.reference):
30+
uri = urlsplit(refnode['refuri'])._replace(query=query)
31+
refnode['refuri'] = urlunsplit(uri)
1132

12-
levels = rel_source.count('/')
13-
refuri = ('../' * levels +
14-
'tutorials/introductory/customizing.html' +
15-
f"?highlight={text}#a-sample-matplotlibrc-file")
33+
self.visit_literal(node)
34+
35+
36+
def depart_query_reference_node(self, node):
37+
"""
38+
Act as if this is a `~docutils.nodes.literal`.
39+
"""
40+
self.depart_literal(node)
41+
42+
43+
def rcparam_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
44+
# Generate a pending cross-reference so that Sphinx will ensure this link
45+
# isn't broken at some point in the future.
46+
title = f'rcParam["{text}"]'
47+
target = 'matplotlibrc-sample'
48+
ref_nodes, messages = inliner.interpreted(title, f'{title} <{target}>',
49+
'ref', lineno)
50+
51+
qr = QueryReference(rawtext, highlight=text)
52+
qr += ref_nodes
53+
node_list = [qr]
1654

17-
ref = nodes.reference(rawtext, rendered, refuri=refuri)
18-
node_list = [nodes.literal('', '', ref)]
1955
# The default backend would be printed as "agg", but that's not correct (as
2056
# the default is actually determined by fallback).
2157
if text in rcParamsDefault and text != "backend":
@@ -24,9 +60,16 @@ def rcparam_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
2460
nodes.literal('', repr(rcParamsDefault[text])),
2561
nodes.Text(')'),
2662
])
27-
return node_list, []
63+
64+
return node_list, messages
2865

2966

3067
def setup(app):
3168
app.add_role("rc", rcparam_role)
69+
app.add_node(
70+
QueryReference,
71+
html=(visit_query_reference_node, depart_query_reference_node),
72+
latex=(visit_query_reference_node, depart_query_reference_node),
73+
text=(visit_query_reference_node, depart_query_reference_node),
74+
)
3275
return {"parallel_read_safe": True, "parallel_write_safe": True}

0 commit comments

Comments
 (0)