Extend attribute and item accessor interface using object_api
diff --git a/tests/constructor_stats.h b/tests/constructor_stats.h
index 69e385e..5dd215f 100644
--- a/tests/constructor_stats.h
+++ b/tests/constructor_stats.h
@@ -103,7 +103,7 @@
int alive() {
// Force garbage collection to ensure any pending destructors are invoked:
- py::module::import("gc").attr("collect").operator py::object()();
+ py::module::import("gc").attr("collect")();
int total = 0;
for (const auto &p : _instances) if (p.second > 0) total += p.second;
return total;
diff --git a/tests/test_python_types.cpp b/tests/test_python_types.cpp
index 9dafe77..4ab90e6 100644
--- a/tests/test_python_types.cpp
+++ b/tests/test_python_types.cpp
@@ -203,7 +203,7 @@
py::print("no new line here", "end"_a=" -- ");
py::print("next print");
- auto py_stderr = py::module::import("sys").attr("stderr").cast<py::object>();
+ auto py_stderr = py::module::import("sys").attr("stderr");
py::print("this goes to stderr", "file"_a=py_stderr);
py::print("flush", "flush"_a=true);
@@ -222,4 +222,39 @@
auto d2 = py::dict("z"_a=3, **d1);
return d2;
});
+
+ m.def("test_accessor_api", [](py::object o) {
+ auto d = py::dict();
+
+ d["basic_attr"] = o.attr("basic_attr");
+
+ auto l = py::list();
+ for (const auto &item : o.attr("begin_end")) {
+ l.append(item);
+ }
+ d["begin_end"] = l;
+
+ d["operator[object]"] = o.attr("d")["operator[object]"_s];
+ d["operator[char *]"] = o.attr("d")["operator[char *]"];
+
+ d["attr(object)"] = o.attr("sub").attr("attr_obj");
+ d["attr(char *)"] = o.attr("sub").attr("attr_char");
+ try {
+ o.attr("sub").attr("missing").ptr();
+ } catch (const py::error_already_set &) {
+ d["missing_attr_ptr"] = "raised"_s;
+ }
+ try {
+ o.attr("missing").attr("doesn't matter");
+ } catch (const py::error_already_set &) {
+ d["missing_attr_chain"] = "raised"_s;
+ }
+
+ d["is_none"] = py::cast(o.attr("basic_attr").is_none());
+
+ d["operator()"] = o.attr("func")(1);
+ d["operator*"] = o.attr("func")(*o.attr("begin_end"));
+
+ return d;
+ });
});
diff --git a/tests/test_python_types.py b/tests/test_python_types.py
index fe58f93..4f2cdb2 100644
--- a/tests/test_python_types.py
+++ b/tests/test_python_types.py
@@ -248,3 +248,33 @@
from pybind11_tests import test_dict_keyword_constructor
assert test_dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
+
+
+def test_accessors():
+ from pybind11_tests import test_accessor_api
+
+ class SubTestObject:
+ attr_obj = 1
+ attr_char = 2
+
+ class TestObject:
+ basic_attr = 1
+ begin_end = [1, 2, 3]
+ d = {"operator[object]": 1, "operator[char *]": 2}
+ sub = SubTestObject()
+
+ def func(self, x, *args):
+ return self.basic_attr + x + sum(args)
+
+ d = test_accessor_api(TestObject())
+ assert d["basic_attr"] == 1
+ assert d["begin_end"] == [1, 2, 3]
+ assert d["operator[object]"] == 1
+ assert d["operator[char *]"] == 2
+ assert d["attr(object)"] == 1
+ assert d["attr(char *)"] == 2
+ assert d["missing_attr_ptr"] == "raised"
+ assert d["missing_attr_chain"] == "raised"
+ assert d["is_none"] is False
+ assert d["operator()"] == 2
+ assert d["operator*"] == 7