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 60604fe

Browse filesBrowse files
committed
Fix xkcd style garbage collection.
1 parent 6af4e4f commit 60604fe
Copy full SHA for 60604fe

File tree

Expand file treeCollapse file tree

3 files changed

+31
-30
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+31
-30
lines changed

‎lib/matplotlib/__init__.py

Copy file name to clipboardExpand all lines: lib/matplotlib/__init__.py
+25-12Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,8 +1246,7 @@ def rc_file(fname):
12461246
rcParams.update(rc_params_from_file(fname))
12471247

12481248

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

1283-
orig = rcParams.copy()
1284-
try:
1285-
if fname:
1286-
rc_file(fname)
1287-
if rc:
1288-
rcParams.update(rc)
1289-
yield
1290-
finally:
1300+
def __enter__(self):
1301+
return self
1302+
1303+
def __exit__(self, exc_type, exc_value, exc_tb):
12911304
# No need to revalidate the original values.
1292-
dict.update(rcParams, orig)
1305+
dict.update(rcParams, self._orig)
12931306

12941307

12951308
_use_error_msg = """

‎lib/matplotlib/pyplot.py

Copy file name to clipboardExpand all lines: lib/matplotlib/pyplot.py
+1-16Lines 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

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_style.py
+5-2Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.