Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 03483c2

Browse files
authored
Merge pull request #28906 from anntzer/tb2
Re-fix exception caching in dviread.
2 parents 9dceafc + 88fbc26 commit 03483c2

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

lib/matplotlib/cbook.py

Lines 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

Lines 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

Lines 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)