Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 88fbc26

Browse filesBrowse files
committed
Re-fix exception caching in dviread.
The original solution using with_traceback didn't actually work because with_traceback doesn't return a new exception instance but rather modifies the original one in place, and the traceback will then be attached to it by the raise statement. Instead, we actually need to build a new instance, so reuse the _ExceptionProxy machinery from font_manager (slightly expanded).
1 parent bb68469 commit 88fbc26
Copy full SHA for 88fbc26

File tree

Expand file treeCollapse file tree

3 files changed

+32
-12
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+32
-12
lines changed

‎lib/matplotlib/cbook.py

Copy file name to clipboardExpand all lines: lib/matplotlib/cbook.py
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,29 @@
3232
from matplotlib import _api, _c_internal_utils
3333

3434

35+
class _ExceptionInfo:
36+
"""
37+
A class to carry exception information around.
38+
39+
This is used to store and later raise exceptions. It's an alternative to
40+
directly storing Exception instances that circumvents traceback-related
41+
issues: caching tracebacks can keep user's objects in local namespaces
42+
alive indefinitely, which can lead to very surprising memory issues for
43+
users and result in incorrect tracebacks.
44+
"""
45+
46+
def __init__(self, cls, *args):
47+
self._cls = cls
48+
self._args = args
49+
50+
@classmethod
51+
def from_exception(cls, exc):
52+
return cls(type(exc), *exc.args)
53+
54+
def to_exception(self):
55+
return self._cls(*self._args)
56+
57+
3558
def _get_running_interactive_framework():
3659
"""
3760
Return the interactive framework whose event loop is currently running, if

‎lib/matplotlib/dviread.py

Copy file name to clipboardExpand all lines: lib/matplotlib/dviread.py
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ def _read(self):
340340
byte = self.file.read(1)[0]
341341
self._dtable[byte](self, byte)
342342
if self._missing_font:
343-
raise self._missing_font
343+
raise self._missing_font.to_exception()
344344
name = self._dtable[byte].__name__
345345
if name == "_push":
346346
down_stack.append(down_stack[-1])
@@ -368,14 +368,14 @@ def _read_arg(self, nbytes, signed=False):
368368
@_dispatch(min=0, max=127, state=_dvistate.inpage)
369369
def _set_char_immediate(self, char):
370370
self._put_char_real(char)
371-
if isinstance(self.fonts[self.f], FileNotFoundError):
371+
if isinstance(self.fonts[self.f], cbook._ExceptionInfo):
372372
return
373373
self.h += self.fonts[self.f]._width_of(char)
374374

375375
@_dispatch(min=128, max=131, state=_dvistate.inpage, args=('olen1',))
376376
def _set_char(self, char):
377377
self._put_char_real(char)
378-
if isinstance(self.fonts[self.f], FileNotFoundError):
378+
if isinstance(self.fonts[self.f], cbook._ExceptionInfo):
379379
return
380380
self.h += self.fonts[self.f]._width_of(char)
381381

@@ -390,7 +390,7 @@ def _put_char(self, char):
390390

391391
def _put_char_real(self, char):
392392
font = self.fonts[self.f]
393-
if isinstance(font, FileNotFoundError):
393+
if isinstance(font, cbook._ExceptionInfo):
394394
self._missing_font = font
395395
elif font._vf is None:
396396
self.text.append(Text(self.h, self.v, font, char,
@@ -504,7 +504,7 @@ def _fnt_def_real(self, k, c, s, d, a, l):
504504
# and throw that error in Dvi._read. For Vf, _finalize_packet
505505
# checks whether a missing glyph has been used, and in that case
506506
# skips the glyph definition.
507-
self.fonts[k] = exc.with_traceback(None)
507+
self.fonts[k] = cbook._ExceptionInfo.from_exception(exc)
508508
return
509509
if c != 0 and tfm.checksum != 0 and c != tfm.checksum:
510510
raise ValueError(f'tfm checksum mismatch: {n}')

‎lib/matplotlib/font_manager.py

Copy file name to clipboardExpand all lines: lib/matplotlib/font_manager.py
+4-7Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from __future__ import annotations
2929

3030
from base64 import b64encode
31-
from collections import namedtuple
3231
import copy
3332
import dataclasses
3433
from functools import lru_cache
@@ -133,8 +132,6 @@
133132
'sans',
134133
}
135134

136-
_ExceptionProxy = namedtuple('_ExceptionProxy', ['klass', 'message'])
137-
138135
# OS Font paths
139136
try:
140137
_HOME = Path.home()
@@ -1355,8 +1352,8 @@ def findfont(self, prop, fontext='ttf', directory=None,
13551352
ret = self._findfont_cached(
13561353
prop, fontext, directory, fallback_to_default, rebuild_if_missing,
13571354
rc_params)
1358-
if isinstance(ret, _ExceptionProxy):
1359-
raise ret.klass(ret.message)
1355+
if isinstance(ret, cbook._ExceptionInfo):
1356+
raise ret.to_exception()
13601357
return ret
13611358

13621359
def get_font_names(self):
@@ -1509,7 +1506,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
15091506
# This return instead of raise is intentional, as we wish to
15101507
# cache that it was not found, which will not occur if it was
15111508
# actually raised.
1512-
return _ExceptionProxy(
1509+
return cbook._ExceptionInfo(
15131510
ValueError,
15141511
f"Failed to find font {prop}, and fallback to the default font was "
15151512
f"disabled"
@@ -1535,7 +1532,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
15351532
# This return instead of raise is intentional, as we wish to
15361533
# cache that it was not found, which will not occur if it was
15371534
# actually raised.
1538-
return _ExceptionProxy(ValueError, "No valid font could be found")
1535+
return cbook._ExceptionInfo(ValueError, "No valid font could be found")
15391536

15401537
return _cached_realpath(result)
15411538

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.