8000 Add a helper to generate mathtext error strings. · matplotlib/matplotlib@9af21fa · GitHub
[go: up one dir, main page]

Skip to content

Commit 9af21fa

Browse files
committed
Add a helper to generate mathtext error strings.
This also ensures consistency in the names in the error strings; see e.g. changes in test_mathtext (the contents of `\overline` are indeed a "body", not a "value"). Renaming "simple_group" to "optional_group" is semantically more meaningful.
1 parent d0bef3b commit 9af21fa

File tree

2 files changed

+63
-49
lines changed

2 files changed

+63
-49
lines changed

lib/matplotlib/_mathtext.py

Lines changed: 59 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import numpy as np
1515
from pyparsing import (
1616
Empty, Forward, Literal, NotAny, oneOf, OneOrMore, Optional,
17-
ParseBaseException, ParseFatalException, ParserElement, ParseResults,
18-
QuotedString, Regex, StringEnd, ZeroOrMore, pyparsing_common)
17+
ParseBaseException, ParseExpression, ParseFatalException, ParserElement,
18+
ParseResults, QuotedString, Regex, StringEnd, ZeroOrMore, pyparsing_common)
1919

2020
import matplotlib as mpl
2121
from . import _api, cbook
@@ -1559,9 +1559,7 @@ def Error(msg):
15591559
def raise_error(s, loc, toks):
15601560
raise ParseFatalException(s, loc, msg)
15611561

1562-
empty = Empty()
1563-
empty.setParseAction(raise_error)
1564-
return empty
1562+
return Empty().setParseAction(raise_error)
15651563

15661564

15671565
class ParserState:
@@ -1601,6 +1599,31 @@ def get_current_underline_thickness(self):
16011599
self.font, self.fontsize, self.dpi)
16021600

16031601

1602+
def cmd(expr, args):
1603+
r"""
1604+
Helper to define TeX commands.
1605+
1606+
``cmd("\cmd", args)`` is equivalent to
1607+
``"\cmd" - (args | Error("Expected \cmd{arg}{...}"))`` where the names in
1608+
the error message are taken from element names in *args*. If *expr*
1609+
already includes arguments (e.g. "\cmd{arg}{...}"), then they are stripped
1610+
when constructing the parse element, but kept (and *expr* is used as is) in
1611+
the error message.
1612+
"""
1613+
1614+
def names(elt):
1615+
if isinstance(elt, ParseExpression):
1616+
for expr in elt.exprs:
1617+
yield from names(expr)
1618+
elif elt.resultsName:
1619+
yield elt.resultsName
1620+
1621+
csname = expr.split("{", 1)[0]
1622+
err = (csname + "".join("{%s}" % name for name in names(args))
1623+
if expr == csname else expr)
1624+
return csname - (args | Error(f"Expected {err}"))
1625+
1626+
16041627
class Parser:
16051628
"""
16061629
A pyparsing-based parser for strings containing math expressions.
@@ -1742,69 +1765,60 @@ def set_names_and_parse_actions():
17421765
p.placeable = Forward()
17431766
p.required_group = Forward()
17441767
p.simple = Forward()
1745-
p.simple_group = Forward()
1768+
p.optional_group = Forward()
17461769
p.sqrt = Forward()
17471770
p.subsuper = Forward()
17481771
p.token = Forward()
17491772
p.underset = Forward()
17501773

17511774
set_names_and_parse_actions() # for mutually recursive definitions.
17521775

1753-
p.customspace <<= r"\hspace" - (
1754-
"{" + p.float_literal("space") + "}"
1755-
| Error(r"Expected \hspace{n}"))
1776+
p.customspace <<= cmd(r"\hspace", "{" + p.float_literal("space") + "}")
17561777

1757-
p.accent <<= (
1778+
p.accent <<= (
17581779
"\\"
17591780
+ oneOf([*self._accent_map, *self._wide_accents])("accent")
17601781
- p.placeable("sym"))
17611782

1762-
p.function <<= "\\" + oneOf(self._function_names)("name")
1763-
p.operatorname <<= r"\operatorname" - (
1764-
"{" + ZeroOrMore(p.simple | p.unknown_symbol)("name") + "}"
1765-
| Error(r"Expected \operatorname{name}"))
1783+
p.function <<= "\\" + oneOf(self._function_names)("name")
1784+
p.operatorname <<= cmd(
1785+
r"\operatorname",
1786+
"{" + ZeroOrMore(p.simple | p.unknown_symbol)("name") + "}")
17661787

1767-
p.group <<= (
1768-
p.start_group + ZeroOrMore(p.token)("group") + p.end_group)
1788+
p.group <<= p.start_group + ZeroOrMore(p.token)("group") + p.end_group
17691789

1770-
p.simple_group <<= "{" + ZeroOrMore(p.token)("group") + "}"
1790+
p.optional_group <<= "{" + ZeroOrMore(p.token)("group") + "}"
17711791
p.required_group <<= "{" + OneOrMore(p.token)("group") + "}"
17721792

1773-
p.frac <<= r"\frac" - (
1774-
p.required_group("num") + p.required_group("den")
1775-
| Error(r"Expected \frac{num}{den}"))
1776-
p.dfrac <<= r"\dfrac" - (
1777-
p.required_group("num") + p.required_group("den")
1778-
| Error(r"Expected \dfrac{num}{den}"))
1779-
p.binom <<= r"\binom" - (
1780-
p.required_group("num") + p.required_group("den")
1781-
| Error(r"Expected \binom{num}{den}"))
1782-
1783-
p.genfrac <<= r"\genfrac" - (
1793+
p.frac <<= cmd(
1794+
r"\frac", p.required_group("num") + p.required_group("den"))
1795+
p.dfrac <<= cmd(
1796+
r"\dfrac", p.required_group("num") + p.required_group("den"))
1797+
p.binom <<= cmd(
1798+
r"\binom", p.required_group("num") + p.required_group("den"))
1799+
1800+
p.genfrac <<= cmd(
1801+
r"\genfrac",
17841802
"{" + Optional(p.ambi_delim | p.left_delim)("ldelim") + "}"
17851803
+ "{" + Optional(p.ambi_delim | p.right_delim)("rdelim") + "}"
17861804
+ "{" + p.float_literal("rulesize") + "}"
1787-
+ p.simple_group("style")
1805+
+ p.optional_group("style")
17881806
+ p.required_group("num")
1789-
+ p.required_group("den")
1790-
| Error("Expected "
1791-
r"\genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}"))
1807+
+ p.required_group("den"))
17921808

1793-
p.sqrt <<= r"\sqrt" - (
1809+
p.sqrt <<= cmd(
1810+
r"\sqrt{value}",
17941811
Optional("[" + OneOrMore(NotAny("]") + p.token)("root") + "]")
1795-
+ p.required_group("value")
1796-
| Error(r"Expected \sqrt{value}"))
1812+
+ p.required_group("value"))
17971813

1798-
p.overline <<= r"\overline" - (
1799-
p.required_group("body")
1800-
| Error(r"Expected \overline{value}"))
1814+
p.overline <<= cmd(r"\overline", p.required_group("body"))
18011815

1802-
p.overset <<= r"\overset" - (
1803-
p.simple_group("annotation") + p.simple_group("body")
1804-
| Error(r"Expected \overset{annotation}{body}"))
1805-
p.underset <<= r"\underset" - (
1806-
p.simple_group("annotation") + p.simple_group("body")
1807-
| Error(r"Expected \underset{annotation}{body}"))
1816+
p.overset <<= cmd(
1817+
r"\overset",
1818+
p.optional_group("annotation") + p.optional_group("body"))
1819+
p.underset <<= cmd(
1820+
r"\underset",
1821+
p.optional_group("annotation") + p.optional_group("body"))
18081822

18091823
p.placeable <<= (
18101824
p.accentprefixed # Must be before accent so named symbols that are
@@ -2110,7 +2124,7 @@ def group(self, s, loc, toks):
21102124
def required_group(self, s, loc, toks):
21112125
return Hlist(toks.get("group", []))
21122126

2113-
simple_group = required_group
2127+
optional_group = required_group
21142128

21152129
def end_group(self, s, loc, toks):
21162130
self.pop_state()

lib/matplotlib/tests/test_mathtext.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ def test_fontinfo():
234234
@pytest.mark.parametrize(
235235
'math, msg',
236236
[
237-
(r'$\hspace{}$', r'Expected \hspace{n}'),
238-
(r'$\hspace{foo}$', r'Expected \hspace{n}'),
237+
(r'$\hspace{}$', r'Expected \hspace{space}'),
238+
(r'$\hspace{foo}$', r'Expected \hspace{space}'),
239239
(r'$\frac$', r'Expected \frac{num}{den}'),
240240
(r'$\frac{}{}$', r'Expected \frac{num}{den}'),
241241
(r'$\binom$', r'Expected \binom{num}{den}'),
@@ -246,8 +246,8 @@ def test_fontinfo():
246246
r'Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}'),
247247
(r'$\sqrt$', r'Expected \sqrt{value}'),
248248
(r'$\sqrt f$', r'Expected \sqrt{value}'),
249-
(r'$\overline$', r'Expected \overline{value}'),
250-
(r'$\overline{}$', r'Expected \overline{value}'),
249+
(r'$\overline$', r'Expected \overline{body}'),
250+
(r'$\overline{}$', r'Expected \overline{body}'),
251251
(r'$\leftF$', r'Expected a delimiter'),
252252
(r'$\rightF$', r'Unknown symbol: \rightF'),
253253
(r'$\left(\right$', r'Expected a delimiter'),

0 commit comments

Comments
 (0)
0