forked from jupyter-xeus/xeus-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxtraceback.cpp
181 lines (147 loc) · 5.94 KB
/
xtraceback.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/***************************************************************************
* Copyright (c) 2018, Martin Renou, Johan Mabille, Sylvain Corlay, and *
* Wolf Vollprecht *
* Copyright (c) 2018, QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#include <algorithm>
#include <map>
#include <vector>
#include <string>
#include "xeus-python/xutils.hpp"
#include "xeus-python/xtraceback.hpp"
#include "pybind11/pybind11.h"
#include "xinternal_utils.hpp"
namespace py = pybind11;
namespace xpyt
{
py::str get_filename(const py::str& raw_code)
{
return get_cell_tmp_file(raw_code);
}
using filename_map = std::map<std::string, int>;
filename_map& get_filename_map()
{
static filename_map fnm;
return fnm;
}
void register_filename_mapping(const std::string& filename, int execution_count)
{
get_filename_map()[filename] = execution_count;
}
xerror extract_error(const py::list& error)
{
xerror out;
out.m_ename = error[0].cast<std::string>();
out.m_evalue = error[1].cast<std::string>();
py::list tb = error[2];
std::transform(
tb.begin(), tb.end(), std::back_inserter(out.m_traceback),
[](py::handle obj) -> std::string { return obj.cast<std::string>(); }
);
return out;
}
xerror extract_already_set_error(py::error_already_set& error)
{
xerror out;
// Fetch the error message, it must be released by the C++ exception first
error.restore();
py::object py_type;
py::object py_value;
py::object py_tb;
PyErr_Fetch(&py_type.ptr(), &py_value.ptr(), &py_tb.ptr());
// This should NOT happen
if (py_type.is_none())
{
out.m_ename = "Error";
out.m_evalue = error.what();
out.m_traceback.push_back(error.what());
}
else
{
out.m_ename = py::str(py_type.attr("__name__"));
out.m_evalue = py::str(py_value);
std::size_t first_frame_size(75);
std::string delimiter(first_frame_size, '-');
std::string traceback_msg("Traceback (most recent call last)");
std::string first_frame_padding(first_frame_size - traceback_msg.size() - out.m_ename.size(), ' ');
std::stringstream first_frame;
first_frame << red_text(delimiter) << "\n"
<< red_text(out.m_ename) << first_frame_padding << traceback_msg;
out.m_traceback.push_back(first_frame.str());
if (py_tb.ptr() != nullptr && !py_tb.is_none())
{
for (py::handle py_frame : py::module::import("traceback").attr("extract_tb")(py_tb))
{
std::string filename;
std::string lineno;
std::string name;
std::string line;
filename = py::str(py_frame.attr("filename"));
lineno = py::str(py_frame.attr("lineno"));
name = py::str(py_frame.attr("name"));
line = py::str(py_frame.attr("line"));
// Workaround for py::exec
if (filename == "<string>")
{
continue;
}
std::stringstream cpp_frame;
std::string padding(6 - lineno.size(), ' ');
std::string file_prefix;
std::string func_name;
std::string prefix = get_tmp_prefix();
// If the error occured in a cell code, extract the line from the given code
if(!filename.empty() && !filename.compare(0, prefix.size(), prefix.c_str(), prefix.size()))
{
file_prefix = "In ";
auto it = get_filename_map().find(filename);
if(it != get_filename_map().end())
{
filename = '[' + std::to_string(it->second) + ']';
}
}
else
{
file_prefix = "File ";
func_name = ", in " + green_text(name);
}
cpp_frame << file_prefix << blue_text(filename) << func_name << ":\n"
<< "Line " << blue_text(lineno) << ":"
<< padding << highlight(line);
out.m_traceback.push_back(cpp_frame.str());
}
}
std::stringstream last_frame;
last_frame << red_text(out.m_ename) << ": " << out.m_evalue << "\n"
<< red_text(delimiter);
out.m_traceback.push_back(last_frame.str());
}
return out;
}
/********************
* traceback module *
********************/
py::module get_traceback_module_impl()
{
py::module traceback_module = create_module("traceback");
traceback_module.def("get_filename",
get_filename,
py::arg("raw_code")
);
traceback_module.def("register_filename_mapping",
register_filename_mapping,
py::arg("filename"),
py::arg("execution_count")
);
return traceback_module;
}
py::module get_traceback_module()
{
static py::module traceback_module = get_traceback_module_impl();
return traceback_module;
}
}