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

Skip to content

Commit 78224ef

Browse files
authored
Merge pull request #10856 from anntzer/xkcdgc
Fix xkcd style garbage collection.
2 parents a81fdf5 + 60604fe commit 78224ef

File tree

3 files changed

+31
-30
lines changed

3 files changed

+31
-30
lines changed

lib/matplotlib/__init__.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,8 +1243,7 @@ def rc_file(fname):
12431243
rcParams.update(rc_params_from_file(fname))
12441244

12451245

1246-
@contextlib.contextmanager
1247-
def rc_context(rc=None, fname=None):
1246+
class rc_context:
12481247
"""
12491248
Return a context manager for managing rc settings.
12501249
@@ -1274,19 +1273,33 @@ def rc_context(rc=None, fname=None):
12741273
ax.plot(range(3), range(3))
12751274
fig.savefig('A.png', format='png')
12761275
plt.close(fig)
1277-
12781276
"""
1277+
# While it may seem natural to implement rc_context using
1278+
# contextlib.contextmanager, that would entail always calling the finally:
1279+
# clause of the contextmanager (which restores the original rcs) including
1280+
# during garbage collection; as a result, something like `plt.xkcd();
1281+
# gc.collect()` would result in the style being lost (as `xkcd()` is
1282+
# implemented on top of rc_context, and nothing is holding onto context
1283+
# manager except possibly circular references.
1284+
1285+
def __init__(self, rc=None, fname=None):
1286+
self._orig = rcParams.copy()
1287+
try:
1288+
if fname:
1289+
rc_file(fname)
1290+
if rc:
1291+
rcParams.update(rc)
1292+
except Exception:
1293+
# If anything goes wrong, revert to the original rcs.
1294+
dict.update(rcParams, self._orig)
1295+
raise
12791296

1280-
orig = rcParams.copy()
1281-
try:
1282-
if fname:
1283-
rc_file(fname)
1284-
if rc:
1285-
rcParams.update(rc)
1286-
yield
1287-
finally:
1297+
def __enter__(self):
1298+
return self
1299+
1300+
def __exit__(self, exc_type, exc_value, exc_tb):
12881301
# No need to revalidate the original values.
1289-
dict.update(rcParams, orig)
1302+
dict.update(rcParams, self._orig)
12901303

12911304

12921305
_use_error_msg = """

lib/matplotlib/pyplot.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ def xkcd(scale=1, length=100, randomness=2):
387387
"xkcd mode is not compatible with text.usetex = True")
388388

389389
from matplotlib import patheffects
390-
xkcd_ctx = rc_context({
390+
return rc_context({
391391
'font.family': ['xkcd', 'Humor Sans', 'Comic Sans MS'],
392392
'font.size': 14.0,
393393
'path.sketch': (scale, length, randomness),
@@ -404,21 +404,6 @@ def xkcd(scale=1, length=100, randomness=2):
404404
'ytick.major.size': 8,
405405
'ytick.major.width': 3,
406406
})
407-
xkcd_ctx.__enter__()
408-
409-
# In order to make the call to `xkcd` that does not use a context manager
410-
# (cm) work, we need to enter into the cm ourselves, and return a dummy
411-
# cm that does nothing on entry and cleans up the xkcd context on exit.
412-
# Additionally, we need to keep a reference to the dummy cm because it
413-
# would otherwise be exited when GC'd.
414-
415-
class dummy_ctx(object):
416-
def __enter__(self):
417-
pass
418-
419-
__exit__ = xkcd_ctx.__exit__
420-
421-
return dummy_ctx()
422407

423408

424409
## Figures ##

lib/matplotlib/tests/test_style.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from __future__ import absolute_import, division, print_function
22

3+
from collections import OrderedDict
4+
from contextlib import contextmanager
5+
import gc
36
import os
47
import shutil
58
import tempfile
69
import warnings
7-
from collections import OrderedDict
8-
from contextlib import contextmanager
910

1011
import pytest
1112

@@ -163,6 +164,8 @@ def test_xkcd_no_cm():
163164
assert mpl.rcParams["path.sketch"] is None
164165
plt.xkcd()
165166
assert mpl.rcParams["path.sketch"] == (1, 100, 2)
167+
gc.collect()
168+
assert mpl.rcParams["path.sketch"] == (1, 100, 2)
166169

167170

168171
def test_xkcd_cm():

0 commit comments

Comments
 (0)