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

Skip to content

Commit 488962a

Browse files
authored
Merge pull request #24730 from timhoffm/rcparams-data-api
Data access API for rcParams
2 parents 65dc9be + ecf156c commit 488962a

File tree

6 files changed

+82
-17
lines changed

6 files changed

+82
-17
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
rcParams type
2+
~~~~~~~~~~~~~
3+
Relying on ``rcParams`` being a ``dict`` subclass is deprecated.
4+
5+
Nothing will change for regular users because ``rcParams`` will continue to
6+
be dict-like (technically fulfill the ``MutableMapping`` interface).
7+
8+
The `.RcParams` class does validation checking on calls to
9+
``.RcParams.__getitem__`` and ``.RcParams.__setitem__``. However, there are rare
10+
cases where we want to circumvent the validation logic and directly access the
11+
underlying data values. Previously, this could be accomplished via a call to
12+
the parent methods ``dict.__getitem__(rcParams, key)`` and
13+
``dict.__setitem__(rcParams, key, val)``.
14+
15+
Matplotlib 3.7 introduces ``rcParams._set(key, val)`` and
16+
``rcParams._get(key)`` as a replacement to calling the parent methods. They are
17+
intentionally marked private to discourage external use; However, if direct
18+
`.RcParams` data access is needed, please switch from the dict functions to the
19+
new ``_get()`` and ``_set()``. Even though marked private, we guarantee API
20+
stability for these methods and they are subject to Matplotlib's API and
21+
deprecation policy.
22+
23+
Please notify the Matplotlib developers if you rely on ``rcParams`` being a
24+
dict subclass in any other way, for which there is no migration path yet.

lib/matplotlib/__init__.py

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ def gen_candidates():
620620
)
621621
class RcParams(MutableMapping, dict):
622622
"""
623-
A dictionary object including validation.
623+
A dict-like key-value store for config parameters, including validation.
624624
625625
Validating functions are defined and associated with rc parameters in
626626
:mod:`matplotlib.rcsetup`.
@@ -640,6 +640,47 @@ class RcParams(MutableMapping, dict):
640640
def __init__(self, *args, **kwargs):
641641
self.update(*args, **kwargs)
642642

643+
def _set(self, key, val):
644+
"""
645+
Directly write data bypassing deprecation and validation logic.
646+
647+
Notes
648+
-----
649+
As end user or downstream library you almost always should use
650+
``rcParams[key] = val`` and not ``_set()``.
651+
652+
There are only very few special cases that need direct data access.
653+
These cases previously used ``dict.__setitem__(rcParams, key, val)``,
654+
which is now deprecated and replaced by ``rcParams._set(key, val)``.
655+
656+
Even though private, we guarantee API stability for ``rcParams._set``,
657+
i.e. it is subject to Matplotlib's API and deprecation policy.
658+
659+
:meta public:
660+
"""
661+
dict.__setitem__(self, key, val)
662+
663+
def _get(self, key):
664+
"""
665+
Directly read data bypassing deprecation, backend and validation
666+
logic.
667+
668+
Notes
669+
-----
670+
As end user or downstream library you almost always should use
671+
``val = rcParams[key]`` and not ``_get()``.
672+
673+
There are only very few special cases that need direct data access.
674+
These cases previously used ``dict.__getitem__(rcParams, key, val)``,
675+
which is now deprecated and replaced by ``rcParams._get(key)``.
676+
677+
Even though private, we guarantee API stability for ``rcParams._get``,
678+
i.e. it is subject to Matplotlib's API and deprecation policy.
679+
680+
:meta public:
681+
"""
682+
return dict.__getitem__(self, key)
683+
643684
def __setitem__(self, key, val):
644685
try:
645686
if key in _deprecated_map:
@@ -664,7 +705,7 @@ def __setitem__(self, key, val):
664705
cval = self.validate[key](val)
665706
except ValueError as ve:
666707
raise ValueError(f"Key {key}: {ve}") from None
667-
dict.__setitem__(self, key, cval)
708+
self._set(key, cval)
668709
except KeyError as err:
669710
raise KeyError(
670711
f"{key} is not a valid rc parameter (see rcParams.keys() for "
@@ -675,27 +716,27 @@ def __getitem__(self, key):
675716
version, alt_key, alt_val, inverse_alt = _deprecated_map[key]
676717
_api.warn_deprecated(
677718
version, name=key, obj_type="rcparam", alternative=alt_key)
678-
return inverse_alt(dict.__getitem__(self, alt_key))
719+
return inverse_alt(self._get(alt_key))
679720

680721
elif key in _deprecated_ignore_map:
681722
version, alt_key = _deprecated_ignore_map[key]
682723
_api.warn_deprecated(
683724
version, name=key, obj_type="rcparam", alternative=alt_key)
684-
return dict.__getitem__(self, alt_key) if alt_key else None
725+
return self._get(alt_key) if alt_key else None
685726

686727
# In theory, this should only ever be used after the global rcParams
687728
# has been set up, but better be safe e.g. in presence of breakpoints.
688729
elif key == "backend" and self is globals().get("rcParams"):
689-
val = dict.__getitem__(self, key)
730+
val = self._get(key)
690731
if val is rcsetup._auto_backend_sentinel:
691732
from matplotlib import pyplot as plt
692733
plt.switch_backend(rcsetup._auto_backend_sentinel)
693734

694-
return dict.__getitem__(self, key)
735+
return self._get(key)
695736

696737
def _get_backend_or_none(self):
697738
"""Get the requested backend, if any, without triggering resolution."""
698-
backend = dict.__getitem__(self, "backend")
739+
backend = self._get("backend")
699740
return None if backend is rcsetup._auto_backend_sentinel else backend
700741

701742
def __repr__(self):
@@ -738,7 +779,7 @@ def copy(self):
738779
"""Copy this RcParams instance."""
739780
rccopy = RcParams()
740781
for k in self: # Skip deprecations and revalidation.
741-
dict.__setitem__(rccopy, k, dict.__getitem__(self, k))
782+
rccopy._set(k, self._get(k))
742783
return rccopy
743784

744785

lib/matplotlib/pyplot.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,10 @@ def _get_backend_mod():
202202
This is currently private, but may be made public in the future.
203203
"""
204204
if _backend_mod is None:
205-
# Use __getitem__ here to avoid going through the fallback logic (which
206-
# will (re)import pyplot and then call switch_backend if we need to
207-
# resolve the auto sentinel)
208-
switch_backend(dict.__getitem__(rcParams, "backend"))
205+
# Use rcParams._get("backend") to avoid going through the fallback
206+
# logic (which will (re)import pyplot and then call switch_backend if
207+
# we need to resolve the auto sentinel)
208+
switch_backend(rcParams._get("backend"))
209209
return _backend_mod
210210

211211

@@ -2241,7 +2241,7 @@ def polar(*args, **kwargs):
22412241
and rcParams._get_backend_or_none() in (
22422242
set(_interactive_bk) - {'WebAgg', 'nbAgg'})
22432243
and cbook._get_running_interactive_framework()):
2244-
dict.__setitem__(rcParams, "backend", rcsetup._auto_backend_sentinel)
2244+
rcParams._set("backend", rcsetup._auto_backend_sentinel)
22452245

22462246

22472247
################# REMAINING CONTENT GENERATED BY boilerplate.py ##############

lib/matplotlib/tests/test_backends_interactive.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,13 @@ def _impl_test_lazy_auto_backend_selection():
249249
import matplotlib
250250
import matplotlib.pyplot as plt
251251
# just importing pyplot should not be enough to trigger resolution
252-
bk = dict.__getitem__(matplotlib.rcParams, 'backend')
252+
bk = matplotlib.rcParams._get('backend')
253253
assert not isinstance(bk, str)
254254
assert plt._backend_mod is None
255255
# but actually plotting should
256256
plt.plot(5)
257257
assert plt._backend_mod is not None
258-
bk = dict.__getitem__(matplotlib.rcParams, 'backend')
258+
bk = matplotlib.rcParams._get('backend')
259259
assert isinstance(bk, str)
260260

261261

lib/matplotlib/tests/test_rcparams.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ def test_backend_fallback_headful(tmpdir):
544544
"sentinel = mpl.rcsetup._auto_backend_sentinel; "
545545
# Check that access on another instance does not resolve the sentinel.
546546
"assert mpl.RcParams({'backend': sentinel})['backend'] == sentinel; "
547-
"assert dict.__getitem__(mpl.rcParams, 'backend') == sentinel; "
547+
"assert mpl.rcParams._get('backend') == sentinel; "
548548
"import matplotlib.pyplot; "
549549
"print(matplotlib.get_backend())"],
550550
env=env, universal_newlines=True)

lib/matplotlib/tests/test_widgets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,7 @@ def test_CheckButtons(ax):
967967
@pytest.mark.parametrize("toolbar", ["none", "toolbar2", "toolmanager"])
968968
def test_TextBox(ax, toolbar):
969969
# Avoid "toolmanager is provisional" warning.
970-
dict.__setitem__(plt.rcParams, "toolbar", toolbar)
970+
plt.rcParams._set("toolbar", toolbar)
971971

972972
submit_event = mock.Mock(spec=noop, return_value=None)
973973
text_change_event = mock.Mock(spec=noop, return_value=None)

0 commit comments

Comments
 (0)