1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/python/lib/core/py_util.h"
17
18 // Place `<locale>` before <Python.h> to avoid build failure in macOS.
19 #include <locale>
20
21 #include "tensorflow/core/lib/core/errors.h"
22 #include "tensorflow/core/lib/strings/strcat.h"
23
24 namespace tensorflow {
25 namespace {
26
27 // py.__class__.__name__
ClassName(PyObject * py)28 const char* ClassName(PyObject* py) {
29 /* PyPy doesn't have a separate C API for old-style classes. */
30 #if PY_MAJOR_VERSION < 3 && !defined(PYPY_VERSION)
31 if (PyClass_Check(py))
32 return PyString_AS_STRING(
33 CHECK_NOTNULL(reinterpret_cast<PyClassObject*>(py)->cl_name));
34 if (PyInstance_Check(py))
35 return PyString_AS_STRING(CHECK_NOTNULL(
36 reinterpret_cast<PyInstanceObject*>(py)->in_class->cl_name));
37 #endif
38 if (Py_TYPE(py) == &PyType_Type) {
39 return reinterpret_cast<PyTypeObject*>(py)->tp_name;
40 }
41 return Py_TYPE(py)->tp_name;
42 }
43
44 } // end namespace
45
46 // Returns a PyObject containing a string, or null
TryAppendTraceback(PyObject * ptype,PyObject * pvalue,PyObject * ptraceback,string * out)47 void TryAppendTraceback(PyObject* ptype, PyObject* pvalue, PyObject* ptraceback,
48 string* out) {
49 // The "traceback" module is assumed to be imported already by script_ops.py.
50 PyObject* tb_module = PyImport_AddModule("traceback");
51
52 if (!tb_module) {
53 return;
54 }
55
56 PyObject* format_exception =
57 PyObject_GetAttrString(tb_module, "format_exception");
58
59 if (!format_exception) {
60 return;
61 }
62
63 if (!PyCallable_Check(format_exception)) {
64 Py_DECREF(format_exception);
65 return;
66 }
67
68 PyObject* ret_val = PyObject_CallFunctionObjArgs(format_exception, ptype,
69 pvalue, ptraceback, nullptr);
70 Py_DECREF(format_exception);
71
72 if (!ret_val) {
73 return;
74 }
75
76 if (!PyList_Check(ret_val)) {
77 Py_DECREF(ret_val);
78 return;
79 }
80
81 Py_ssize_t n = PyList_GET_SIZE(ret_val);
82 for (Py_ssize_t i = 0; i < n; ++i) {
83 PyObject* v = PyList_GET_ITEM(ret_val, i);
84 #if PY_MAJOR_VERSION < 3
85 strings::StrAppend(out, PyString_AS_STRING(v), "\n");
86 #else
87 strings::StrAppend(out, PyUnicode_AsUTF8(v), "\n");
88 #endif
89 }
90
91 // Iterate through ret_val.
92 Py_DECREF(ret_val);
93 }
94
PyExceptionFetch()95 string PyExceptionFetch() {
96 CHECK(PyErr_Occurred())
97 << "Must only call PyExceptionFetch after an exception.";
98 PyObject* ptype;
99 PyObject* pvalue;
100 PyObject* ptraceback;
101 PyErr_Fetch(&ptype, &pvalue, &ptraceback);
102 PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
103 string err = ClassName(ptype);
104 if (pvalue) {
105 PyObject* str = PyObject_Str(pvalue);
106
107 if (str) {
108 #if PY_MAJOR_VERSION < 3
109 strings::StrAppend(&err, ": ", PyString_AS_STRING(str), "\n");
110 #else
111 strings::StrAppend(&err, ": ", PyUnicode_AsUTF8(str), "\n");
112 #endif
113 Py_DECREF(str);
114 } else {
115 strings::StrAppend(&err, "(unknown error message)\n");
116 }
117
118 TryAppendTraceback(ptype, pvalue, ptraceback, &err);
119
120 Py_DECREF(pvalue);
121 }
122 Py_DECREF(ptype);
123 Py_XDECREF(ptraceback);
124 return err;
125 }
126
127 } // end namespace tensorflow
128