• 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 #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