Skip to content

Commit af93c0b

Browse files
committed
Remove namespaces and keep chainmap for settings.
As per @timhoffm's suggestion, decreasing scope of this PR to first just remove the dict inheritance and add a ChainMap to maintain settings. This is a fairly straightforward change and doesn't change the interface. Furthermore, the keys are still dotted and don't support namespacing as defining namespaces might take a little more discussion.
1 parent 68a16c9 commit af93c0b

File tree

3 files changed

+36
-107
lines changed

3 files changed

+36
-107
lines changed

lib/matplotlib/__init__.py

+26-103
Original file line numberDiff line numberDiff line change
@@ -662,21 +662,11 @@ class RcParams(MutableMapping):
662662
:ref:`customizing-with-matplotlibrc-files`
663663
"""
664664
validate = rcsetup._validators
665-
_namespaces = ("backends", "lines", "patches", "hatches", "boxplot", "font", "text",
666-
"latex", "axes", "date", "xtick", "ytick", "grid", "legend",
667-
"figure", "image", "contour", "errorbar", "hist", "scatter", "agg",
668-
"path", "savefig", "tk", "ps", "pdf", "svg", "pgf", "docstring",
669-
"keymap", "animation", "_internal", "webagg", "markers", "pcolor",
670-
"pcolormesh", "patch", "hatch", "mathtext", "polaraxes", "axes3d",
671-
"xaxis", "yaxis", "default")
672-
673-
_single_key_set = {"backend", "toolbar", "interactive",
674-
"timezone", "backend_fallback"}
675665

676666
def __init__(self, *args, **kwargs):
677-
self._namespace_maps = {name: ChainMap({}) for name in self._namespaces}
667+
self._rcvalues = ChainMap({})
678668
self.update(*args, **kwargs)
679-
self._new_child()
669+
self._rcvalues.new_child()
680670

681671
@staticmethod
682672
@functools.lru_cache
@@ -710,25 +700,7 @@ def _set(self, key, val):
710700
711701
:meta public:
712702
"""
713-
keys, depth = self._split_key(key)
714-
if depth == 1:
715-
if key in self._single_key_set:
716-
self._namespace_maps["default"][key] = val
717-
# Uncomment the following line and remove the raise statement
718-
# to enable setting namespaces.
719-
# else:
720-
# if isinstance(val, dict):
721-
# self._namespace_maps[key] = ChainMap({}, val)
722-
# else:
723-
# raise ValueError(
724-
# f"{key} should be set using a dictionary but found "
725-
# f"{type(val)}")
726-
else:
727-
raise KeyError(
728-
f"{key} is not a valid rc parameter (see rcParams.keys() for "
729-
f"a list of valid parameters)")
730-
elif depth == 2:
731-
self._namespace_maps[keys[0]][keys[1]] = val
703+
self._rcvalues[key] = val
732704

733705
def _get(self, key):
734706
"""
@@ -749,19 +721,7 @@ def _get(self, key):
749721
750722
:meta public:
751723
"""
752-
keys, depth = self._split_key(key)
753-
if depth == 1:
754-
if key in self._single_key_set:
755-
return self._namespace_maps["default"].get(key)
756-
# Uncomment the following line and remove the raise statement
757-
# to enable getting namespace parameters.
758-
# return self._namespace_maps[key]
759-
else:
760-
raise KeyError(
761-
f"{key} is not a valid rc parameter (see rcParams.keys() for "
762-
f"a list of valid parameters)")
763-
elif depth == 2:
764-
return self._namespace_maps[keys[0]].get(keys[1])
724+
return self._rcvalues[key]
765725

766726
def __setitem__(self, key, val):
767727
try:
@@ -785,8 +745,8 @@ def __setitem__(self, key, val):
785745
return
786746
try:
787747
cval = self.validate[key](val)
788-
if key in self._single_key_set:
789-
key = f"default.{key}"
748+
# if key in self._single_key_set:
749+
# key = f"default.{key}"
790750
except ValueError as ve:
791751
raise ValueError(f"Key {key}: {ve}") from None
792752
self._set(key, cval)
@@ -819,21 +779,9 @@ def __getitem__(self, key):
819779
return self._get(key)
820780

821781
def _get_default(self, key):
822-
keys, depth = self._split_key(key)
823-
if depth == 1:
824-
if key in self._single_key_set:
825-
return self._namespace_maps["default"].get(key)
826-
# Uncomment the following line and remove the raise statement
827-
# to enable getting namespace parameters.
828-
# return self._namespace_maps[key]
829-
else:
830-
raise KeyError(
831-
f"{key} is not a valid rc parameter (see rcParams.keys() for "
832-
f"a list of valid parameters)")
833-
elif depth == 2:
834-
return self._namespace_maps[keys[0]].maps[-1].get(keys[1])
782+
return self._rcvalues.maps[-1][key]
835783

836-
def getdefault(self, key):
784+
def get_default(self, key):
837785
if key in _deprecated_map:
838786
version, alt_key, alt_val, inverse_alt = _deprecated_map[key]
839787
_api.warn_deprecated(
@@ -848,7 +796,7 @@ def getdefault(self, key):
848796

849797
return self._get_default(key)
850798

851-
def getdefaults(self):
799+
def get_defaults(self):
852800
"""Return default values set during initialization."""
853801
defaults = self.copy()
854802
defaults.clear()
@@ -860,54 +808,35 @@ def _get_backend_or_none(self):
860808
return None if backend is rcsetup._auto_backend_sentinel else backend
861809

862810
def __delitem__(self, key):
863-
keys, depth = self._split_key(key)
864811
try:
865-
if depth == 1:
866-
if key in self._single_key_set:
867-
del self._namespace_maps["default"][key]
868-
else:
869-
raise KeyError
870-
elif depth == 2:
871-
del self._namespace_maps[keys[0]][keys[1]]
812+
del self._rcvalues[key]
872813
except KeyError as err:
873814
raise KeyError(
874815
f"{key} is not a valid rc parameter (see rcParams.keys() for "
875816
f"a list of valid parameters)") from err
876817

877818
def __contains__(self, key):
878-
keys, depth = self._split_key(key)
879-
if depth == 1:
880-
if key in self._single_key_set:
881-
return key in self._namespace_maps["default"]
882-
else:
883-
return False
884-
elif depth == 2:
885-
return any(key in mapping for mapping in self._namespace_maps)
819+
return key in self._rcvalues
886820

887821
def __iter__(self):
888822
"""Yield from sorted list of keys"""
889-
keys = (
890-
".".join((space, key)) if space != 'default' else key
891-
for space, mapping in self._namespace_maps.items()
892-
for key in mapping.keys()
893-
)
894823
with _api.suppress_matplotlib_deprecation_warning():
895-
yield from sorted(keys)
824+
yield from sorted(self._rcvalues.keys())
896825

897826
def __len__(self):
898-
return sum(len(mapping) for mapping in self._namespace_maps)
827+
return len(self._rcvalues)
899828

900829
def __repr__(self):
901830
class_name = self.__class__.__name__
902831
indent = len(class_name) + 1
903832
with _api.suppress_matplotlib_deprecation_warning():
904-
repr_split = pprint.pformat(dict(self.items()), indent=1,
833+
repr_split = pprint.pformat(dict(self._rcvalues.items()), indent=1,
905834
width=80 - indent).split('\n')
906835
repr_indented = ('\n' + ' ' * indent).join(repr_split)
907836
return f'{class_name}({repr_indented})'
908837

909838
def __str__(self):
910-
return '\n'.join(map('{0[0]}: {0[1]}'.format, sorted(self.items())))
839+
return '\n'.join(map('{0[0]}: {0[1]}'.format, sorted(self._rcvalues.items())))
911840

912841
def pop(self, key):
913842
keys, depth = self._split_key(key)
@@ -926,8 +855,7 @@ def popitem(self):
926855
"popitem is not implemented for RcParams.")
927856

928857
def clear(self):
929-
for namespace in self._namespace_maps:
930-
self._namespace_maps[namespace].clear()
858+
self._rcvalues.clear()
931859

932860
def setdefault(self, key, default=None):
933861
"""Insert key with a value of default if key is not in the dictionary.
@@ -1062,8 +990,7 @@ def _rc_params_in_file(fname, transform=lambda x: x, fail_on_error=False):
1062990
fname)
1063991
raise
1064992

1065-
config = RcParams()
1066-
config._parents()
993+
config = dict()
1067994

1068995
for key, (val, line, line_no) in rc_temp.items():
1069996
if key in rcsetup._validators:
@@ -1092,8 +1019,7 @@ def _rc_params_in_file(fname, transform=lambda x: x, fail_on_error=False):
10921019
or from the matplotlib source distribution""",
10931020
dict(key=key, fname=fname, line_no=line_no,
10941021
line=line.rstrip('\n'), version=version))
1095-
config._new_child()
1096-
return config
1022+
return RcParams(config)
10971023

10981024

10991025
def rc_params_from_file(fname, fail_on_error=False, use_default_template=True):
@@ -1117,7 +1043,7 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True):
11171043
return config_from_file
11181044

11191045
with _api.suppress_matplotlib_deprecation_warning():
1120-
config = RcParams({**rcParams.getdefaults(), **config_from_file})
1046+
config = RcParams({**rcParams.get_defaults(), **config_from_file})
11211047

11221048
if "".join(config['text.latex.preamble']):
11231049
_log.info("""
@@ -1137,10 +1063,10 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True):
11371063
# Strip leading comment.
11381064
transform=lambda line: line[1:] if line.startswith("#") else line,
11391065
fail_on_error=True)
1140-
for key in rcsetup._hardcoded_defaults:
1141-
space, subkey = key.split(".")
1142-
if not rcParams._namespace_maps[space]:
1143-
rcParams._namespace_maps[space] = ChainMap({})
1066+
# for key in rcsetup._hardcoded_defaults:
1067+
# space, subkey = key.split(".")
1068+
# if not rcParams._namespace_maps[space]:
1069+
# rcParams._namespace_maps[space] = ChainMap({})
11441070
rcParams.update(rcsetup._hardcoded_defaults)
11451071
# Normally, the default matplotlibrc file contains *no* entry for backend (the
11461072
# corresponding line starts with ##, not #; we fill on _auto_backend_sentinel
@@ -1156,7 +1082,7 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True):
11561082
defaultParams = rcsetup.defaultParams = {
11571083
# We want to resolve deprecated rcParams, but not backend...
11581084
key: [(rcsetup._auto_backend_sentinel if key == "backend" else
1159-
rcParams.getdefault(key)),
1085+
rcParams.get_default(key)),
11601086
validator]
11611087
for key, validator in rcsetup._validators.items()}
11621088
if rcParams['axes.formatter.use_locale']:
@@ -1349,10 +1275,7 @@ def rc_context(rc=None, fname=None):
13491275
13501276
"""
13511277
try:
1352-
for space in rcParams._namespace_maps.keys():
1353-
rcParams._namespace_maps[space] = rcParams._namespace_maps[
1354-
space
1355-
].new_child()
1278+
rcParams._rcvalues = rcParams._rcvalues.new_child()
13561279
if fname:
13571280
rc_file(fname)
13581281
if rc:
@@ -1361,7 +1284,7 @@ def rc_context(rc=None, fname=None):
13611284
finally:
13621285
# Revert to the original rcs.
13631286
backend = rcParams["backend"]
1364-
rcParams._parents()
1287+
rcParams._rcvalues = rcParams._rcvalues.parents
13651288
rcParams["backend"] = backend
13661289

13671290

lib/matplotlib/style/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def use(style):
114114
# rcParamsDefault, no need to reemit them here.
115115
with _api.suppress_matplotlib_deprecation_warning():
116116
# don't trigger RcParams.__getitem__('backend')
117-
style = {k: mpl.rcParams.getdefault(k) for k in mpl.rcParams
117+
style = {k: mpl.rcParams.get_default(k) for k in mpl.rcParams
118118
if k not in STYLE_BLACKLIST}
119119
elif style in library:
120120
style = library[style]

lib/matplotlib/tests/test_rcparams.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -601,12 +601,12 @@ def test_rcparams_legend_loc():
601601

602602
def test_rcparams_getdefault():
603603
with mpl.rc_context({"image.lut": 128}):
604-
assert mpl.rcParams.getdefault("image.lut") == 256
604+
assert mpl.rcParams.get_default("image.lut") == 256
605605

606606

607607
def test_rcparams_getdefaults():
608608
mpl.rc("image", lut=128)
609-
defaults = mpl.rcParams.getdefaults()
609+
defaults = mpl.rcParams.get_defaults()
610610
mpl.rcParams.clear()
611611
assert defaults == mpl.rcParams
612612

@@ -618,8 +618,14 @@ def test_rcdefaults():
618618
# lines.linewidth is not a style blacklisted key and should be
619619
# reset to the default value.
620620
# breakpoint()
621-
lw = mpl.rcParams.getdefault("lines.linewidth")
621+
lw = mpl.rcParams.get_default("lines.linewidth")
622622
mpl.rcParams["lines.linewidth"] = lw + 1
623623
mpl.rcdefaults()
624624
assert mpl.rcParams["webagg.port"] == 9000
625625
assert mpl.rcParams["lines.linewidth"] == lw
626+
627+
628+
def test_rcparams_clear():
629+
mpl.rcParams["image.lut"] = 128
630+
mpl.rcParams.clear()
631+
assert mpl.rcParams["image.lut"] == 256

0 commit comments

Comments
 (0)