Skip to content

Commit ddcf9fd

Browse files
committed
Show kwargs in failed method invocation
With the previous commit, output can be very confusing because you only see positional arguments in the "invoked with" line, but you can have a failure from kwargs as well (in particular, when a value is invalidly specified via both via positional and kwargs). This commits adds kwargs to the output, and updates the associated tests to match.
1 parent 7889139 commit ddcf9fd

File tree

2 files changed

+32
-15
lines changed

2 files changed

+32
-15
lines changed

include/pybind11/pybind11.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,11 +650,26 @@ class cpp_function : public function {
650650
}
651651
msg += "\nInvoked with: ";
652652
auto args_ = reinterpret_borrow<tuple>(args_in);
653+
bool some_args = false;
653654
for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
655+
if (!some_args) some_args = true;
656+
else msg += ", ";
654657
msg += pybind11::repr(args_[ti]);
655-
if ((ti + 1) != args_.size() )
656-
msg += ", ";
657658
}
659+
if (kwargs_in) {
660+
auto kwargs = reinterpret_borrow<dict>(kwargs_in);
661+
if (kwargs.size() > 0) {
662+
if (some_args) msg += "; ";
663+
msg += "kwargs: ";
664+
bool first = true;
665+
for (auto kwarg : kwargs) {
666+
if (first) first = false;
667+
else msg += ", ";
668+
msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
669+
}
670+
}
671+
}
672+
658673
PyErr_SetString(PyExc_TypeError, msg.c_str());
659674
return nullptr;
660675
} else if (!result) {

tests/test_kwargs_and_defaults.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,8 @@ def test_named_arguments(msg):
3434
with pytest.raises(TypeError) as excinfo:
3535
# noinspection PyArgumentList
3636
kw_func2(x=5, y=10, z=12)
37-
assert msg(excinfo.value) == """
38-
kw_func2(): incompatible function arguments. The following argument types are supported:
39-
1. (x: int=100, y: int=200) -> str
40-
41-
Invoked with:
42-
"""
37+
assert excinfo.match(
38+
r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$)){3}$')
4339

4440
assert kw_func4() == "{13 17}"
4541
assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
@@ -74,15 +70,15 @@ def test_mixed_args_and_kwargs(msg):
7470
1. (arg0: int, arg1: float, *args) -> tuple
7571
7672
Invoked with: 1
77-
""" # noqa: E501
73+
""" # noqa: E501 line too long
7874
with pytest.raises(TypeError) as excinfo:
7975
assert mpa()
8076
assert msg(excinfo.value) == """
8177
mixed_plus_args(): incompatible function arguments. The following argument types are supported:
8278
1. (arg0: int, arg1: float, *args) -> tuple
8379
8480
Invoked with:
85-
""" # noqa: E501
81+
""" # noqa: E501 line too long
8682

8783
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159})
8884
assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == (
@@ -93,14 +89,20 @@ def test_mixed_args_and_kwargs(msg):
9389
assert mpakd(k=42) == (1, 3.14159, (), {'k': 42})
9490
assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == (
9591
1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21})
96-
# Arguments specified both positionally and via kwargs is an error:
92+
# Arguments specified both positionally and via kwargs should fail:
9793
with pytest.raises(TypeError) as excinfo:
9894
assert mpakd(1, i=1)
9995
assert msg(excinfo.value) == """
100-
mixed_plus_args_kwargs_defaults(): got multiple values for argument 'i'
101-
"""
96+
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
97+
1. (i: int=1, j: float=3.14159, *args, **kwargs) -> tuple
98+
99+
Invoked with: 1; kwargs: i=1
100+
""" # noqa: E501 line too long
102101
with pytest.raises(TypeError) as excinfo:
103102
assert mpakd(1, 2, j=1)
104103
assert msg(excinfo.value) == """
105-
mixed_plus_args_kwargs_defaults(): got multiple values for argument 'j'
106-
"""
104+
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
105+
1. (i: int=1, j: float=3.14159, *args, **kwargs) -> tuple
106+
107+
Invoked with: 1, 2; kwargs: j=1
108+
""" # noqa: E501 line too long

0 commit comments

Comments
 (0)