blob: 81fe8bfbe952e5bcc68ba70e229925004316d161 [file] [log] [blame]
Wenzel Jakob38bd7112015-07-05 20:05:44 +02001/*
Dean Moldovana0c1ccf2016-08-12 13:50:00 +02002 tests/pybind11_tests.cpp -- pybind example plugin
Wenzel Jakob38bd7112015-07-05 20:05:44 +02003
Wenzel Jakob8cb6cb32016-04-17 20:21:41 +02004 Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
Wenzel Jakob38bd7112015-07-05 20:05:44 +02005
6 All rights reserved. Use of this source code is governed by a
7 BSD-style license that can be found in the LICENSE file.
8*/
9
Dean Moldovana0c1ccf2016-08-12 13:50:00 +020010#include "pybind11_tests.h"
11#include "constructor_stats.h"
Wenzel Jakob38bd7112015-07-05 20:05:44 +020012
Dean Moldovan83e328f2017-06-09 00:44:49 +020013#include <functional>
14#include <list>
15
Jason Rhinelander0558a9a2017-02-01 04:36:29 -050016/*
17For testing purposes, we define a static global variable here in a function that each individual
18test .cpp calls with its initialization lambda. It's convenient here because we can just not
19compile some test files to disable/ignore some of the test code.
20
21It is NOT recommended as a way to use pybind11 in practice, however: the initialization order will
22be essentially random, which is okay for our test scripts (there are no dependencies between the
23individual pybind11 test .cpp files), but most likely not what you want when using pybind11
24productively.
25
26Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions"
27section of the documentation for good practice on splitting binding code over multiple files.
28*/
Jason Rhinelander52f4be82016-09-03 14:54:22 -040029std::list<std::function<void(py::module &)>> &initializers() {
30 static std::list<std::function<void(py::module &)>> inits;
31 return inits;
32}
Wenzel Jakob38bd7112015-07-05 20:05:44 +020033
Dean Moldovan83e328f2017-06-09 00:44:49 +020034test_initializer::test_initializer(Initializer init) {
35 initializers().push_back(init);
36}
37
38test_initializer::test_initializer(const char *submodule_name, Initializer init) {
39 initializers().push_back([=](py::module &parent) {
40 auto m = parent.def_submodule(submodule_name);
41 init(m);
42 });
Jason Rhinelander52f4be82016-09-03 14:54:22 -040043}
Wenzel Jakob9e0a0562016-05-05 20:33:54 +020044
Jason Rhinelander3f589372016-08-07 13:05:26 -040045void bind_ConstructorStats(py::module &m) {
46 py::class_<ConstructorStats>(m, "ConstructorStats")
47 .def("alive", &ConstructorStats::alive)
48 .def("values", &ConstructorStats::values)
49 .def_readwrite("default_constructions", &ConstructorStats::default_constructions)
50 .def_readwrite("copy_assignments", &ConstructorStats::copy_assignments)
51 .def_readwrite("move_assignments", &ConstructorStats::move_assignments)
52 .def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
53 .def_readwrite("move_constructions", &ConstructorStats::move_constructions)
Jason Rhinelander14e70652017-04-21 17:14:22 -040054 .def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
55
56 // Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances
57 // to allow instance cleanup checks (invokes a GC first)
58 .def_static("detail_reg_inst", []() {
59 ConstructorStats::gc();
60 return py::detail::get_internals().registered_instances.size();
61 })
62 ;
Jason Rhinelander3f589372016-08-07 13:05:26 -040063}
64
Dean Moldovan443ab592017-04-24 01:51:44 +020065PYBIND11_MODULE(pybind11_tests, m) {
66 m.doc() = "pybind11 test module";
Wenzel Jakob38bd7112015-07-05 20:05:44 +020067
Jason Rhinelander3f589372016-08-07 13:05:26 -040068 bind_ConstructorStats(m);
69
Dean Moldovan83e328f2017-06-09 00:44:49 +020070#if !defined(NDEBUG)
71 m.attr("debug_enabled") = true;
72#else
73 m.attr("debug_enabled") = false;
74#endif
75
76 py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")
77 .def(py::init<>())
78 .def(py::init<int>())
79 .def("get_value", &UserType::value, "Get value using a method")
80 .def_property_readonly("value", &UserType::value, "Get value using a property")
81 .def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
82
83 py::class_<IncType, UserType>(m, "IncType")
84 .def(py::init<>())
85 .def(py::init<int>())
86 .def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); });
87
Jason Rhinelander52f4be82016-09-03 14:54:22 -040088 for (const auto &initializer : initializers())
89 initializer(m);
Wenzel Jakob38bd7112015-07-05 20:05:44 +020090
Jason Rhinelander3f1ff3f2016-12-12 17:42:52 -050091 if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = false;
Wenzel Jakob38bd7112015-07-05 20:05:44 +020092}