Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix mathtext mismatched braces #26519

Merged
merged 3 commits into from
Aug 21, 2023
Merged

Fix mathtext mismatched braces #26519

merged 3 commits into from
Aug 21, 2023

Conversation

devRD
Copy link
Contributor

@devRD devRD commented Aug 14, 2023

PR summary

Fixes #26510

PR checklist

@ksunden
Copy link
Member

ksunden commented Aug 14, 2023

We discussed this a bit on GSOC call, the error message is not the most useful, but it is actually pretty hard to get a better one (the group parser just doesn't match without a closing brace, so it kicks it back as wholesale invalid, rather than being specific about invalid because the closing brace is missing)

Current feeling is that erroring is better than not, but if someone has an idea of how to get the parser to give a more informative message, I'd be open to hearing it.

@ksunden
Copy link
Member

ksunden commented Aug 14, 2023

Actually, this diff may get us a better error message:

diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py
index 25a825b7b0..de4c25bfe5 100644
--- a/lib/matplotlib/_mathtext.py
+++ b/lib/matplotlib/_mathtext.py
@@ -1894,6 +1894,7 @@ class Parser:
         p.function = csnames("name", self._function_names)
 
         p.group = p.start_group + ZeroOrMore(p.token)("group") + p.end_group
+        p.unclosed_group = p.start_group + ZeroOrMore(p.token)("group") + StringEnd()
 
         p.frac  = cmd(r"\frac", p.required_group("num") + p.required_group("den"))
         p.dfrac = cmd(r"\dfrac", p.required_group("num") + p.required_group("den"))
@@ -1943,6 +1944,7 @@ class Parser:
             p.simple
             | p.auto_delim
             | p.unknown_symbol  # Must be last
+            | p.unclosed_group  # Must be last
         )
 
         p.operatorname = cmd(r"\operatorname", "{" + ZeroOrMore(p.simple)("name") + "}")
@@ -2144,6 +2146,9 @@ class Parser:
     def unknown_symbol(self, s, loc, toks):
         raise ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}")
 
+    def unclosed_group(self, s, loc, toks):
+        raise ParseFatalException(s, len(s), "Expected '}'")
+
     _accent_map = {
         r'hat':            r'\circumflexaccent',
         r'breve':          r'\combiningbreve',
diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py
index d80312495d..5a9e8a8b92 100644
--- a/lib/matplotlib/tests/test_mathtext.py
+++ b/lib/matplotlib/tests/test_mathtext.py
@@ -320,6 +320,7 @@ def test_fontinfo():
         (r'$a^2^2$', r'Double superscript'),
         (r'$a_2_2$', r'Double subscript'),
         (r'$a^2_a^2$', r'Double superscript'),
+        (r'$a = {b$', r"Expected '}'"),
     ],
     ids=[
         'hspace without value',
@@ -347,7 +348,8 @@ def test_fontinfo():
         'unknown symbol',
         'double superscript',
         'double subscript',
-        'super on sub without braces'
+        'super on sub without braces',
+        'unclosed group',
     ]
 )
 def test_mathtext_exceptions(math, msg):

@devRD thoughts?

@devRD
Copy link
Contributor Author

devRD commented Aug 15, 2023

I think the diff makes sense, we do get a better error message. Added the changes...

@@ -1865,6 +1865,8 @@ def csnames(group, names):
"|".join(map(re.escape, tex2uni)))
)("sym").leaveWhitespace()
p.unknown_symbol = Regex(r"\\[A-Za-z]+")("name")
def unclosed_group(self, s, loc, toks):
raise ParseFatalException(s, len(s), "Expected '}'")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The location of this method is not that logical. I'd suggest moving it down to other group-methods. Otherwise, it looks good!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me rephrase that: I think this should be removed as there is another method below (at a different level, so I wonder if this is used at all?).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the method is being utilized because we get the same error message as above.

Re: there is another method below (at a different level - I might be missing something, could you point out which one?

@devRD
Copy link
Contributor Author

devRD commented Aug 16, 2023

Although not completely sure if this is correct, I think the same behavior is also achieved by redefining the group grammar to:
p.group = p.start_group + ZeroOrMore(p.token)("group") - p.end_group
(The - sign here checks for trailing end_groups("}") and raises an Exception if none is found)

Instead, the error message here would be ParseSyntaxException: Expected end_group, found end of text

@@ -2144,6 +2149,9 @@ def symbol(self, s, loc, toks):
def unknown_symbol(self, s, loc, toks):
raise ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}")

def unclosed_group(self, s, loc, toks):
raise ParseFatalException(s, len(s), "Expected '}'")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the other, identical, method. Should only require one and I think this is the one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I missed that. Thanks!

Co-authored-by: Kyle Sunden <git@ksunden.space>
lib/matplotlib/tests/test_mathtext.py Outdated Show resolved Hide resolved
lib/matplotlib/_mathtext.py Outdated Show resolved Hide resolved
Copy link
Contributor

@oscargus oscargus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Not sure if it should go into 3.8 or 3.9 (I'd vote, always, for 3.8...), so I let one of the reviewers closer to the release process tag and merge.

@ksunden ksunden added this to the v3.8.0 milestone Aug 21, 2023
@ksunden ksunden merged commit 02f9429 into matplotlib:main Aug 21, 2023
37 of 39 checks passed
meeseeksmachine pushed a commit to meeseeksmachine/matplotlib that referenced this pull request Aug 21, 2023
ksunden added a commit that referenced this pull request Aug 21, 2023
…519-on-v3.8.x

Backport PR #26519 on branch v3.8.x (Fix mathtext mismatched braces)
@ksunden ksunden mentioned this pull request Sep 15, 2023
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: mathtext silently ignores content after mismatched opening brace
4 participants