8000 Include close matches when key not found · matplotlib/matplotlib@43bdfce · GitHub
[go: up one dir, main page]

Skip to content

Commit 43bdfce

Browse files
committed
Include close matches when key not found
1 parent abda9dd commit 43bdfce

File tree

4 files changed

+55
-8
lines changed

4 files changed

+55
-8
lines changed

lib/matplotlib/__init__.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -740,12 +740,16 @@ def __setitem__(self, key, val):
740740
and val is rcsetup._auto_backend_sentinel
741741
and "backend" in self):
742742
return
743+
744+
_api.check_in_keys(
745+
key,
746+
self.validate,
747+
error_string=("{value} is not a valid rc parameter. "
748+
"See rcParams.keys() for a list of valid parameters. "
749+
"{matches_str}")
750+
)
743751
try:
744752
cval = self.validate[key](val)
745-
except KeyError as err:
746-
raise KeyError(
747-
f"{key} is not a valid rc parameter (see rcParams.keys() for "
748-
f"a list of valid parameters)") from err
749753
except ValueError as ve:
750754
raise ValueError(f"Key {key}: {ve}") from None
751755
self._set(key, cval)

lib/matplotlib/_api/__init__.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
"""
1212

13+
import difflib
1314
import functools
1415
import itertools
1516
import pathlib
@@ -139,6 +140,35 @@ def check_in_list(values, /, *, _print_supported_values=True, **kwargs):
139140
raise ValueError(msg)
140141

141142

143+
def check_in_keys(value, mappable, *,
144+
error_string="{value!r} not found. {matches_str}"):
145+
"""
146+
Check if *value* is in the keys of *mappable*.
147+
148+
Parameters
149+
----------
150+
value :
151+
Value to check for in keys of *mappable*.
152+
mappable :
153+
A mappable object with keys.
154+
error_string:
155+
String to use to format error.
156+
Must contain fields for *value* and *matches_str*.
157+
158+
Raises
159+
------
160+
KeyError
161+
If *value* is not in the keys of *mappable*.
162+
"""
163+
valid = list(mappable)
164+
if value not in valid:
165+
matches_str = ""
166+
if len(best := difflib.get_close_matches(value, valid, cutoff=.1)):
167+
matches_str = f"Did you mean one of {best}?"
168+
raise KeyError(error_string.format(value=value, matches_str=matches_str))
169+
170+
171+
142172
def check_shape(shape, /, **kwargs):
143173
"""
144174
For each *key, value* pair in *kwargs*, check that *value* has the shape *shape*;

lib/matplotlib/cm.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,12 @@ def __init__(self, cmaps):
9292
self._builtin_cmaps = tuple(cmaps)
9393

9494
def __getitem__(self, item):
95-
try:
96-
return self._cmaps[item].copy()
97-
except KeyError:
98-
raise KeyError(f"{item!r} is not a known colormap name") from None
95+
_api.check_in_keys(
96+
item,
97+
self._cmaps,
98+
error_string="{value!r} is not a known colormap name. {matches_str}"
99+
)
100+
return self._cmaps[item].copy()
99101

100102
def __iter__(self):
101103
return iter(self._cmaps)

lib/matplotlib/tests/test_colors.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,3 +1828,14 @@ def test_LinearSegmentedColormap_from_list_value_color_tuple():
18281828
cmap([value for value, _ in value_color_tuples]),
18291829
to_rgba_array([color for _, color in value_color_tuples]),
18301830
)
1831+
1832+
1833+
def test_close_error_name():
1834+
with pytest.raises(KeyError) as exinfo:
1835+
matplotlib.colormaps["grays"]
1836+
1837+
msg = exinfo.value.args[0]
1838+
assert msg == (
1839+
"'grays' is not a known colormap name. "
1840+
"Did you mean one of ['gray', 'Grays', 'gray_r']?"
1841+
)

0 commit comments

Comments
 (0)
0