Skip to content

Commit 1eaacd1

Browse files
jagermanwjakob
authored andcommitted
Fix debugging output for nameless py::arg_v annotations (#648)
* Fix debugging output for nameless py::arg annotations This fixes a couple bugs with nameless py::arg() (introduced in #634) annotations: - the argument name was being used in debug mode without checking that it exists (which would result in the std::string construction throwing an exception for being invoked with a nullptr) - the error output says "keyword arguments", but py::arg_v() can now also be used for positional argument defaults. - the debugging output "in function named 'blah'" was overly verbose: changed it to just "in function 'blah'". * Fix missing space in debug test string * Moved tests from issues to methods_and_attributes
1 parent 93cc4bd commit 1eaacd1

File tree

4 files changed

+48
-6
lines changed

4 files changed

+48
-6
lines changed

include/pybind11/attr.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,19 +303,21 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
303303

304304
if (!a.value) {
305305
#if !defined(NDEBUG)
306-
auto descr = "'" + std::string(a.name) + ": " + a.type + "'";
306+
std::string descr("'");
307+
if (a.name) descr += std::string(a.name) + ": ";
308+
descr += a.type + "'";
307309
if (r->is_method) {
308310
if (r->name)
309311
descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'";
310312
else
311313
descr += " in method of '" + (std::string) str(r->scope) + "'";
312314
} else if (r->name) {
313-
descr += " in function named '" + (std::string) r->name + "'";
315+
descr += " in function '" + (std::string) r->name + "'";
314316
}
315-
pybind11_fail("arg(): could not convert default keyword argument "
317+
pybind11_fail("arg(): could not convert default argument "
316318
+ descr + " into a Python object (type not registered yet?)");
317319
#else
318-
pybind11_fail("arg(): could not convert default keyword argument "
320+
pybind11_fail("arg(): could not convert default argument "
319321
"into a Python object (type not registered yet?). "
320322
"Compile in debug mode for more information.");
321323
#endif

tests/test_issues.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ namespace std {
7474
template <> struct hash<TplConstrClass> { size_t operator()(const TplConstrClass &t) const { return std::hash<std::string>()(t.str); } };
7575
}
7676

77-
7877
void init_issues(py::module &m) {
7978
py::module m2 = m.def_submodule("issues");
8079

@@ -397,5 +396,5 @@ void init_issues(py::module &m) {
397396
#endif
398397
}
399398

400-
// MSVC workaround: trying to use a lambda here crashes MSCV
399+
// MSVC workaround: trying to use a lambda here crashes MSVC
401400
test_initializer issues(&init_issues);

tests/test_methods_and_attributes.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ template <> struct type_caster<ArgAlwaysConverts> {
150150
};
151151
}}
152152

153+
/// Issue/PR #648: bad arg default debugging output
154+
class NotRegistered {};
155+
153156
test_initializer methods_and_attributes([](py::module &m) {
154157
py::class_<ExampleMandA>(m, "ExampleMandA")
155158
.def(py::init<>())
@@ -270,4 +273,18 @@ test_initializer methods_and_attributes([](py::module &m) {
270273
m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
271274
m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
272275

276+
/// Issue/PR #648: bad arg default debugging output
277+
#if !defined(NDEBUG)
278+
m.attr("debug_enabled") = true;
279+
#else
280+
m.attr("debug_enabled") = false;
281+
#endif
282+
m.def("bad_arg_def_named", []{
283+
auto m = py::module::import("pybind11_tests.issues");
284+
m.def("should_fail", [](int, NotRegistered) {}, py::arg(), py::arg("a") = NotRegistered());
285+
});
286+
m.def("bad_arg_def_unnamed", []{
287+
auto m = py::module::import("pybind11_tests.issues");
288+
m.def("should_fail", [](int, NotRegistered) {}, py::arg(), py::arg() = NotRegistered());
289+
});
273290
});

tests/test_methods_and_attributes.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,27 @@ def test_noconvert_args(msg):
255255
256256
Invoked with: 4
257257
"""
258+
259+
260+
def test_bad_arg_default(msg):
261+
from pybind11_tests import debug_enabled, bad_arg_def_named, bad_arg_def_unnamed
262+
263+
with pytest.raises(RuntimeError) as excinfo:
264+
bad_arg_def_named()
265+
assert msg(excinfo.value) == (
266+
"arg(): could not convert default argument 'a: NotRegistered' in function 'should_fail' "
267+
"into a Python object (type not registered yet?)"
268+
if debug_enabled else
269+
"arg(): could not convert default argument into a Python object (type not registered "
270+
"yet?). Compile in debug mode for more information."
271+
)
272+
273+
with pytest.raises(RuntimeError) as excinfo:
274+
bad_arg_def_unnamed()
275+
assert msg(excinfo.value) == (
276+
"arg(): could not convert default argument 'NotRegistered' in function 'should_fail' "
277+
"into a Python object (type not registered yet?)"
278+
if debug_enabled else
279+
"arg(): could not convert default argument into a Python object (type not registered "
280+
"yet?). Compile in debug mode for more information."
281+
)

0 commit comments

Comments
 (0)