aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/tests/pybind11_cross_module_tests.cpp
blob: 9379f3f259e5bea210a56654d7e5af0d06b3cfca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
138
139
140
141
142
143
144
145
146
147
148
149
/*
    tests/pybind11_cross_module_tests.cpp -- contains tests that require multiple modules

    Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>

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

#include <pybind11/stl_bind.h>

#include "local_bindings.h"
#include "pybind11_tests.h"
#include "test_exceptions.h"

#include <numeric>
#include <utility>

PYBIND11_MODULE(pybind11_cross_module_tests, m) {
    m.doc() = "pybind11 cross-module test module";

    // test_local_bindings.py tests:
    //
    // Definitions here are tested by importing both this module and the
    // relevant pybind11_tests submodule from a test_whatever.py

    // test_load_external
    bind_local<ExternalType1>(m, "ExternalType1", py::module_local());
    bind_local<ExternalType2>(m, "ExternalType2", py::module_local());

    // test_exceptions.py
    py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
    m.def("raise_runtime_error", []() {
        PyErr_SetString(PyExc_RuntimeError, "My runtime error");
        throw py::error_already_set();
    });
    m.def("raise_value_error", []() {
        PyErr_SetString(PyExc_ValueError, "My value error");
        throw py::error_already_set();
    });
    m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
    m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
    m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
    m.def("throw_local_error", []() { throw LocalException("just local"); });
    m.def("throw_local_simple_error", []() { throw LocalSimpleException("external mod"); });
    py::register_exception_translator([](std::exception_ptr p) {
        try {
            if (p) {
                std::rethrow_exception(p);
            }
        } catch (const shared_exception &e) {
            PyErr_SetString(PyExc_KeyError, e.what());
        }
    });

    // translate the local exception into a key error but only in this module
    py::register_local_exception_translator([](std::exception_ptr p) {
        try {
            if (p) {
                std::rethrow_exception(p);
            }
        } catch (const LocalException &e) {
            PyErr_SetString(PyExc_KeyError, e.what());
        }
    });

    // test_local_bindings.py
    // Local to both:
    bind_local<LocalType, 1>(m, "LocalType", py::module_local()).def("get2", [](LocalType &t) {
        return t.i + 2;
    });

    // Can only be called with our python type:
    m.def("local_value", [](LocalType &l) { return l.i; });

    // test_nonlocal_failure
    // This registration will fail (global registration when LocalFail is already registered
    // globally in the main test module):
    m.def("register_nonlocal", [m]() { bind_local<NonLocalType, 0>(m, "NonLocalType"); });

    // test_stl_bind_local
    // stl_bind.h binders defaults to py::module_local if the types are local or converting:
    py::bind_vector<LocalVec>(m, "LocalVec");
    py::bind_map<LocalMap>(m, "LocalMap");

    // test_stl_bind_global
    // and global if the type (or one of the types, for the map) is global (so these will fail,
    // assuming pybind11_tests is already loaded):
    m.def("register_nonlocal_vec", [m]() { py::bind_vector<NonLocalVec>(m, "NonLocalVec"); });
    m.def("register_nonlocal_map", [m]() { py::bind_map<NonLocalMap>(m, "NonLocalMap"); });
    // The default can, however, be overridden to global using `py::module_local()` or
    // `py::module_local(false)`.
    // Explicitly made local:
    py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
    // Explicitly made global (and so will fail to bind):
    m.def("register_nonlocal_map2",
          [m]() { py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false)); });

    // test_mixed_local_global
    // We try this both with the global type registered first and vice versa (the order shouldn't
    // matter).
    m.def("register_mixed_global_local",
          [m]() { bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local()); });
    m.def("register_mixed_local_global", [m]() {
        bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
    });
    m.def("get_mixed_gl", [](int i) { return MixedGlobalLocal(i); });
    m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });

    // test_internal_locals_differ
    m.def("local_cpp_types_addr",
          []() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });

    // test_stl_caster_vs_stl_bind
    py::bind_vector<std::vector<int>>(m, "VectorInt");

    m.def("load_vector_via_binding",
          [](std::vector<int> &v) { return std::accumulate(v.begin(), v.end(), 0); });

    // test_cross_module_calls
    m.def("return_self", [](LocalVec *v) { return v; });
    m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });

    class Dog : public pets::Pet {
    public:
        explicit Dog(std::string name) : Pet(std::move(name)) {}
    };
    py::class_<pets::Pet>(m, "Pet", py::module_local()).def("name", &pets::Pet::name);
    // Binding for local extending class:
    py::class_<Dog, pets::Pet>(m, "Dog").def(py::init<std::string>());
    m.def("pet_name", [](pets::Pet &p) { return p.name(); });

    py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
    m.def("get_gl_value", [](MixGL &o) { return o.i + 100; });

    py::class_<MixGL2>(m, "MixGL2", py::module_local()).def(py::init<int>());

    // test_vector_bool
    // We can't test both stl.h and stl_bind.h conversions of `std::vector<bool>` within
    // the same module (it would be an ODR violation). Therefore `bind_vector` of `bool`
    // is defined here and tested in `test_stl_binders.py`.
    py::bind_vector<std::vector<bool>>(m, "VectorBool");

    // test_missing_header_message
    // The main module already includes stl.h, but we need to test the error message
    // which appears when this header is missing.
    m.def("missing_header_arg", [](const std::vector<float> &) {});
    m.def("missing_header_return", []() { return std::vector<float>(); });
}