From 2819ce64a4fcc406822382b9ad70bbe12aec90bf Mon Sep 17 00:00:00 2001 From: Boris Staletic Date: Fri, 24 Jul 2020 18:43:59 +0200 Subject: [PATCH] Avoid attr("__repr__") in initialize_generic (#2317) If the default argument value is a class, and not an instance of a class, `a.value.attr("__repr__")` raises a `ValueError`. Switching to `repr(a.value)` makes this use case work. Fixes #2028 --- include/pybind11/pybind11.h | 2 +- tests/test_kwargs_and_defaults.cpp | 5 +++++ tests/test_kwargs_and_defaults.py | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ee2870524..1a415a405 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -228,7 +228,7 @@ protected: if (a.descr) a.descr = strdup(a.descr); else if (a.value) - a.descr = strdup(a.value.attr("__repr__")().cast().c_str()); + a.descr = strdup(repr(a.value).cast().c_str()); } rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 8f095fe4a..64bc2377b 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -123,4 +123,9 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { py::class_(m, "KWClass") .def("foo0", &KWClass::foo) .def("foo1", &KWClass::foo, "x"_a, "y"_a); + + // Make sure a class (not an instance) can be used as a default argument. + // The return value doesn't matter, only that the module is importable. + m.def("class_default_argument", [](py::object a) { return py::repr(a); }, + "a"_a = py::module::import("decimal").attr("Decimal")); } diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index 531a9fdae..dad40dbeb 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -191,3 +191,5 @@ def test_args_refcount(): # tuple without having to inc_ref the individual elements, but here we can't, hence the extra # refs. assert m.mixed_args_refcount(myval, myval, myval) == (exp3 + 3, exp3 + 3, exp3 + 3) + + assert m.class_default_argument() == ""