47#include <system_error>
54namespace fs = std::filesystem;
56using TChar = fs::path::value_type;
58void setOSErrorFromErrno(
int errno_,
const std::string& message,
const TChar* path1 =
nullptr,
const int* winerr =
nullptr,
const TChar* path2 =
nullptr)
65 args = makeTuple(errno_, message, path1, *winerr, path2);
69 args = makeTuple(errno_, message, path1,
nullptr, path2);
74 args = makeTuple(errno_, message, path1, *winerr);
78 args = makeTuple(errno_, message, path1);
82 args = makeTuple(errno_, message);
86 TPyObjPtr value(PyObject_CallObject(PyExc_OSError, args.get()));
87 PyObject* v = value.get();
88 PyErr_SetObject((PyObject*) Py_TYPE(v), v);
91void setOSErrorFromCode(
const std::error_code& code,
const TChar* path1 =
nullptr,
const TChar* path2 =
nullptr)
93 if (code.category() == std::generic_category())
95 setOSErrorFromErrno(code.value(), code.message(), path1,
nullptr, path2);
97 else if (code.category() == std::system_category())
99#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
100 const int winerror = code.value();
101 setOSErrorFromErrno(0, code.message(), path1, &winerror, path2);
103 setOSErrorFromErrno(code.value(), code.message(), path1,
nullptr, path2);
108 LASS_ASSERT(!path1 && !path2);
109 PyErr_SetString(PyExc_Exception, code.message().c_str());
126 if (!PyErr_Occurred() || !PyErr_ExceptionMatches(PyExc_TypeError))
130 PyObject *type, *value, *traceback;
131 PyErr_Fetch(&type, &value, &traceback);
134 if (PyUnicode_Check(value))
136 std::string left = std::string(header) +
": ";
137 TPyObjPtr pyLeft(PyUnicode_DecodeUTF8(left.data(),
static_cast<Py_ssize_t
>(left.length()), 0));
138 PyObject* newValue = PyUnicode_Concat(pyLeft.get(), value);
139 std::swap(value, newValue);
143 catch (
const std::exception&)
146 PyErr_Restore(type, value, traceback);
154 if (!PyErr_Occurred())
156 LASS_THROW(
"internal error: fetchAndThrowPythonException called while Python exception is not set");
159 PyObject *tempType, *tempValue, *tempTraceback;
160 PyErr_Fetch(&tempType, &tempValue, &tempTraceback);
164 const TPyObjPtr traceback(tempTraceback);
176 std::rethrow_exception(ptr);
187 ::std::ostringstream buffer;
188 buffer << error.message() <<
"\n\n(" << error.location() <<
")";
189 PyErr_SetString(PyExc_Exception, buffer.str().c_str());
191 catch (
const std::invalid_argument& error)
193 PyErr_SetString(PyExc_ValueError, error.what());
195 catch (
const std::domain_error& error)
197 PyErr_SetString(PyExc_ValueError, error.what());
199 catch (
const std::length_error& error)
201 PyErr_SetString(PyExc_ValueError, error.what());
203 catch (
const std::out_of_range& error)
205 PyErr_SetString(PyExc_IndexError, error.what());
207 catch (
const std::range_error& error)
209 PyErr_SetString(PyExc_ValueError, error.what());
211 catch (
const std::overflow_error& error)
213 PyErr_SetString(PyExc_OverflowError, error.what());
215 catch (
const std::underflow_error& error)
217 PyErr_SetString(PyExc_ValueError, error.what());
219 catch (
const std::bad_cast& error)
221 PyErr_SetString(PyExc_TypeError, error.what());
223 catch (
const std::bad_alloc& error)
225 PyErr_SetString(PyExc_MemoryError, error.what());
227 catch (
const std::filesystem::filesystem_error& error)
229 const TChar* path1 = error.path1().empty() ? nullptr : error.path1().c_str();
230 const TChar* path2 = error.path2().empty() ? nullptr : error.path2().c_str();
231 setOSErrorFromCode(error.code(), path1, path2);
233 catch (
const std::system_error& error)
235 setOSErrorFromCode(error.code());
237 catch (
const std::exception& error)
239 PyErr_SetString(PyExc_Exception, error.what());
245PythonException::PythonException(
247 util::ExceptionMixin<
PythonException>(extractMessage(type.get(), value.get()), std::move(loc)),
250 traceback_(traceback)
254PythonException::PythonException(PyObject* type,
const std::string& msg, std::string loc):
257 value_(pyBuildSimpleObject(msg)),
262PythonException::PythonException(PyObject* type,
const std::string& msg):
263 util::ExceptionMixin<
PythonException>(extractMessage(type) +
": " + msg),
265 value_(pyBuildSimpleObject(msg)),
270const std::string PythonException::extractMessage(PyObject* type, PyObject* value)
272 LockGIL LASS_UNUSED(lock);
274 const TPyObjPtr typeStr(PyObject_Str(type));
275 if (!typeStr || pyGetSimpleObject(typeStr.get(), message) != 0)
277 message =
"unknown python exception";
280 if (value && value != Py_None)
283 const TPyObjPtr valueStr(PyObject_Str(value));
284 if (!valueStr || pyGetSimpleObject(valueStr.get(), valmsg) != 0)
289 message +=
": " + valmsg;
299 va_start(vargs, format);
310 if (!PyErr_Occurred())
312 return PyErr_FormatV(exception, format, vargs);
316 PyObject *exc, *fromValue, *newValue, *traceback;
317 PyErr_Fetch(&exc, &fromValue, &traceback);
319 PyErr_NormalizeException(&exc, &fromValue, &traceback);
322 PyException_SetTraceback(fromValue, traceback);
323 Py_DECREF(traceback);
326 assert(!PyErr_Occurred());
329 PyErr_FormatV(exception, format, vargs);
331 PyErr_Fetch(&exc, &newValue, &traceback);
332 PyErr_NormalizeException(&exc, &newValue, &traceback);
334 Py_INCREF(fromValue);
335 PyException_SetCause(newValue, fromValue);
336 PyException_SetContext(newValue, fromValue);
338 PyErr_Restore(exc, newValue, traceback);
acquire the GIL for the current scope.
C++ exception type that holds a Python exception.
type of all exceptions in lass
void addMessageHeader(const char *header)
Prepend a message to the current Python exception value.
void handleException(std::exception_ptr ptr)
Handle a C++ exception by raising an Python exception.
void fetchAndThrowPythonException(std::string loc)
Fetch the current Python exception and throw it as a C++ PythonException.
PyObject * chainErrFormat(PyObject *exception, const char *format,...)
Raise an explicitly chained Python exception.
PyObject * chainErrFormatV(PyObject *exception, const char *format, va_list vargs)
Raise an explicitly chained Python exception.
PyObjectPtr< PyObject >::Type TPyObjPtr
PyObjectPtr to a PyObject.
PyObject * fromSharedPtrToNakedCast(const util::SharedPtr< T, PyObjectStorage, PyObjectCounter > &object)
fromSharedPtrToNakedCast.
lass::util::SharedPtr< T, PyObjectStorage, PyObjectCounter > fromNakedToSharedPtrCast(PyObject *object)
fromNakedToSharedPtrCast.
Comprehensive C++ to Python binding library.
general utility, debug facilities, ...
Library for Assembled Shared Sources.