test_methods_and_attributes.cpp 22 KB
Newer Older
1
/*
Dean Moldovan's avatar
Dean Moldovan committed
2
    tests/test_methods_and_attributes.cpp -- constructors, deconstructors, attribute access,
3
4
5
6
7
8
9
10
    __str__, argument and return value conventions

    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

Dean Moldovan's avatar
Dean Moldovan committed
11
12
#include "pybind11_tests.h"
#include "constructor_stats.h"
13
14
15

class ExampleMandA {
public:
16
17
18
19
20
21
    ExampleMandA() { print_default_created(this); }
    ExampleMandA(int value) : value(value) { print_created(this, value); }
    ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); }
    ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); }
    ~ExampleMandA() { print_destroyed(this); }

22
23
24
25
    std::string toString() {
        return "ExampleMandA[value=" + std::to_string(value) + "]";
    }

26
27
    void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
    void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
28

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    void add1(ExampleMandA other) { value += other.value; }         // passing by value
    void add2(ExampleMandA &other) { value += other.value; }        // passing by reference
    void add3(const ExampleMandA &other) { value += other.value; }  // passing by const reference
    void add4(ExampleMandA *other) { value += other->value; }       // passing by pointer
    void add5(const ExampleMandA *other) { value += other->value; } // passing by const pointer

    void add6(int other) { value += other; }                        // passing by value
    void add7(int &other) { value += other; }                       // passing by reference
    void add8(const int &other) { value += other; }                 // passing by const reference
    void add9(int *other) { value += *other; }                      // passing by pointer
    void add10(const int *other) { value += *other; }               // passing by const pointer

    ExampleMandA self1() { return *this; }                          // return by value
    ExampleMandA &self2() { return *this; }                         // return by reference
    const ExampleMandA &self3() { return *this; }                   // return by const reference
    ExampleMandA *self4() { return this; }                          // return by pointer
    const ExampleMandA *self5() { return this; }                    // return by const pointer

    int internal1() { return value; }                               // return by value
    int &internal2() { return value; }                              // return by reference
    const int &internal3() { return value; }                        // return by const reference
    int *internal4() { return &value; }                             // return by pointer
    const int *internal5() { return &value; }                       // return by const pointer

    py::str overloaded()             { return "()"; }
    py::str overloaded(int)          { return "(int)"; }
55
56
57
58
    py::str overloaded(int, float)   { return "(int, float)"; }
    py::str overloaded(float, int)   { return "(float, int)"; }
    py::str overloaded(int, int)     { return "(int, int)"; }
    py::str overloaded(float, float) { return "(float, float)"; }
59
    py::str overloaded(int)          const { return "(int) const"; }
60
61
62
63
    py::str overloaded(int, float)   const { return "(int, float) const"; }
    py::str overloaded(float, int)   const { return "(float, int) const"; }
    py::str overloaded(int, int)     const { return "(int, int) const"; }
    py::str overloaded(float, float) const { return "(float, float) const"; }
64

65
    static py::str overloaded(float) { return "static float"; }
66

67
68
69
    int value = 0;
};

70
71
72
73
74
75
76
77
78
79
80
81
struct TestProperties {
    int value = 1;
    static int static_value;

    int get() const { return value; }
    void set(int v) { value = v; }

    static int static_get() { return static_value; }
    static void static_set(int v) { static_value = v; }
};
int TestProperties::static_value = 1;

82
83
84
85
86
87
struct TestPropertiesOverride : TestProperties {
    int value = 99;
    static int static_value;
};
int TestPropertiesOverride::static_value = 99;

88
struct TestPropRVP {
89
90
91
92
93
94
95
96
97
98
    UserType v1{1};
    UserType v2{1};
    static UserType sv1;
    static UserType sv2;

    const UserType &get1() const { return v1; }
    const UserType &get2() const { return v2; }
    UserType get_rvalue() const { return v2; }
    void set1(int v) { v1.set(v); }
    void set2(int v) { v2.set(v); }
99
};
100
101
UserType TestPropRVP::sv1(1);
UserType TestPropRVP::sv2(1);
102

103
104
105
// py::arg/py::arg_v testing: these arguments just record their argument when invoked
class ArgInspector1 { public: std::string arg = "(default arg inspector 1)"; };
class ArgInspector2 { public: std::string arg = "(default arg inspector 2)"; };
106
class ArgAlwaysConverts { };
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
namespace pybind11 { namespace detail {
template <> struct type_caster<ArgInspector1> {
public:
    PYBIND11_TYPE_CASTER(ArgInspector1, _("ArgInspector1"));

    bool load(handle src, bool convert) {
        value.arg = "loading ArgInspector1 argument " +
            std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed.  "
            "Argument value = " + (std::string) str(src);
        return true;
    }

    static handle cast(const ArgInspector1 &src, return_value_policy, handle) {
        return str(src.arg).release();
    }
};
template <> struct type_caster<ArgInspector2> {
public:
    PYBIND11_TYPE_CASTER(ArgInspector2, _("ArgInspector2"));

    bool load(handle src, bool convert) {
        value.arg = "loading ArgInspector2 argument " +
            std::string(convert ? "WITH" : "WITHOUT") + " conversion allowed.  "
            "Argument value = " + (std::string) str(src);
        return true;
    }

    static handle cast(const ArgInspector2 &src, return_value_policy, handle) {
        return str(src.arg).release();
    }
};
138
139
140
141
142
143
144
145
146
template <> struct type_caster<ArgAlwaysConverts> {
public:
    PYBIND11_TYPE_CASTER(ArgAlwaysConverts, _("ArgAlwaysConverts"));

    bool load(handle, bool convert) {
        return convert;
    }

    static handle cast(const ArgAlwaysConverts &, return_value_policy, handle) {
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
        return py::none().release();
    }
};
}}

// test_custom_caster_destruction
class DestructionTester {
public:
    DestructionTester() { print_default_created(this); }
    ~DestructionTester() { print_destroyed(this); }
    DestructionTester(const DestructionTester &) { print_copy_created(this); }
    DestructionTester(DestructionTester &&) { print_move_created(this); }
    DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; }
    DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; }
};
namespace pybind11 { namespace detail {
template <> struct type_caster<DestructionTester> {
    PYBIND11_TYPE_CASTER(DestructionTester, _("DestructionTester"));
    bool load(handle, bool) { return true; }

    static handle cast(const DestructionTester &, return_value_policy, handle) {
        return py::bool_(true).release();
169
170
    }
};
171
172
}}

173
174
175
176
177
178
179
180
// Test None-allowed py::arg argument policy
class NoneTester { public: int answer = 42; };
int none1(const NoneTester &obj) { return obj.answer; }
int none2(NoneTester *obj) { return obj ? obj->answer : -1; }
int none3(std::shared_ptr<NoneTester> &obj) { return obj ? obj->answer : -1; }
int none4(std::shared_ptr<NoneTester> *obj) { return obj && *obj ? (*obj)->answer : -1; }
int none5(std::shared_ptr<NoneTester> obj) { return obj ? obj->answer : -1; }

181
182
183
184
185
186
187
struct StrIssue {
    int val = -1;

    StrIssue() = default;
    StrIssue(int i) : val{i} {}
};

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Issues #854, #910: incompatible function args when member function/pointer is in unregistered base class
class UnregisteredBase {
public:
    void do_nothing() const {}
    void increase_value() { rw_value++; ro_value += 0.25; }
    void set_int(int v) { rw_value = v; }
    int get_int() const { return rw_value; }
    double get_double() const { return ro_value; }
    int rw_value = 42;
    double ro_value = 1.25;
};
class RegisteredDerived : public UnregisteredBase {
public:
    using UnregisteredBase::UnregisteredBase;
    double sum() const { return rw_value + ro_value; }
};

205
206
TEST_SUBMODULE(methods_and_attributes, m) {
    // test_methods_and_attributes
207
208
    py::class_<ExampleMandA> emna(m, "ExampleMandA");
    emna.def(py::init<>())
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
        .def(py::init<int>())
        .def(py::init<const ExampleMandA&>())
        .def("add1", &ExampleMandA::add1)
        .def("add2", &ExampleMandA::add2)
        .def("add3", &ExampleMandA::add3)
        .def("add4", &ExampleMandA::add4)
        .def("add5", &ExampleMandA::add5)
        .def("add6", &ExampleMandA::add6)
        .def("add7", &ExampleMandA::add7)
        .def("add8", &ExampleMandA::add8)
        .def("add9", &ExampleMandA::add9)
        .def("add10", &ExampleMandA::add10)
        .def("self1", &ExampleMandA::self1)
        .def("self2", &ExampleMandA::self2)
        .def("self3", &ExampleMandA::self3)
        .def("self4", &ExampleMandA::self4)
        .def("self5", &ExampleMandA::self5)
        .def("internal1", &ExampleMandA::internal1)
        .def("internal2", &ExampleMandA::internal2)
        .def("internal3", &ExampleMandA::internal3)
        .def("internal4", &ExampleMandA::internal4)
        .def("internal5", &ExampleMandA::internal5)
231
#if defined(PYBIND11_OVERLOAD_CAST)
232
233
        .def("overloaded", py::overload_cast<>(&ExampleMandA::overloaded))
        .def("overloaded", py::overload_cast<int>(&ExampleMandA::overloaded))
234
235
236
237
238
        .def("overloaded", py::overload_cast<int,   float>(&ExampleMandA::overloaded))
        .def("overloaded", py::overload_cast<float,   int>(&ExampleMandA::overloaded))
        .def("overloaded", py::overload_cast<int,     int>(&ExampleMandA::overloaded))
        .def("overloaded", py::overload_cast<float, float>(&ExampleMandA::overloaded))
        .def("overloaded_float", py::overload_cast<float, float>(&ExampleMandA::overloaded))
239
        .def("overloaded_const", py::overload_cast<int         >(&ExampleMandA::overloaded, py::const_))
240
241
242
243
        .def("overloaded_const", py::overload_cast<int,   float>(&ExampleMandA::overloaded, py::const_))
        .def("overloaded_const", py::overload_cast<float,   int>(&ExampleMandA::overloaded, py::const_))
        .def("overloaded_const", py::overload_cast<int,     int>(&ExampleMandA::overloaded, py::const_))
        .def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
244
#else
245
246
        .def("overloaded", static_cast<py::str (ExampleMandA::*)()>(&ExampleMandA::overloaded))
        .def("overloaded", static_cast<py::str (ExampleMandA::*)(int)>(&ExampleMandA::overloaded))
247
248
249
250
251
        .def("overloaded", static_cast<py::str (ExampleMandA::*)(int,   float)>(&ExampleMandA::overloaded))
        .def("overloaded", static_cast<py::str (ExampleMandA::*)(float,   int)>(&ExampleMandA::overloaded))
        .def("overloaded", static_cast<py::str (ExampleMandA::*)(int,     int)>(&ExampleMandA::overloaded))
        .def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
        .def("overloaded_float", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
252
        .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int         ) const>(&ExampleMandA::overloaded))
253
254
255
256
        .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int,   float) const>(&ExampleMandA::overloaded))
        .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float,   int) const>(&ExampleMandA::overloaded))
        .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int,     int) const>(&ExampleMandA::overloaded))
        .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))
257
#endif
258
        // test_no_mixed_overloads
259
260
        // Raise error if trying to mix static/non-static overloads on the same name:
        .def_static("add_mixed_overloads1", []() {
261
            auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
262
            emna.def       ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
263
                .def_static("overload_mixed1", static_cast<py::str (              *)(float   )>(&ExampleMandA::overloaded));
264
265
        })
        .def_static("add_mixed_overloads2", []() {
266
267
            auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
            emna.def_static("overload_mixed2", static_cast<py::str (              *)(float   )>(&ExampleMandA::overloaded))
268
269
                .def       ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
        })
270
        .def("__str__", &ExampleMandA::toString)
Wenzel Jakob's avatar
Wenzel Jakob committed
271
        .def_readwrite("value", &ExampleMandA::value);
Dean Moldovan's avatar
Dean Moldovan committed
272

273
    // test_copy_method
274
275
276
    // Issue #443: can't call copied methods in Python 3
    emna.attr("add2b") = emna.attr("add2");

277
    // test_properties, test_static_properties, test_static_cls
278
    py::class_<TestProperties>(m, "TestProperties")
279
280
281
282
283
284
285
286
287
288
289
        .def(py::init<>())
        .def_readonly("def_readonly", &TestProperties::value)
        .def_readwrite("def_readwrite", &TestProperties::value)
        .def_property_readonly("def_property_readonly", &TestProperties::get)
        .def_property("def_property", &TestProperties::get, &TestProperties::set)
        .def_readonly_static("def_readonly_static", &TestProperties::static_value)
        .def_readwrite_static("def_readwrite_static", &TestProperties::static_value)
        .def_property_readonly_static("def_property_readonly_static",
                                      [](py::object) { return TestProperties::static_get(); })
        .def_property_static("def_property_static",
                             [](py::object) { return TestProperties::static_get(); },
290
291
292
293
                             [](py::object, int v) { TestProperties::static_set(v); })
        .def_property_static("static_cls",
                             [](py::object cls) { return cls; },
                             [](py::object cls, py::function f) { f(cls); });
294

295
296
297
298
299
    py::class_<TestPropertiesOverride, TestProperties>(m, "TestPropertiesOverride")
        .def(py::init<>())
        .def_readonly("def_readonly", &TestPropertiesOverride::value)
        .def_readonly_static("def_readonly_static", &TestPropertiesOverride::static_value);

300
301
302
303
    auto static_get1 = [](py::object) -> const UserType & { return TestPropRVP::sv1; };
    auto static_get2 = [](py::object) -> const UserType & { return TestPropRVP::sv2; };
    auto static_set1 = [](py::object, int v) { TestPropRVP::sv1.set(v); };
    auto static_set2 = [](py::object, int v) { TestPropRVP::sv2.set(v); };
304
305
    auto rvp_copy = py::return_value_policy::copy;

306
    // test_property_return_value_policies
307
    py::class_<TestPropRVP>(m, "TestPropRVP")
308
309
310
311
312
313
314
315
316
317
318
319
320
        .def(py::init<>())
        .def_property_readonly("ro_ref", &TestPropRVP::get1)
        .def_property_readonly("ro_copy", &TestPropRVP::get2, rvp_copy)
        .def_property_readonly("ro_func", py::cpp_function(&TestPropRVP::get2, rvp_copy))
        .def_property("rw_ref", &TestPropRVP::get1, &TestPropRVP::set1)
        .def_property("rw_copy", &TestPropRVP::get2, &TestPropRVP::set2, rvp_copy)
        .def_property("rw_func", py::cpp_function(&TestPropRVP::get2, rvp_copy), &TestPropRVP::set2)
        .def_property_readonly_static("static_ro_ref", static_get1)
        .def_property_readonly_static("static_ro_copy", static_get2, rvp_copy)
        .def_property_readonly_static("static_ro_func", py::cpp_function(static_get2, rvp_copy))
        .def_property_static("static_rw_ref", static_get1, static_set1)
        .def_property_static("static_rw_copy", static_get2, static_set2, rvp_copy)
        .def_property_static("static_rw_func", py::cpp_function(static_get2, rvp_copy), static_set2)
321
        // test_property_rvalue_policy
322
        .def_property_readonly("rvalue", &TestPropRVP::get_rvalue)
323
        .def_property_readonly_static("static_rvalue", [](py::object) { return UserType(1); });
324

325
    // test_metaclass_override
326
327
328
329
    struct MetaclassOverride { };
    py::class_<MetaclassOverride>(m, "MetaclassOverride", py::metaclass((PyObject *) &PyType_Type))
        .def_property_readonly_static("readonly", [](py::object) { return 1; });

330
#if !defined(PYPY_VERSION)
331
332
333
334
335
336
    // test_dynamic_attributes
    class DynamicClass {
    public:
        DynamicClass() { print_default_created(this); }
        ~DynamicClass() { print_destroyed(this); }
    };
Dean Moldovan's avatar
Dean Moldovan committed
337
338
    py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
        .def(py::init());
339

340
    class CppDerivedDynamicClass : public DynamicClass { };
341
342
    py::class_<CppDerivedDynamicClass, DynamicClass>(m, "CppDerivedDynamicClass")
        .def(py::init());
343
#endif
344

345
346
    // test_noconvert_args
    //
347
348
349
    // Test converting.  The ArgAlwaysConverts is just there to make the first no-conversion pass
    // fail so that our call always ends up happening via the second dispatch (the one that allows
    // some conversion).
350
351
    class ArgInspector {
    public:
352
353
        ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; }
        std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) {
354
355
            return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg;
        }
356
        static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; }
357
358
359
    };
    py::class_<ArgInspector>(m, "ArgInspector")
        .def(py::init<>())
360
361
362
        .def("f", &ArgInspector::f, py::arg(), py::arg() = ArgAlwaysConverts())
        .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts())
        .def_static("h", &ArgInspector::h, py::arg().noconvert(), py::arg() = ArgAlwaysConverts())
363
        ;
364
365
    m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; },
            py::arg().noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts());
366
367
368

    m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
    m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
369
370
    m.def("ints_preferred", [](int i) { return i / 2; }, py::arg("i"));
    m.def("ints_only", [](int i) { return i / 2; }, py::arg("i").noconvert());
371

372
    // test_bad_arg_default
373
    // Issue/PR #648: bad arg default debugging output
374
375
376
377
378
379
#if !defined(NDEBUG)
    m.attr("debug_enabled") = true;
#else
    m.attr("debug_enabled") = false;
#endif
    m.def("bad_arg_def_named", []{
Jason Rhinelander's avatar
Jason Rhinelander committed
380
        auto m = py::module::import("pybind11_tests");
381
        m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());
382
383
    });
    m.def("bad_arg_def_unnamed", []{
Jason Rhinelander's avatar
Jason Rhinelander committed
384
        auto m = py::module::import("pybind11_tests");
385
        m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
386
    });
387

388
    // test_accepts_none
389
390
391
392
393
394
395
396
397
398
399
400
401
    py::class_<NoneTester, std::shared_ptr<NoneTester>>(m, "NoneTester")
        .def(py::init<>());
    m.def("no_none1", &none1, py::arg().none(false));
    m.def("no_none2", &none2, py::arg().none(false));
    m.def("no_none3", &none3, py::arg().none(false));
    m.def("no_none4", &none4, py::arg().none(false));
    m.def("no_none5", &none5, py::arg().none(false));
    m.def("ok_none1", &none1);
    m.def("ok_none2", &none2, py::arg().none(true));
    m.def("ok_none3", &none3);
    m.def("ok_none4", &none4, py::arg().none(true));
    m.def("ok_none5", &none5);

402
    // test_str_issue
403
404
405
406
407
408
409
    // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
    py::class_<StrIssue>(m, "StrIssue")
        .def(py::init<int>())
        .def(py::init<>())
        .def("__str__", [](const StrIssue &si) {
            return "StrIssue[" + std::to_string(si.val) + "]"; }
        );
410

411
412
    // test_unregistered_base_implementations
    //
413
414
415
416
417
418
419
420
421
422
423
    // Issues #854/910: incompatible function args when member function/pointer is in unregistered
    // base class The methods and member pointers below actually resolve to members/pointers in
    // UnregisteredBase; before this test/fix they would be registered via lambda with a first
    // argument of an unregistered type, and thus uncallable.
    py::class_<RegisteredDerived>(m, "RegisteredDerived")
        .def(py::init<>())
        .def("do_nothing", &RegisteredDerived::do_nothing)
        .def("increase_value", &RegisteredDerived::increase_value)
        .def_readwrite("rw_value", &RegisteredDerived::rw_value)
        .def_readonly("ro_value", &RegisteredDerived::ro_value)
        // These should trigger a static_assert if uncommented
424
425
        //.def_readwrite("fails", &UserType::value) // should trigger a static_assert if uncommented
        //.def_readonly("fails", &UserType::value) // should trigger a static_assert if uncommented
426
427
428
429
430
431
432
433
        .def_property("rw_value_prop", &RegisteredDerived::get_int, &RegisteredDerived::set_int)
        .def_property_readonly("ro_value_prop", &RegisteredDerived::get_double)
        // This one is in the registered class:
        .def("sum", &RegisteredDerived::sum)
        ;

    using Adapted = decltype(py::method_adaptor<RegisteredDerived>(&RegisteredDerived::do_nothing));
    static_assert(std::is_same<Adapted, void (RegisteredDerived::*)() const>::value, "");
434
435
436
437
438
439
440
441
442
443
444
445

    // test_custom_caster_destruction
    // Test that `take_ownership` works on types with a custom type caster when given a pointer

    // default policy: don't take ownership:
    m.def("custom_caster_no_destroy", []() { static auto *dt = new DestructionTester(); return dt; });

    m.def("custom_caster_destroy", []() { return new DestructionTester(); },
            py::return_value_policy::take_ownership); // Takes ownership: destroy when finished
    m.def("custom_caster_destroy_const", []() -> const DestructionTester * { return new DestructionTester(); },
            py::return_value_policy::take_ownership); // Likewise (const doesn't inhibit destruction)
    m.def("destruction_tester_cstats", &ConstructorStats::get<DestructionTester>, py::return_value_policy::reference);
446
}