Merge pull request #6467 from tk0miya/refactor_math

refactor: Add data accessors to MathDomain
This commit is contained in:
Takeshi KOMIYA 2019-06-15 23:48:57 +09:00 committed by GitHub
commit 564d23be7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 25 deletions

View File

@ -10,6 +10,8 @@ Incompatible changes
Deprecated
----------
* ``sphinx.domains.math.MathDomain.add_equation()``
* ``sphinx.domains.math.MathDomain.get_next_equation_number()``
* The ``info`` and ``warn`` arguments of
``sphinx.ext.autosummary.generate.generate_autosummary_docs()``
* ``sphinx.ext.autosummary.generate._simple_info()``

View File

@ -26,6 +26,16 @@ The following is a list of deprecated interfaces.
- (will be) Removed
- Alternatives
* - ``sphinx.domains.math.MathDomain.add_equation()``
- 2.2
- 4.0
- ``sphinx.domains.math.MathDomain.note_equation()``
* - ``sphinx.domains.math.MathDomain.get_next_equation_number()``
- 2.2
- 4.0
- ``sphinx.domains.math.MathDomain.note_equation()``
* - The ``info`` and ``warn`` arguments of
``sphinx.ext.autosummary.generate.generate_autosummary_docs()``
- 2.2

View File

@ -16,6 +16,7 @@ from docutils.parsers.rst.directives import images, html, tables
from sphinx import addnodes
from sphinx.directives import optional_int
from sphinx.domains.math import MathDomain
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import set_source_info
@ -194,18 +195,15 @@ class MathDirective(SphinxDirective):
return
# register label to domain
domain = self.env.get_domain('math')
try:
eqno = domain.add_equation(self.env, self.env.docname, node['label']) # type: ignore # NOQA
node['number'] = eqno
domain = cast(MathDomain, self.env.get_domain('math'))
domain.note_equation(self.env.docname, node['label'], location=node)
node['number'] = domain.get_equation_number_for(node['label'])
# add target node
node_id = make_id('equation-%s' % node['label'])
target = nodes.target('', '', ids=[node_id])
self.state.document.note_explicit_target(target)
ret.insert(0, target)
except UserWarning as exc:
self.state_machine.reporter.warning(exc, line=self.lineno)
# add target node
node_id = make_id('equation-%s' % node['label'])
target = nodes.target('', '', ids=[node_id])
self.state.document.note_explicit_target(target)
ret.insert(0, target)
def setup(app: "Sphinx") -> Dict[str, Any]:

View File

@ -8,10 +8,13 @@
:license: BSD, see LICENSE for details.
"""
import warnings
from docutils import nodes
from docutils.nodes import make_id
from sphinx.addnodes import math_block as displaymath
from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.domains import Domain
from sphinx.locale import __
from sphinx.roles import XRefRole
@ -44,7 +47,7 @@ class MathDomain(Domain):
initial_data = {
'objects': {}, # labelid -> (docname, eqno)
'has_equations': {}, # docname -> bool
} # type: Dict[str, Dict[str, Tuple[str, int]]]
} # type: Dict
dangling_warnings = {
'eq': 'equation not found: %(target)s',
}
@ -56,6 +59,27 @@ class MathDomain(Domain):
'numref': MathReferenceRole(),
}
@property
def equations(self):
# type: () -> Dict[str, Tuple[str, int]]
return self.data.setdefault('objects', {}) # labelid -> (docname, eqno)
def note_equation(self, docname, labelid, location=None):
# type: (str, str, Any) -> None
if labelid in self.equations:
other = self.equations[labelid][0]
logger.warning(__('duplicate label of equation %s, other instance in %s') %
(labelid, other), location=location)
self.equations[labelid] = (docname, self.env.new_serialno('eqno') + 1)
def get_equation_number_for(self, labelid):
# type: (str) -> int
if labelid in self.equations:
return self.equations[labelid][1]
else:
return None
def process_doc(self, env, docname, document):
# type: (BuildEnvironment, str, nodes.document) -> None
def math_node(node):
@ -66,9 +90,9 @@ class MathDomain(Domain):
def clear_doc(self, docname):
# type: (str) -> None
for equation_id, (doc, eqno) in list(self.data['objects'].items()):
for equation_id, (doc, eqno) in list(self.equations.items()):
if doc == docname:
del self.data['objects'][equation_id]
del self.equations[equation_id]
self.data['has_equations'].pop(docname, None)
@ -76,7 +100,7 @@ class MathDomain(Domain):
# type: (Iterable[str], Dict) -> None
for labelid, (doc, eqno) in otherdata['objects'].items():
if doc in docnames:
self.data['objects'][labelid] = (doc, eqno)
self.equations[labelid] = (doc, eqno)
for docname in docnames:
self.data['has_equations'][docname] = otherdata['has_equations'][docname]
@ -84,19 +108,22 @@ class MathDomain(Domain):
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
# type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
assert typ in ('eq', 'numref')
docname, number = self.data['objects'].get(target, (None, None))
docname, number = self.equations.get(target, (None, None))
if docname:
# TODO: perhaps use rather a sphinx-core provided prefix here?
node_id = make_id('equation-%s' % target)
if env.config.math_numfig and env.config.numfig:
if docname in env.toc_fignumbers:
number = env.toc_fignumbers[docname]['displaymath'].get(node_id, ())
number = '.'.join(map(str, number))
numbers = env.toc_fignumbers[docname]['displaymath'].get(node_id, ())
eqno = '.'.join(map(str, numbers))
else:
number = ''
eqno = ''
else:
eqno = str(number)
try:
eqref_format = env.config.math_eqref_format or "({number})"
title = nodes.Text(eqref_format.format(number=number))
title = nodes.Text(eqref_format.format(number=eqno))
except KeyError as exc:
logger.warning(__('Invalid math_eqref_format: %r'), exc,
location=node)
@ -120,19 +147,22 @@ class MathDomain(Domain):
def add_equation(self, env, docname, labelid):
# type: (BuildEnvironment, str, str) -> int
equations = self.data['objects']
if labelid in equations:
path = env.doc2path(equations[labelid][0])
warnings.warn('MathDomain.add_equation() is deprecated.',
RemovedInSphinx40Warning)
if labelid in self.equations:
path = env.doc2path(self.equations[labelid][0])
msg = __('duplicate label of equation %s, other instance in %s') % (labelid, path)
raise UserWarning(msg)
else:
eqno = self.get_next_equation_number(docname)
equations[labelid] = (docname, eqno)
self.equations[labelid] = (docname, eqno)
return eqno
def get_next_equation_number(self, docname):
# type: (str) -> int
targets = [eq for eq in self.data['objects'].values() if eq[0] == docname]
warnings.warn('MathDomain.get_next_equation_number() is deprecated.',
RemovedInSphinx40Warning)
targets = [eq for eq in self.equations.values() if eq[0] == docname]
return len(targets) + 1
def has_equations(self):

View File

@ -52,3 +52,35 @@ def test_code_directive(app):
doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, nodes.literal_block, 'print("hello world")'])
assert_node(doctree[0], language="python", linenos=True, highlight_args={'linenostart': 5})
def test_math_directive(app):
# normal case
text = '.. math:: E = mc^2'
doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, nodes.math_block, 'E = mc^2\n\n'])
# :name: option
text = ('.. math:: E = mc^2\n'
' :name: eq1\n')
doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, (nodes.target,
[nodes.math_block, "E = mc^2\n\n"])])
assert_node(doctree[1], nodes.math_block, docname='index', label="eq1", number=1)
# :label: option
text = ('.. math:: E = mc^2\n'
' :label: eq2\n')
doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, (nodes.target,
[nodes.math_block, 'E = mc^2\n\n'])])
assert_node(doctree[1], nodes.math_block, docname='index', label="eq2", number=2)
# :label: option without value
text = ('.. math:: E = mc^2\n'
' :label:\n')
doctree = restructuredtext.parse(app, text)
assert_node(doctree, [nodes.document, (nodes.target,
[nodes.math_block, 'E = mc^2\n\n'])])
assert_node(doctree[1], nodes.math_block, ids=['equation-index-0'],
docname='index', label="index:0", number=3)