Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
PyException.cxx
Go to the documentation of this file.
1// Standard
2#include <string.h>
3
4// Bindings
5#include "CPyCppyy.h"
6#define CPYCPPYY_INTERNAL 1
8#undef CPYCPPYY_INTERNAL
9
10
11//______________________________________________________________________________
12// C++ exception for throwing python exceptions
13// ============================================
14// Purpose: A C++ exception class for throwing python exceptions
15// through C++ code.
16// Created: Apr, 2004, Scott Snyder, from the version in D0's python_util.
17//
18// Note: Don't be tempted to declare the virtual functions defined here
19// as inline.
20// If you do, you may not be able to properly throw these
21// exceptions across shared libraries.
22
23
24//- constructors/destructor --------------------------------------------------
26{
27#ifdef WITH_THREAD
28 PyGILState_STATE state = PyGILState_Ensure();
29#endif
30
31#if PY_VERSION_HEX >= 0x030c0000
32 PyObject *pyvalue = PyErr_GetRaisedException();
33 PyObject *pytype = pyvalue ? (PyObject *)Py_TYPE(pyvalue) : nullptr;
34 PyObject* traceback = pyvalue ? PyException_GetTraceback(pyvalue) : nullptr;
35#else
36 PyObject* pytype = nullptr, *pyvalue = nullptr, *pytrace = nullptr;
37 PyErr_Fetch(&pytype, &pyvalue, &pytrace);
38 PyObject* traceback = pytrace; // to keep the original unchanged
39 Py_XINCREF(traceback);
40#endif
41
42 if (pytype && pyvalue) {
43 const char* tname = PyExceptionClass_Name(pytype);
44 if (tname) {
45 char* dot = strrchr((char*)tname, '.');
46 if (dot) tname = dot+1;
47 fMsg += tname;
48 fMsg += ": ";
49 }
50
51 PyObject* msg = PyObject_Str(pyvalue);
52 if (msg) {
54 Py_DECREF(msg);
55 }
56 }
57
58 std::string locName;
59 std::string locFile;
60 int locLine = 0;
61
62 while (traceback && traceback != Py_None) {
63 PyObject* frame = PyObject_GetAttrString(traceback, "tb_frame");
64 PyObject* code = PyObject_GetAttrString(frame, "f_code");
65 Py_DECREF(frame);
66
67 PyObject* filename = PyObject_GetAttrString(code, "co_filename");
68 Py_DECREF(code);
69
70 PyObject* filenameStr = PyObject_Str(filename);
71 locFile = CPyCppyy_PyText_AsString(filenameStr);
72 Py_DECREF(filenameStr);
73 Py_DECREF(filename);
74
75 PyObject* name = PyObject_GetAttrString(code, "co_name");
76 PyObject* nameStr = PyObject_Str(name);
77 locName = CPyCppyy_PyText_AsString(nameStr);
78 Py_DECREF(nameStr);
79 Py_DECREF(name);
80
81 PyObject* lineno = PyObject_GetAttrString(traceback, "tb_lineno");
82 locLine = PyLong_AsLong(lineno);
83 Py_DECREF(lineno);
84
85 if (locFile == "<string>") { // these are not that useful, skipping
86 PyObject* nextTraceback = PyObject_GetAttrString(traceback, "tb_next");
87 Py_DECREF(traceback);
88 traceback = nextTraceback;
89 continue;
90 }
91
92 break;
93 }
94
95 Py_XDECREF(traceback);
96
97#if PY_VERSION_HEX >= 0x030c0000
98 PyErr_SetRaisedException(pyvalue);
99#else
100 PyErr_Restore(pytype, pyvalue, pytrace);
101#endif
102
103 if (fMsg.empty())
104 fMsg = "python exception";
105
106 if (!locFile.empty()) {
107
108 // only keeping the filename, not the full path
109 locFile = locFile.substr(locFile.find_last_of("/\\") + 1);
110
111 fMsg += " (at " + locFile + ":" + std::to_string(locLine);
112
113 if (locName != "<module>")
114 fMsg += " in " + locName;
115
116 fMsg += ")";
117 }
118
119#ifdef WITH_THREAD
120 PyGILState_Release(state);
121#endif
122}
123
125{
126// destructor
127}
128
129
130//- public members -----------------------------------------------------------
131const char* CPyCppyy::PyException::what() const noexcept
132{
133// Return reason for throwing this exception: a python exception was raised.
134 return fMsg.c_str();
135}
136
137void CPyCppyy::PyException::clear() const noexcept
138{
139// clear Python error, to allow full error handling C++ side
140 PyErr_Clear();
141}
#define Py_TYPE(ob)
Definition CPyCppyy.h:196
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
_object PyObject
char name[80]
Definition TGX11.cxx:148
const char * what() const noexcept override
~PyException() noexcept override
void clear() const noexcept