Skip to content

Commit b07377f

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 6e4c5c1 commit b07377f

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
@@ -1589,9 +1589,17 @@ def func(ax, *args, **kwargs): ...
15891589
The list of parameter names for which lookup into *data* should be
15901590
attempted. If None, replacement is attempted for all arguments.
15911591
label_namer : string, optional, default: None
1592-
If set e.g. to "namer", if a ``namer`` kwarg is passed as a string, and
1593-
a ``label`` kwarg is not passed, then pass the value of the ``namer``
1594-
kwarg as the ``label`` kwarg as well.
1592+
If set e.g. to "namer" (which must be a kwarg in the function's
1593+
signature -- not as ``**kwargs``), if the *namer* argument passed in is
1594+
a (string) key of *data* and no *label* kwarg is passed, then use the
1595+
(string) value of the *namer* as *label*. ::
1596+
1597+
@_preprocess_data(label_namer="foo")
1598+
def func(foo, label=None): ...
1599+
1600+
func("key", data={"key": value})
1601+
# is equivalent to
1602+
func.__wrapped__(value, label="key")
15951603
"""
15961604

15971605
if func is None: # Return the actual decorator.
@@ -1625,7 +1633,7 @@ def func(ax, *args, **kwargs): ...
16251633
assert (replace_names or set()) <= set(arg_names) or varkwargs_name, (
16261634
"Matplotlib internal error: invalid replace_names ({!r}) for {!r}"
16271635
.format(replace_names, func.__name__))
1628-
assert label_namer is None or label_namer in arg_names or varkwargs_name, (
1636+
assert label_namer is None or label_namer in arg_names, (
16291637
"Matplotlib internal error: invalid label_namer ({!r}) for {!r}"
16301638
.format(label_namer, func.__name__))
16311639

@@ -1656,26 +1664,19 @@ def inner(ax, *args, data=None, **kwargs):
16561664
bound.apply_defaults()
16571665
del bound.arguments["data"]
16581666

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

16801681
return func(*bound.args, **bound.kwargs)
16811682

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)