Skip to content

Commit 2900fda

Browse files
committed
Declare sphinxext.redirect_from parallel_read_safe
This uses a domain as data store for the redirects sphinx plugin. That is how the sphinx todo extension handles data and was suggested in sphinx-doc/sphinx#9003 (comment)
1 parent 153b463 commit 2900fda

File tree

1 file changed

+35
-5
lines changed

1 file changed

+35
-5
lines changed

doc/sphinxext/redirect_from.py

+35-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
from pathlib import Path
3434
from docutils.parsers.rst import Directive
35+
from sphinx.domains import Domain
3536
from sphinx.util import logging
3637

3738
logger = logging.getLogger(__name__)
@@ -48,32 +49,61 @@
4849
def setup(app):
4950
RedirectFrom.app = app
5051
app.add_directive("redirect-from", RedirectFrom)
52+
app.add_domain(RedirectFromDomain)
5153
app.connect("build-finished", _generate_redirects)
5254

55+
metadata = {'parallel_read_safe': True}
56+
return metadata
57+
58+
59+
class RedirectFromDomain(Domain):
60+
"""
61+
The sole purpose of this domain is a parallel_read_safe data store for the
62+
redirects mapping.
63+
"""
64+
name = 'redirect_from'
65+
label = 'redirect_from'
66+
67+
@property
68+
def redirects(self):
69+
"""The mapping of the redirectes."""
70+
return self.data.setdefault('redirects', {})
71+
72+
def clear_doc(self, docnames):
73+
self.redirects.clear()
74+
75+
def merge_domaindata(self, docnames, otherdata):
76+
for src, dst in otherdata['redirects'].items():
77+
if src not in self.redirects:
78+
self.redirects[src] = dst
79+
elif self.redirects[src] != dst:
80+
raise ValueError(
81+
f"{src} is already noted as redirecting to {dst}")
82+
5383

5484
class RedirectFrom(Directive):
5585
required_arguments = 1
56-
redirects = {}
5786

5887
def run(self):
5988
redirected_doc, = self.arguments
6089
env = self.app.env
6190
builder = self.app.builder
91+
domain = env.get_domain('redirect_from')
6292
current_doc = env.path2doc(self.state.document.current_source)
6393
redirected_reldoc, _ = env.relfn2path(redirected_doc, current_doc)
64-
if redirected_reldoc in self.redirects:
94+
if redirected_reldoc in domain.redirects:
6595
raise ValueError(
6696
f"{redirected_reldoc} is already noted as redirecting to "
67-
f"{self.redirects[redirected_reldoc]}")
68-
self.redirects[redirected_reldoc] = current_doc
97+
f"{domain.redirects[redirected_reldoc]}")
98+
domain.redirects[redirected_reldoc] = current_doc
6999
return []
70100

71101

72102
def _generate_redirects(app, exception):
73103
builder = app.builder
74104
if builder.name != "html" or exception:
75105
return
76-
for k, v in RedirectFrom.redirects.items():
106+
for k, v in app.env.get_domain('redirect_from').redirects.items():
77107
p = Path(app.outdir, k + builder.out_suffix)
78108
html = HTML_TEMPLATE.format(v=builder.get_relative_uri(k, v))
79109
if p.is_file():

0 commit comments

Comments
 (0)