From 495b4f58d72c76deecef95141c2e3fb9c0be5198 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 22 Dec 2025 11:39:56 -0600 Subject: [PATCH 1/4] feat: move Pythonizations implementations to source files --- include/podio/detail/Pythonizations.h | 47 ++--------------------- src/CMakeLists.txt | 2 + src/Pythonizations.cc | 54 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 44 deletions(-) create mode 100644 src/Pythonizations.cc 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..0991199e0 --- /dev/null +++ b/src/Pythonizations.cc @@ -0,0 +1,54 @@ +#include "podio/detail/Pythonizations.h" + +#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 = {"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); +} + +} // namespace podio::detail::pythonizations \ No newline at end of file From 21d8d85c056b0d4b1b420833ee5acd7cb3fbd504 Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 22 Dec 2025 12:17:33 -0600 Subject: [PATCH 2/4] fix: typo in string in src/Pythonizations.cc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/Pythonizations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pythonizations.cc b/src/Pythonizations.cc index 0991199e0..dd777f2d2 100644 --- a/src/Pythonizations.cc +++ b/src/Pythonizations.cc @@ -29,7 +29,7 @@ PyObject* subscript(PyObject* self, PyObject* index) { // Helper to register the subscript pythonization callback as `__getitem__` method void pythonize_subscript(PyObject* klass, const std::string& name) { - static PyMethodDef ml = {"subscipt_pythonization", subscript, METH_VARARGS, R"( + 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. )"}; From e0c8c89ee5f32363766e60c17804119d3c75995c Mon Sep 17 00:00:00 2001 From: Wouter Deconinck Date: Mon, 22 Dec 2025 12:17:53 -0600 Subject: [PATCH 3/4] fix: include cstring in src/Pythonizations.cc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/Pythonizations.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Pythonizations.cc b/src/Pythonizations.cc index dd777f2d2..c653404bf 100644 --- a/src/Pythonizations.cc +++ b/src/Pythonizations.cc @@ -1,6 +1,7 @@ #include "podio/detail/Pythonizations.h" #include +#include namespace podio::detail::pythonizations { From 05877e48aca32c6113c7511780346ff9de272813 Mon Sep 17 00:00:00 2001 From: Thomas Madlener Date: Mon, 22 Dec 2025 20:05:23 +0100 Subject: [PATCH 4/4] Remove docstrings from implementation and re-order headers --- src/Pythonizations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pythonizations.cc b/src/Pythonizations.cc index c653404bf..5602dc016 100644 --- a/src/Pythonizations.cc +++ b/src/Pythonizations.cc @@ -1,7 +1,7 @@ #include "podio/detail/Pythonizations.h" -#include #include +#include namespace podio::detail::pythonizations {