Skip to content

Commit 79e43af

Browse files
committed
Move domains and translators to their own files
Small refactor to have everything in place. `extension.py` was getting bigger with no reason.
1 parent 2ccb9b4 commit 79e43af

File tree

3 files changed

+132
-127
lines changed

3 files changed

+132
-127
lines changed

hoverxref/domains.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
from sphinx.domains.python import PythonDomain
2+
from sphinx.domains.std import StandardDomain
3+
from sphinx.util import logging
4+
from .utils import get_ref_xref_data, get_ref_obj_data
5+
6+
logger = logging.getLogger(__name__)
7+
8+
9+
class HoverXRefBaseDomain:
10+
11+
def _is_hoverxref_configured(self, env):
12+
project = env.config.hoverxref_project
13+
version = env.config.hoverxref_version
14+
return project and version
15+
16+
def _inject_hoverxref_data(self, env, refnode, docname, labelid):
17+
refnode.replace_attr('classes', ['hoverxref'])
18+
19+
project = env.config.hoverxref_project
20+
version = env.config.hoverxref_version
21+
refnode._hoverxref = {
22+
'data-project': project,
23+
'data-version': version,
24+
'data-doc': docname,
25+
'data-section': labelid,
26+
}
27+
28+
29+
class HoverXRefPythonDomain(HoverXRefBaseDomain, PythonDomain):
30+
31+
def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode):
32+
refnode = super().resolve_xref(env, fromdocname, builder, type, target, node, contnode)
33+
if refnode is None:
34+
return
35+
36+
modname = node.get('py:module')
37+
clsname = node.get('py:class')
38+
searchmode = node.hasattr('refspecific') and 1 or 0
39+
matches = self.find_obj(env, modname, clsname, target,
40+
type, searchmode)
41+
name, obj = matches[0]
42+
43+
if self._is_hoverxref_configured(env):
44+
docname, labelid = obj[0], name
45+
self._inject_hoverxref_data(env, refnode, docname, labelid)
46+
logger.info(
47+
':ref: _hoverxref injected: fromdocname=%s %s',
48+
fromdocname,
49+
refnode._hoverxref,
50+
)
51+
return refnode
52+
53+
54+
class HoverXRefStandardDomain(HoverXRefBaseDomain, StandardDomain):
55+
"""
56+
Override ``StandardDomain`` to save the values after the xref resolution.
57+
58+
``:ref:`` are treating as a different node in Sphinx
59+
(``sphinx.addnodes.pending_xref``). These nodes are translated to regular
60+
``docsutils.nodes.reference`` for this domain class.
61+
62+
Before loosing the data used to resolve the reference, our customized domain
63+
saves it inside the node itself to be used later by the ``HTMLTranslator``.
64+
"""
65+
66+
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
67+
if typ == 'hoverxref':
68+
resolver = self._resolve_ref_xref
69+
return resolver(env, fromdocname, builder, typ, target, node, contnode)
70+
71+
return super().resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
72+
73+
# NOTE: We could override more ``_resolve_xref`` method apply hover in more places
74+
def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
75+
refnode = super()._resolve_ref_xref(env, fromdocname, builder, typ, target, node, contnode)
76+
if refnode is None:
77+
return
78+
79+
if not self._is_hoverxref_configured(env) and typ == 'hoverxref':
80+
# Using ``:hoverxref:`` role without having hoverxref configured
81+
# properly. Log a warning.
82+
logger.warning('hoverxref role is not fully configured.')
83+
84+
if self._is_hoverxref_configured(env) and (env.config.hoverxref_auto_ref or typ == 'hoverxref'):
85+
docname, labelid, _ = get_ref_xref_data(self, node, target)
86+
self._inject_hoverxref_data(env, refnode, docname, labelid)
87+
logger.info(
88+
':ref: _hoverxref injected: fromdocname=%s %s',
89+
fromdocname,
90+
refnode._hoverxref,
91+
)
92+
return refnode
93+
94+
def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode):
95+
refnode = super()._resolve_obj_xref(env, fromdocname, builder, typ, target, node, contnode)
96+
if refnode is None:
97+
return
98+
99+
if typ in env.config.hoverxref_roles:
100+
docname, labelid = get_ref_obj_data(self, node, typ, target)
101+
if self._is_hoverxref_configured(env):
102+
self._inject_hoverxref_data(env, refnode, docname, labelid)
103+
logger.info(
104+
':%s: _hoverxref injected: fromdocname=%s %s',
105+
typ,
106+
fromdocname,
107+
refnode._hoverxref,
108+
)
109+
return refnode

hoverxref/extension.py

Lines changed: 2 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import os
22
import inspect
33
from docutils import nodes
4-
from sphinx.domains.python import PythonDomain
5-
from sphinx.domains.std import StandardDomain
64
from sphinx.roles import XRefRole
7-
from sphinx.util import logging
85
from sphinx.util.fileutil import copy_asset
9-
from sphinx.writers.html import HTMLTranslator
106

117
from . import version
12-
from .utils import get_ref_xref_data, get_ref_obj_data
8+
from .domains import HoverXRefPythonDomain, HoverXRefStandardDomain
9+
from .translators import HoverXRefHTMLTranslator
1310

1411
ASSETS_FILES = [
1512
'js/hoverxref.js_t', # ``_t`` tells Sphinx this is a template
@@ -19,128 +16,6 @@
1916
'css/tooltipster-sideTip-shadow.min.css',
2017
]
2118

22-
logger = logging.getLogger(__name__)
23-
24-
25-
class HoverXRefBaseDomain:
26-
27-
def _is_hoverxref_configured(self, env):
28-
project = env.config.hoverxref_project
29-
version = env.config.hoverxref_version
30-
return project and version
31-
32-
def _inject_hoverxref_data(self, env, refnode, docname, labelid):
33-
refnode.replace_attr('classes', ['hoverxref'])
34-
35-
project = env.config.hoverxref_project
36-
version = env.config.hoverxref_version
37-
refnode._hoverxref = {
38-
'data-project': project,
39-
'data-version': version,
40-
'data-doc': docname,
41-
'data-section': labelid,
42-
}
43-
44-
45-
class HoverXRefPythonDomain(HoverXRefBaseDomain, PythonDomain):
46-
47-
def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode):
48-
refnode = super().resolve_xref(env, fromdocname, builder, type, target, node, contnode)
49-
if refnode is None:
50-
return
51-
52-
modname = node.get('py:module')
53-
clsname = node.get('py:class')
54-
searchmode = node.hasattr('refspecific') and 1 or 0
55-
matches = self.find_obj(env, modname, clsname, target,
56-
type, searchmode)
57-
name, obj = matches[0]
58-
59-
if self._is_hoverxref_configured(env):
60-
docname, labelid = obj[0], name
61-
self._inject_hoverxref_data(env, refnode, docname, labelid)
62-
logger.info(
63-
':ref: _hoverxref injected: fromdocname=%s %s',
64-
fromdocname,
65-
refnode._hoverxref,
66-
)
67-
return refnode
68-
69-
70-
class HoverXRefStandardDomain(HoverXRefBaseDomain, StandardDomain):
71-
"""
72-
Override ``StandardDomain`` to save the values after the xref resolution.
73-
74-
``:ref:`` are treating as a different node in Sphinx
75-
(``sphinx.addnodes.pending_xref``). These nodes are translated to regular
76-
``docsutils.nodes.reference`` for this domain class.
77-
78-
Before loosing the data used to resolve the reference, our customized domain
79-
saves it inside the node itself to be used later by the ``HTMLTranslator``.
80-
"""
81-
82-
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
83-
if typ == 'hoverxref':
84-
resolver = self._resolve_ref_xref
85-
return resolver(env, fromdocname, builder, typ, target, node, contnode)
86-
87-
return super().resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
88-
89-
# NOTE: We could override more ``_resolve_xref`` method apply hover in more places
90-
def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode):
91-
refnode = super()._resolve_ref_xref(env, fromdocname, builder, typ, target, node, contnode)
92-
if refnode is None:
93-
return
94-
95-
if not self._is_hoverxref_configured(env) and typ == 'hoverxref':
96-
# Using ``:hoverxref:`` role without having hoverxref configured
97-
# properly. Log a warning.
98-
logger.warning('hoverxref role is not fully configured.')
99-
100-
if self._is_hoverxref_configured(env) and (env.config.hoverxref_auto_ref or typ == 'hoverxref'):
101-
docname, labelid, _ = get_ref_xref_data(self, node, target)
102-
self._inject_hoverxref_data(env, refnode, docname, labelid)
103-
logger.info(
104-
':ref: _hoverxref injected: fromdocname=%s %s',
105-
fromdocname,
106-
refnode._hoverxref,
107-
)
108-
return refnode
109-
110-
def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode):
111-
refnode = super()._resolve_obj_xref(env, fromdocname, builder, typ, target, node, contnode)
112-
if refnode is None:
113-
return
114-
115-
if typ in env.config.hoverxref_roles:
116-
docname, labelid = get_ref_obj_data(self, node, typ, target)
117-
if self._is_hoverxref_configured(env):
118-
self._inject_hoverxref_data(env, refnode, docname, labelid)
119-
logger.info(
120-
':%s: _hoverxref injected: fromdocname=%s %s',
121-
typ,
122-
fromdocname,
123-
refnode._hoverxref,
124-
)
125-
return refnode
126-
127-
128-
class HoverXRefHTMLTranslator(HTMLTranslator):
129-
130-
"""
131-
Override ``HTMLTranslator`` to render extra data saved in reference nodes.
132-
133-
It adds all the values saved under ``_hoverxref`` as attributes of the HTML
134-
reference tag.
135-
"""
136-
137-
def starttag(self, node, tagname, suffix='\n', empty=False, **attributes):
138-
if tagname == 'a' and hasattr(node, '_hoverxref'):
139-
attributes.update(node._hoverxref)
140-
logger.info('_hoverxref attributes: %s', attributes)
141-
142-
return super().starttag(node, tagname, suffix, empty, **attributes)
143-
14419

14520
def copy_asset_files(app, exception):
14621
"""

hoverxref/translators.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from sphinx.writers.html import HTMLTranslator
2+
from sphinx.util import logging
3+
4+
logger = logging.getLogger(__name__)
5+
6+
7+
class HoverXRefHTMLTranslator(HTMLTranslator):
8+
9+
"""
10+
Override ``HTMLTranslator`` to render extra data saved in reference nodes.
11+
12+
It adds all the values saved under ``_hoverxref`` as attributes of the HTML
13+
reference tag.
14+
"""
15+
16+
def starttag(self, node, tagname, suffix='\n', empty=False, **attributes):
17+
if tagname == 'a' and hasattr(node, '_hoverxref'):
18+
attributes.update(node._hoverxref)
19+
logger.info('_hoverxref attributes: %s', attributes)
20+
21+
return super().starttag(node, tagname, suffix, empty, **attributes)

0 commit comments

Comments
 (0)