• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // The empty line above is on purpose as otherwise clang-format will
22 // automatically move <Python.h> before <locale>.
23 #include <Python.h>
24 
25 #include "tensorflow/core/lib/core/errors.h"
26 #include "tensorflow/core/lib/strings/strcat.h"
27 
28 namespace tensorflow {
29 namespace {
30 
31 // py.__class__.__name__
ClassName(PyObject * py)32 const char* ClassName(PyObject* py) {
33 /* PyPy doesn't have a separate C API for old-style classes. */
34 #if PY_MAJOR_VERSION < 3 && !defined(PYPY_VERSION)
35   if (PyClass_Check(py))
36     return PyString_AS_STRING(
37         CHECK_NOTNULL(reinterpret_cast<PyClassObject*>(py)->cl_name));
38   if (PyInstance_Check(py))
39     return PyString_AS_STRING(CHECK_NOTNULL(
40         reinterpret_cast<PyInstanceObject*>(py)->in_class->cl_name));
41 #endif
42   if (Py_TYPE(py) == &PyType_Type) {
43     return reinterpret_cast<PyTypeObject*>(py)->tp_name;
44   }
45   return Py_TYPE(py)->tp_name;
46 }
47 
48 }  // end namespace
49 
50 // Returns a PyObject containing a string, or null
TryAppendTraceback(PyObject * ptype,PyObject * pvalue,PyObject * ptraceback,string * out)51 void TryAppendTraceback(PyObject* ptype, PyObject* pvalue, PyObject* ptraceback,
52                         string* out) {
53   // The "traceback" module is assumed to be imported already by script_ops.py.
54   PyObject* tb_module = PyImport_AddModule("traceback");
55 
56   if (!tb_module) {
57     return;
58   }
59 
60   PyObject* format_exception =
61       PyObject_GetAttrString(tb_module, "format_exception");
62 
63   if (!format_exception) {
64     return;
65   }
66 
67   if (!PyCallable_Check(format_exception)) {
68     Py_DECREF(format_exception);
69     return;
70   }
71 
72   PyObject* ret_val = PyObject_CallFunctionObjArgs(format_exception, ptype,
73                                                    pvalue, ptraceback, nullptr);
74   Py_DECREF(format_exception);
75 
76   if (!ret_val) {
77     return;
78   }
79 
80   if (!PyList_Check(ret_val)) {
81     Py_DECREF(ret_val);
82     return;
83   }
84 
85   Py_ssize_t n = PyList_GET_SIZE(ret_val);
86   for (Py_ssize_t i = 0; i < n; ++i) {
87     PyObject* v = PyList_GET_ITEM(ret_val, i);
88 #if PY_MAJOR_VERSION < 3
89     strings::StrAppend(out, PyString_AS_STRING(v), "\n");
90 #else
91     strings::StrAppend(out, PyUnicode_AsUTF8(v), "\n");
92 #endif
93   }
94 
95   // Iterate through ret_val.
96   Py_DECREF(ret_val);
97 }
98 
PyExceptionFetch()99 string PyExceptionFetch() {
100   CHECK(PyErr_Occurred())
101       << "Must only call PyExceptionFetch after an exception.";
102   PyObject* ptype;
103   PyObject* pvalue;
104   PyObject* ptraceback;
105   PyErr_Fetch(&ptype, &pvalue, &ptraceback);
106   PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
107   string err = ClassName(ptype);
108   if (pvalue) {
109     PyObject* str = PyObject_Str(pvalue);
110 
111     if (str) {
112 #if PY_MAJOR_VERSION < 3
113       strings::StrAppend(&err, ": ", PyString_AS_STRING(str), "\n");
114 #else
115       strings::StrAppend(&err, ": ", PyUnicode_AsUTF8(str), "\n");
116 #endif
117       Py_DECREF(str);
118     } else {
119       strings::StrAppend(&err, "(unknown error message)\n");
120     }
121 
122     TryAppendTraceback(ptype, pvalue, ptraceback, &err);
123 
124     Py_DECREF(pvalue);
125   }
126   Py_DECREF(ptype);
127   Py_XDECREF(ptraceback);
128   return err;
129 }
130 
131 }  // end namespace tensorflow
132