Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-06 09:55:32

0001 #ifndef PODIO_DETAIL_PYTHONIZATIONS_H
0002 #define PODIO_DETAIL_PYTHONIZATIONS_H
0003 
0004 #define PY_SSIZE_T_CLEAN
0005 #include <Python.h>
0006 #include <stdexcept>
0007 #include <string>
0008 
0009 namespace podio::detail::pythonizations {
0010 
0011 // Callback function for the subscript pythonization
0012 // Calls the `at` method and change exception type to IndexError if the index is out of range
0013 static inline PyObject* subscript(PyObject* self, PyObject* index) {
0014   PyObject* result = PyObject_CallMethod(self, "at", "O", index);
0015   if (!result) {
0016     PyObject* exc = PyErr_Occurred();
0017     // Check if the exception is `cppyy.gbl.std.out_of_range`
0018     // Since PyImport_ImportModule("cppyy") fails, this workaround checks the exception name
0019     if (exc && PyObject_HasAttrString(exc, "__name__")) {
0020       PyObject* exc_name = PyObject_GetAttrString(exc, "__name__");
0021       if (exc_name) {
0022         const char* name_cstr = PyUnicode_AsUTF8(exc_name);
0023         if (name_cstr && strcmp(name_cstr, "out_of_range") == 0) {
0024           PyErr_Clear();
0025           PyErr_SetString(PyExc_IndexError, "Index out of range");
0026         }
0027         Py_DECREF(exc_name);
0028       }
0029     }
0030   }
0031   return result;
0032 }
0033 
0034 // Helper to register the subscript pythonization callback as `__getitem__` method
0035 static inline void pythonize_subscript(PyObject* klass, const std::string& name) {
0036   static PyMethodDef ml = {"subscipt_pythonization", subscript, METH_VARARGS, R"(
0037         Raise an `IndexError` exception if an index is invalid.
0038         The `__getitem__` will return immutable datatype objects instead of the mutable ones.
0039   )"};
0040   auto* func = PyCFunction_New(&ml, klass);
0041   if (!func) {
0042     throw std::runtime_error("Failed to create Python subscript function for class " + name);
0043   }
0044   auto* method = PyInstanceMethod_New(func);
0045   if (!method) {
0046     Py_DECREF(func);
0047     throw std::runtime_error("Failed to create Python instance method for subscript for class " + name);
0048   }
0049   if (0 != PyObject_SetAttrString(klass, "__getitem__", method)) {
0050     Py_DECREF(method);
0051     Py_DECREF(func);
0052     throw std::runtime_error("Failed to set __getitem__ attribute on class " + name);
0053   }
0054   Py_DECREF(func);
0055   Py_DECREF(method);
0056 }
0057 
0058 } // namespace podio::detail::pythonizations
0059 
0060 #endif // PODIO_DETAIL_PYTHONIZATIONS_H