aboutsummaryrefslogtreecommitdiff
path: root/libs/plugin_python/src/pybind11-qt/pybind11_qt_sip.cpp
blob: 69ad4b866cb861df68c2a379b0c2eec4b85d5133 (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
#include "pybind11_qt/details/pybind11_qt_sip.h"

#include <stdexcept>

#include <QString>

#include <sip.h>

namespace py = pybind11;

namespace pybind11::detail::qt {

    const sipAPIDef* sipAPI()
    {
        std::string exception;
        static const sipAPIDef* sipApi = nullptr;
        if (sipApi == nullptr) {
            PyImport_ImportModule("PyQt6.sip");

            {
                auto errorObj = PyErr_Occurred();
                if (errorObj != NULL) {
                    PyObject *type, *value, *traceback;
                    PyErr_Fetch(&type, &value, &traceback);
                    PyErr_NormalizeException(&type, &value, &traceback);
                    if (traceback != NULL) {
                        py::handle h_type(type);
                        py::handle h_val(value);
                        py::handle h_tb(traceback);
                        py::object tb(py::module_::import("traceback"));
                        py::object fmt_exp(tb.attr("format_exception"));
                        py::object exp_list(fmt_exp(h_type, h_val, h_tb));
                        py::object exp_str(py::str("\n").attr("join")(exp_list));
                        exception = exp_str.cast<std::string>();
                    }
                    PyErr_Restore(type, value, traceback);
                    throw std::runtime_error{"Failed to load SIP API: " + exception};
                }
            }

            sipApi = (const sipAPIDef*)PyCapsule_Import("PyQt6.sip._C_API", 0);
            if (sipApi == NULL) {
                auto errorObj = PyErr_Occurred();
                if (errorObj != NULL) {
                    PyObject *type, *value, *traceback;
                    PyErr_Fetch(&type, &value, &traceback);
                    PyErr_NormalizeException(&type, &value, &traceback);
                    if (traceback != NULL) {
                        py::handle h_type(type);
                        py::handle h_val(value);
                        py::handle h_tb(traceback);
                        py::object tb(py::module_::import("traceback"));
                        py::object fmt_exp(tb.attr("format_exception"));
                        py::object exp_list(fmt_exp(h_type, h_val, h_tb));
                        py::object exp_str(py::str("\n").attr("join")(exp_list));
                        exception = exp_str.cast<std::string>();
                    }
                    PyErr_Restore(type, value, traceback);
                }
                throw std::runtime_error{"Failed to load SIP API: " + exception};
            }
        }
        return sipApi;
    }

    namespace sip {
        const sipTypeDef* api_find_type(const char* type)
        {
            return sipAPI()->api_find_type(type);
        }

        int api_can_convert_to_type(PyObject* pyObj, const sipTypeDef* td, int flags)
        {
            return sipAPI()->api_can_convert_to_type(pyObj, td, flags);
        }

        void api_transfer_to(PyObject* self, PyObject* owner)
        {
            sipAPI()->api_transfer_to(self, owner);
        }

        void api_transfer_back(PyObject* self)
        {
            sipAPI()->api_transfer_back(self);
        }

        PyObject* api_convert_from_type(void* cpp, const sipTypeDef* td, PyObject*)
        {
            return sipAPI()->api_convert_from_type(cpp, td, 0);
        }

        void* extract_data(PyObject* ptr)
        {
            if (PyObject_TypeCheck(ptr, sipAPI()->api_simplewrapper_type)) {
                return reinterpret_cast<sipSimpleWrapper*>(ptr)->data;
            }
            else if (PyObject_TypeCheck(ptr, sipAPI()->api_wrapper_type)) {
                return reinterpret_cast<sipWrapper*>(ptr)->super.data;
            }
            return nullptr;
        }

    }  // namespace sip

}  // namespace pybind11::detail::qt