Commit 231e1678 by Jason Rhinelander Committed by Wenzel Jakob

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.
parent caa1379e
...@@ -650,11 +650,26 @@ protected: ...@@ -650,11 +650,26 @@ protected:
} }
msg += "\nInvoked with: "; msg += "\nInvoked with: ";
auto args_ = reinterpret_borrow<tuple>(args_in); auto args_ = reinterpret_borrow<tuple>(args_in);
bool some_args = false;
for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
if (!some_args) some_args = true;
else msg += ", ";
msg += pybind11::repr(args_[ti]); msg += pybind11::repr(args_[ti]);
if ((ti + 1) != args_.size() )
msg += ", ";
} }
if (kwargs_in) {
auto kwargs = reinterpret_borrow<dict>(kwargs_in);
if (kwargs.size() > 0) {
if (some_args) msg += "; ";
msg += "kwargs: ";
bool first = true;
for (auto kwarg : kwargs) {
if (first) first = false;
else msg += ", ";
msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
}
}
}
PyErr_SetString(PyExc_TypeError, msg.c_str()); PyErr_SetString(PyExc_TypeError, msg.c_str());
return nullptr; return nullptr;
} else if (!result) { } else if (!result) {
......
...@@ -34,12 +34,8 @@ def test_named_arguments(msg): ...@@ -34,12 +34,8 @@ def test_named_arguments(msg):
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
# noinspection PyArgumentList # noinspection PyArgumentList
kw_func2(x=5, y=10, z=12) kw_func2(x=5, y=10, z=12)
assert msg(excinfo.value) == """ assert excinfo.match(
kw_func2(): incompatible function arguments. The following argument types are supported: r'(?s)^kw_func2\(\): incompatible.*Invoked with: kwargs: ((x=5|y=10|z=12)(, |$)){3}$')
1. (x: int=100, y: int=200) -> str
Invoked with:
"""
assert kw_func4() == "{13 17}" assert kw_func4() == "{13 17}"
assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}" assert kw_func4(myList=[1, 2, 3]) == "{1 2 3}"
...@@ -74,7 +70,7 @@ def test_mixed_args_and_kwargs(msg): ...@@ -74,7 +70,7 @@ def test_mixed_args_and_kwargs(msg):
1. (arg0: int, arg1: float, *args) -> tuple 1. (arg0: int, arg1: float, *args) -> tuple
Invoked with: 1 Invoked with: 1
""" # noqa: E501 """ # noqa: E501 line too long
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert mpa() assert mpa()
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
...@@ -82,7 +78,7 @@ def test_mixed_args_and_kwargs(msg): ...@@ -82,7 +78,7 @@ def test_mixed_args_and_kwargs(msg):
1. (arg0: int, arg1: float, *args) -> tuple 1. (arg0: int, arg1: float, *args) -> tuple
Invoked with: Invoked with:
""" # noqa: E501 """ # noqa: E501 line too long
assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159}) assert mpk(-2, 3.5, pi=3.14159, e=2.71828) == (-2, 3.5, {'e': 2.71828, 'pi': 3.14159})
assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == ( assert mpak(7, 7.7, 7.77, 7.777, 7.7777, minusseven=-7) == (
...@@ -93,14 +89,20 @@ def test_mixed_args_and_kwargs(msg): ...@@ -93,14 +89,20 @@ def test_mixed_args_and_kwargs(msg):
assert mpakd(k=42) == (1, 3.14159, (), {'k': 42}) assert mpakd(k=42) == (1, 3.14159, (), {'k': 42})
assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == ( assert mpakd(1, 1, 2, 3, 5, 8, then=13, followedby=21) == (
1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21}) 1, 1, (2, 3, 5, 8), {'then': 13, 'followedby': 21})
# Arguments specified both positionally and via kwargs is an error: # Arguments specified both positionally and via kwargs should fail:
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert mpakd(1, i=1) assert mpakd(1, i=1)
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
mixed_plus_args_kwargs_defaults(): got multiple values for argument 'i' mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
""" 1. (i: int=1, j: float=3.14159, *args, **kwargs) -> tuple
Invoked with: 1; kwargs: i=1
""" # noqa: E501 line too long
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
assert mpakd(1, 2, j=1) assert mpakd(1, 2, j=1)
assert msg(excinfo.value) == """ assert msg(excinfo.value) == """
mixed_plus_args_kwargs_defaults(): got multiple values for argument 'j' mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
""" 1. (i: int=1, j: float=3.14159, *args, **kwargs) -> tuple
Invoked with: 1, 2; kwargs: j=1
""" # noqa: E501 line too long
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment