Skip to content

Commit a2728f1

Browse files
committed
Better error message for unescaped underscores
1 parent e78aee9 commit a2728f1

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

lib/matplotlib/tests/test_texmanager.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import pytest
2+
13
import matplotlib.pyplot as plt
24
from matplotlib.texmanager import TexManager
35

@@ -16,3 +18,13 @@ def test_fontconfig_preamble():
1618
font_config2 = tm2.get_font_config()
1719

1820
assert font_config1 != font_config2
21+
22+
23+
def test_usetex_missing_underscore():
24+
"""
25+
Test that failed TeX rendering due to an unescaped underscore has a
26+
custom error message.
27+
"""
28+
with pytest.raises(RuntimeError, match='caused by an unescaped underscore'):
29+
plt.text(0, 0, 'foo_bar', usetex=True)
30+
plt.draw() # TeX rendering is done at draw time

lib/matplotlib/texmanager.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,38 @@ def _run_checked_subprocess(self, command, tex, *, cwd=None):
281281
'Failed to process string with tex because {} could not be '
282282
'found'.format(command[0])) from exc
283283
except subprocess.CalledProcessError as exc:
284-
raise RuntimeError(
285-
'{prog} was not able to process the following string:\n'
286-
'{tex!r}\n\n'
287-
'Here is the full report generated by {prog}:\n'
288-
'{exc}\n\n'.format(
289-
prog=command[0],
290-
tex=tex.encode('unicode_escape'),
291-
exc=exc.output.decode('utf-8'))) from exc
284+
tex_log = exc.output.decode('utf-8')
285+
286+
# whether the exception was likely caused by an unescaped
287+
# underscore. This cannot be easily determined unambiguously.
288+
# By requiring `'$' not in tex` we err on the side of preventing
289+
# false positives, because we only want to issue the customized
290+
# error message if we are sure there's an unescaped underscore.
291+
unescaped_underscore = (
292+
'_' in tex and '$' not in tex and
293+
re.match(r'.*Missing \$ inserted.*_\n', tex_log,
294+
flags=re.DOTALL)
295+
)
296+
if unescaped_underscore:
297+
message = (
298+
'{prog} was not able to process the following string:\n'
299+
'{tex!r}\n\n'
300+
'This is likely caused by an unescaped underscore.\n'
301+
'You may escape the underscore or add '
302+
'r"\\usepackage{{underscore}}"\n'
303+
'to the matplotlib rcParam text.latex.preamble'.format(
304+
prog=command[0],
305+
tex=tex.encode('unicode_escape')))
306+
else:
307+
message = (
308+
'{prog} was not able to process the following string:\n'
309+
'{tex!r}\n\n'
310+
'Here is the full report generated by {prog}:\n'
311+
'{exc}\n\n'.format(
312+
prog=command[0],
313+
tex=tex.encode('unicode_escape'),
314+
exc=tex_log))
315+
raise RuntimeError(message) from exc
292316
_log.debug(report)
293317
return report
294318

0 commit comments

Comments
 (0)