2018-06-23 20:32:18 +08:00
|
|
|
#ifndef NO_PYTHON
|
|
|
|
|
2018-06-06 03:03:06 +08:00
|
|
|
#include <Python.h>
|
2020-07-24 00:35:18 +08:00
|
|
|
#include <pybind11/pybind11.h>
|
2018-06-12 20:24:59 +08:00
|
|
|
#include "nextpnr.h"
|
2018-06-06 03:03:06 +08:00
|
|
|
|
2020-07-24 00:35:18 +08:00
|
|
|
namespace py = pybind11;
|
2018-06-06 03:03:06 +08:00
|
|
|
|
2018-06-12 20:24:59 +08:00
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
|
2018-06-06 03:03:06 +08:00
|
|
|
// Parses the value of the active python exception
|
|
|
|
// NOTE SHOULD NOT BE CALLED IF NO EXCEPTION
|
2018-06-08 17:04:02 +08:00
|
|
|
std::string parse_python_exception()
|
|
|
|
{
|
2018-06-06 03:03:06 +08:00
|
|
|
PyObject *type_ptr = NULL, *value_ptr = NULL, *traceback_ptr = NULL;
|
|
|
|
// Fetch the exception info from the Python C API
|
|
|
|
PyErr_Fetch(&type_ptr, &value_ptr, &traceback_ptr);
|
|
|
|
|
|
|
|
// Fallback error
|
|
|
|
std::string ret("Unfetchable Python error");
|
|
|
|
// If the fetch got a type pointer, parse the type into the exception string
|
2018-06-08 17:04:02 +08:00
|
|
|
if (type_ptr != NULL) {
|
2020-07-24 00:35:18 +08:00
|
|
|
py::object obj = py::reinterpret_borrow<py::object>(type_ptr);
|
2018-06-08 17:04:02 +08:00
|
|
|
// If a valid string extraction is available, use it
|
2018-06-06 03:03:06 +08:00
|
|
|
// otherwise use fallback
|
2020-07-24 00:35:18 +08:00
|
|
|
if (py::isinstance<py::str>(obj))
|
|
|
|
ret = obj.cast<std::string>();
|
2018-06-06 03:03:06 +08:00
|
|
|
else
|
|
|
|
ret = "Unknown exception type";
|
|
|
|
}
|
2018-06-08 17:04:02 +08:00
|
|
|
// Do the same for the exception value (the stringification of the
|
|
|
|
// exception)
|
|
|
|
if (value_ptr != NULL) {
|
2020-07-24 00:35:18 +08:00
|
|
|
py::object obj = py::reinterpret_borrow<py::object>(value_ptr);
|
|
|
|
if (py::isinstance<py::str>(obj))
|
|
|
|
ret += ": " + obj.cast<std::string>();
|
2018-06-06 03:03:06 +08:00
|
|
|
else
|
|
|
|
ret += std::string(": Unparseable Python error: ");
|
|
|
|
}
|
|
|
|
// Parse lines from the traceback using the Python traceback module
|
2018-06-08 17:04:02 +08:00
|
|
|
if (traceback_ptr != NULL) {
|
2020-07-24 00:35:18 +08:00
|
|
|
py::handle h_tb(traceback_ptr);
|
2018-06-06 03:03:06 +08:00
|
|
|
// Load the traceback module and the format_tb function
|
2020-07-24 00:35:18 +08:00
|
|
|
py::object tb(py::module::import("traceback"));
|
2018-06-06 03:03:06 +08:00
|
|
|
py::object fmt_tb(tb.attr("format_tb"));
|
|
|
|
// Call format_tb to get a list of traceback strings
|
|
|
|
py::object tb_list(fmt_tb(h_tb));
|
|
|
|
// Join the traceback strings into a single string
|
2020-07-24 00:35:18 +08:00
|
|
|
py::object tb_str(py::str("\n") + tb_list);
|
2018-06-06 03:03:06 +08:00
|
|
|
// Extract the string, check the extraction, and fallback in necessary
|
2020-07-24 00:35:18 +08:00
|
|
|
if (py::isinstance<py::str>(tb_str))
|
|
|
|
ret += ": " + tb_str.cast<std::string>();
|
2018-06-06 03:03:06 +08:00
|
|
|
else
|
|
|
|
ret += std::string(": Unparseable Python traceback");
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2018-06-12 20:24:59 +08:00
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_END
|
2018-06-23 20:32:18 +08:00
|
|
|
|
|
|
|
#endif // NO_PYTHON
|