Skip to content

Commit 94c63af

Browse files
authored
Merge pull request #10860 from matplotlib/auto-backport-of-pr-10856
Backport PR #10856 on branch v2.2.x
2 parents 6afe2f9 + 960e73e commit 94c63af

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
@@ -1294,8 +1294,7 @@ def rc_file(fname):
12941294
rcParams.update(rc_params_from_file(fname))
12951295

12961296

1297-
@contextlib.contextmanager
1298-
def rc_context(rc=None, fname=None):
1297+
class rc_context(object):
12991298
"""
13001299
Return a context manager for managing rc settings.
13011300
@@ -1325,19 +1324,33 @@ def rc_context(rc=None, fname=None):
13251324
ax.plot(range(3), range(3))
13261325
fig.savefig('A.png', format='png')
13271326
plt.close(fig)
1328-
13291327
"""
1328+
# While it may seem natural to implement rc_context using
1329+
# contextlib.contextmanager, that would entail always calling the finally:
1330+
# clause of the contextmanager (which restores the original rcs) including
1331+
# during garbage collection; as a result, something like `plt.xkcd();
1332+
# gc.collect()` would result in the style being lost (as `xkcd()` is
1333+
# implemented on top of rc_context, and nothing is holding onto context
1334+
# manager except possibly circular references.
1335+
1336+
def __init__(self, rc=None, fname=None):
1337+
self._orig = rcParams.copy()
1338+
try:
1339+
if fname:
1340+
rc_file(fname)
1341+
if rc:
1342+
rcParams.update(rc)
1343+
except Exception:
1344+
# If anything goes wrong, revert to the original rcs.
1345+
dict.update(rcParams, self._orig)
1346+
raise
13301347

1331-
orig = rcParams.copy()
1332-
try:
1333-
if fname:
1334-
rc_file(fname)
1335-
if rc:
1336-
rcParams.update(rc)
1337-
yield
1338-
finally:
1348+
def __enter__(self):
1349+
return self
1350+
1351+
def __exit__(self, exc_type, exc_value, exc_tb):
13391352
# No need to revalidate the original values.
1340-
dict.update(rcParams, orig)
1353+
dict.update(rcParams, self._orig)
13411354

13421355

13431356
_use_error_msg = """

lib/matplotlib/pyplot.py

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

394394
from matplotlib import patheffects
395-
xkcd_ctx = rc_context({
395+
return rc_context({
396396
'font.family': ['xkcd', 'Humor Sans', 'Comic Sans MS'],
397397
'font.size': 14.0,
398398
'path.sketch': (scale, length, randomness),
@@ -409,21 +409,6 @@ def xkcd(scale=1, length=100, randomness=2):
409409
'ytick.major.size': 8,
410410
'ytick.major.width': 3,
411411
})
412-
xkcd_ctx.__enter__()
413-
414-
# In order to make the call to `xkcd` that does not use a context manager
415-
# (cm) work, we need to enter into the cm ourselves, and return a dummy
416-
# cm that does nothing on entry and cleans up the xkcd context on exit.
417-
# Additionally, we need to keep a reference to the dummy cm because it
418-
# would otherwise be exited when GC'd.
419-
420-
class dummy_ctx(object):
421-
def __enter__(self):
422-
pass
423-
424-
__exit__ = xkcd_ctx.__exit__
425-
426-
return dummy_ctx()
427412

428413

429414
## 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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy