diff --git a/include/podio/detail/Pythonizations.h b/include/podio/detail/Pythonizations.h index fb498750d..b8661eace 100644 --- a/include/podio/detail/Pythonizations.h +++ b/include/podio/detail/Pythonizations.h @@ -3,58 +3,17 @@ #define PY_SSIZE_T_CLEAN #include -#include #include namespace podio::detail::pythonizations { // Callback function for the subscript pythonization // Calls the `at` method and change exception type to IndexError if the index is out of range -static inline PyObject* subscript(PyObject* self, PyObject* index) { - PyObject* result = PyObject_CallMethod(self, "at", "O", index); - if (!result) { - PyObject* exc = PyErr_Occurred(); - // Check if the exception is `cppyy.gbl.std.out_of_range` - // Since PyImport_ImportModule("cppyy") fails, this workaround checks the exception name - if (exc && PyObject_HasAttrString(exc, "__name__")) { - PyObject* exc_name = PyObject_GetAttrString(exc, "__name__"); - if (exc_name) { - const char* name_cstr = PyUnicode_AsUTF8(exc_name); - if (name_cstr && strcmp(name_cstr, "out_of_range") == 0) { - PyErr_Clear(); - PyErr_SetString(PyExc_IndexError, "Index out of range"); - } - Py_DECREF(exc_name); - } - } - } - return result; -} +PyObject* subscript(PyObject* self, PyObject* index); // Helper to register the subscript pythonization callback as `__getitem__` method -static inline void pythonize_subscript(PyObject* klass, const std::string& name) { - static PyMethodDef ml = {"subscipt_pythonization", subscript, METH_VARARGS, R"( - Raise an `IndexError` exception if an index is invalid. - The `__getitem__` will return immutable datatype objects instead of the mutable ones. - )"}; - auto* func = PyCFunction_New(&ml, klass); - if (!func) { - throw std::runtime_error("Failed to create Python subscript function for class " + name); - } - auto* method = PyInstanceMethod_New(func); - if (!method) { - Py_DECREF(func); - throw std::runtime_error("Failed to create Python instance method for subscript for class " + name); - } - if (0 != PyObject_SetAttrString(klass, "__getitem__", method)) { - Py_DECREF(method); - Py_DECREF(func); - throw std::runtime_error("Failed to set __getitem__ attribute on class " + name); - } - Py_DECREF(func); - Py_DECREF(method); -} +void pythonize_subscript(PyObject* klass, const std::string& name); } // namespace podio::detail::pythonizations -#endif // PODIO_DETAIL_PYTHONIZATIONS_H +#endif // PODIO_DETAIL_PYTHONIZATIONS_H \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 260163ed1..2d2d312c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -61,6 +61,7 @@ SET(core_sources MurmurHash3.cpp SchemaEvolution.cc Glob.cc + Pythonizations.cc ) SET(core_headers @@ -79,6 +80,7 @@ SET(core_headers PODIO_ADD_LIB_AND_DICT(podio "${core_headers}" "${core_sources}" selection.xml) target_compile_options(podio PRIVATE -pthread) +target_link_libraries(podio PRIVATE Python3::Python) # For Frame.h if (ROOT_VERSION VERSION_LESS 6.36) target_compile_definitions(podio PUBLIC PODIO_ROOT_OLDER_6_36=1) diff --git a/src/Pythonizations.cc b/src/Pythonizations.cc new file mode 100644 index 000000000..5602dc016 --- /dev/null +++ b/src/Pythonizations.cc @@ -0,0 +1,55 @@ +#include "podio/detail/Pythonizations.h" + +#include +#include + +namespace podio::detail::pythonizations { + +// Callback function for the subscript pythonization +// Calls the `at` method and change exception type to IndexError if the index is out of range +PyObject* subscript(PyObject* self, PyObject* index) { + PyObject* result = PyObject_CallMethod(self, "at", "O", index); + if (!result) { + PyObject* exc = PyErr_Occurred(); + // Check if the exception is `cppyy.gbl.std.out_of_range` + // Since PyImport_ImportModule("cppyy") fails, this workaround checks the exception name + if (exc && PyObject_HasAttrString(exc, "__name__")) { + PyObject* exc_name = PyObject_GetAttrString(exc, "__name__"); + if (exc_name) { + const char* name_cstr = PyUnicode_AsUTF8(exc_name); + if (name_cstr && strcmp(name_cstr, "out_of_range") == 0) { + PyErr_Clear(); + PyErr_SetString(PyExc_IndexError, "Index out of range"); + } + Py_DECREF(exc_name); + } + } + } + return result; +} + +// Helper to register the subscript pythonization callback as `__getitem__` method +void pythonize_subscript(PyObject* klass, const std::string& name) { + static PyMethodDef ml = {"subscript_pythonization", subscript, METH_VARARGS, R"( + Raise an `IndexError` exception if an index is invalid. + The `__getitem__` will return immutable datatype objects instead of the mutable ones. + )"}; + auto* func = PyCFunction_New(&ml, klass); + if (!func) { + throw std::runtime_error("Failed to create Python subscript function for class " + name); + } + auto* method = PyInstanceMethod_New(func); + if (!method) { + Py_DECREF(func); + throw std::runtime_error("Failed to create Python instance method for subscript for class " + name); + } + if (0 != PyObject_SetAttrString(klass, "__getitem__", method)) { + Py_DECREF(method); + Py_DECREF(func); + throw std::runtime_error("Failed to set __getitem__ attribute on class " + name); + } + Py_DECREF(func); + Py_DECREF(method); +} + +} // namespace podio::detail::pythonizations \ No newline at end of file