Skip to content

Commit 139d156

Browse files
committed
Make _preprocess_data stricter regarding label_namer.
Assert that label_namer (if given) is a parameter in the function signature (not "possibly" present via `**kwargs`). This seems more consistent with the expectations of the check later; in fact we can now just remove that check.
1 parent d9cecc2 commit 139d156

File tree

2 files changed

+23
-78
lines changed

2 files changed

+23
-78
lines changed

lib/matplotlib/__init__.py

+23-22
Original file line numberDiff line numberDiff line change
@@ -1585,9 +1585,17 @@ def func(ax, *args, **kwargs): ...
15851585
The list of parameter names for which lookup into *data* should be
15861586
attempted. If None, replacement is attempted for all arguments.
15871587
label_namer : string, optional, default: None
1588-
If set e.g. to "namer", if a ``namer`` kwarg is passed as a string, and
1589-
a ``label`` kwarg is not passed, then pass the value of the ``namer``
1590-
kwarg as the ``label`` kwarg as well.
1588+
If set e.g. to "namer" (which must be a kwarg in the function's
1589+
signature -- not as ``**kwargs``), if the *namer* argument passed in is
1590+
a (string) key of *data* and no *label* kwarg is passed, then use the
1591+
(string) value of the *namer* as *label*. ::
1592+
1593+
@_preprocess_data(label_namer="foo")
1594+
def func(foo, label=None): ...
1595+
1596+
func("key", data={"key": value})
1597+
# is equivalent to
1598+
func.__wrapped__(value, label="key")
15911599
"""
15921600

15931601
if func is None: # Return the actual decorator.
@@ -1621,7 +1629,7 @@ def func(ax, *args, **kwargs): ...
16211629
assert (replace_names or set()) <= set(arg_names) or varkwargs_name, (
16221630
"Matplotlib internal error: invalid replace_names ({!r}) for {!r}"
16231631
.format(replace_names, func.__name__))
1624-
assert label_namer is None or label_namer in arg_names or varkwargs_name, (
1632+
assert label_namer is None or label_namer in arg_names, (
16251633
"Matplotlib internal error: invalid label_namer ({!r}) for {!r}"
16261634
.format(label_namer, func.__name__))
16271635

@@ -1652,26 +1660,19 @@ def inner(ax, *args, data=None, **kwargs):
16521660
bound.apply_defaults()
16531661
del bound.arguments["data"]
16541662

1655-
all_kwargs = {**bound.arguments, **bound.kwargs}
16561663
if needs_label:
1657-
if label_namer not in all_kwargs:
1658-
cbook._warn_external(
1659-
"Tried to set a label via parameter {!r} in func {!r} but "
1660-
"couldn't find such an argument.\n(This is a programming "
1661-
"error, please report to the Matplotlib list!)".format(
1662-
label_namer, func.__name__),
1663-
RuntimeWarning)
1664+
all_kwargs = {**bound.arguments, **bound.kwargs}
1665+
# label_namer will be in all_kwargs as we asserted above that
1666+
# `label_namer is None or label_namer in arg_names`.
1667+
label = _label_from_arg(all_kwargs[label_namer], auto_label)
1668+
if "label" in arg_names:
1669+
bound.arguments["label"] = label
1670+
try:
1671+
bound.arguments.move_to_end(varkwargs_name)
1672+
except KeyError:
1673+
pass
16641674
else:
1665-
label = _label_from_arg(all_kwargs[label_namer], auto_label)
1666-
if "label" in arg_names:
1667-
bound.arguments["label"] = label
1668-
try:
1669-
bound.arguments.move_to_end(varkwargs_name)
1670-
except KeyError:
1671-
pass
1672-
else:
1673-
bound.arguments.setdefault(
1674-
varkwargs_name, {})["label"] = label
1675+
bound.arguments.setdefault(varkwargs_name, {})["label"] = label
16751676

16761677
return func(*bound.args, **bound.kwargs)
16771678

lib/matplotlib/tests/test_preprocess_data.py

-56
Original file line numberDiff line numberDiff line change
@@ -58,26 +58,6 @@ def func_no_ax_args(*args, **kwargs): pass
5858
with pytest.raises(AssertionError):
5959
_preprocess_data(label_namer="z")(func_args)
6060

61-
# but "ok-ish", if func has kwargs -> will show up at runtime :-(
62-
_preprocess_data(label_namer="z")(func_kwargs)
63-
_preprocess_data(label_namer="z")(func_no_ax_args)
64-
65-
66-
def test_label_namer_only_if_data():
67-
"""label_namer should only apply when data is passed."""
68-
69-
def real_func(x, y):
70-
pass
71-
72-
@_preprocess_data(label_namer="x")
73-
def func(*args, **kwargs):
74-
real_func(**kwargs)
75-
76-
func(None, x="a", y="b")
77-
with pytest.raises(TypeError):
78-
# This sets a label although the function can't handle it.
79-
func(None, x="a", y="b", data={"a": "A", "b": "B"})
80-
8161

8262
@pytest.mark.parametrize('func', all_funcs, ids=all_func_ids)
8363
def test_function_call_without_data(func):
@@ -178,42 +158,6 @@ def func_replace_all(ax, x, y, ls="x", label=None, w="NOT"):
178158
func_replace_all(None, x="a", y="b", w="x", label="text", data=data) ==
179159
"x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
180160

181-
@_preprocess_data(label_namer="y")
182-
def func_varags_replace_all(ax, *args, **kwargs):
183-
all_args = [None, None, "x", None, "xyz"]
184-
for i, v in enumerate(args):
185-
all_args[i] = v
186-
for i, k in enumerate(["x", "y", "ls", "label", "w"]):
187-
if k in kwargs:
188-
all_args[i] = kwargs[k]
189-
x, y, ls, label, w = all_args
190-
return "x: %s, y: %s, ls: %s, w: %s, label: %s" % (
191-
list(x), list(y), ls, w, label)
192-
193-
# in the first case, we can't get a "y" argument,
194-
# as we don't know the names of the *args
195-
assert (func_varags_replace_all(None, x="a", y="b", w="x", data=data) ==
196-
"x: [1, 2], y: [8, 9], ls: x, w: xyz, label: b")
197-
assert (
198-
func_varags_replace_all(None, "a", "b", w="x", label="", data=data) ==
199-
"x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
200-
assert (
201-
func_varags_replace_all(None, "a", "b", w="x", label="text",
202-
data=data) ==
203-
"x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
204-
assert (
205-
func_varags_replace_all(None, x="a", y="b", w="x", label="",
206-
data=data) ==
207-
"x: [1, 2], y: [8, 9], ls: x, w: xyz, label: ")
208-
assert (
209-
func_varags_replace_all(None, x="a", y="b", w="x", label="text",
210-
data=data) ==
211-
"x: [1, 2], y: [8, 9], ls: x, w: xyz, label: text")
212-
213-
with pytest.warns(RuntimeWarning):
214-
assert (func_varags_replace_all(None, "a", "b", w="x", data=data) ==
215-
"x: [1, 2], y: [8, 9], ls: x, w: xyz, label: None")
216-
217161

218162
def test_no_label_replacements():
219163
"""Test with "label_namer=None" -> no label replacement at all"""

0 commit comments

Comments
 (0)