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);
90 TPyObjPtr value(PyObject_CallObject(PyExc_OSError, args.get()));
95 PyObject* v = value.get();
96 PyErr_SetObject((PyObject*) Py_TYPE(v), v);
99void setOSErrorFromCode(
const std::error_code& code,
const TChar* path1 =
nullptr,
const TChar* path2 =
nullptr)
101 if (code.category() == std::generic_category())
103 setOSErrorFromErrno(code.value(), code.message(), path1,
nullptr, path2);
105 else if (code.category() == std::system_category())
107#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
108 const int winerror = code.value();
109 setOSErrorFromErrno(0, code.message(), path1, &winerror, path2);
111 setOSErrorFromErrno(code.value(), code.message(), path1,
nullptr, path2);
116 LASS_ASSERT(!path1 && !path2);
117 PyErr_SetString(PyExc_Exception, code.message().c_str());
134 if (!PyErr_Occurred() || !PyErr_ExceptionMatches(PyExc_TypeError))
138 PyObject *type, *value, *traceback;
139 PyErr_Fetch(&type, &value, &traceback);
142 if (PyUnicode_Check(value))
144 std::string left = std::string(header) +
": ";
145 TPyObjPtr pyLeft(PyUnicode_DecodeUTF8(left.data(),
static_cast<Py_ssize_t
>(left.length()), 0));
146 PyObject* newValue = PyUnicode_Concat(pyLeft.get(), value);
147 std::swap(value, newValue);
151 catch (
const std::exception&)
154 PyErr_Restore(type, value, traceback);
162 if (!PyErr_Occurred())
164 LASS_THROW(
"internal error: fetchAndThrowPythonException called while Python exception is not set");
167 PyObject *tempType, *tempValue, *tempTraceback;
168 PyErr_Fetch(&tempType, &tempValue, &tempTraceback);
172 const TPyObjPtr traceback(tempTraceback);
184 std::rethrow_exception(ptr);
195 ::std::ostringstream buffer;
196 buffer << error.message() <<
"\n\n(" << error.location() <<
")";
197 PyErr_SetString(PyExc_Exception, buffer.str().c_str());
199 catch (
const std::invalid_argument& error)
201 PyErr_SetString(PyExc_ValueError, error.what());
203 catch (
const std::domain_error& error)
205 PyErr_SetString(PyExc_ValueError, error.what());
207 catch (
const std::length_error& error)
209 PyErr_SetString(PyExc_ValueError, error.what());
211 catch (
const std::out_of_range& error)
213 PyErr_SetString(PyExc_IndexError, error.what());
215 catch (
const std::range_error& error)
217 PyErr_SetString(PyExc_ValueError, error.what());
219 catch (
const std::overflow_error& error)
221 PyErr_SetString(PyExc_OverflowError, error.what());
223 catch (
const std::underflow_error& error)
225 PyErr_SetString(PyExc_ValueError, error.what());
227 catch (
const std::bad_cast& error)
229 PyErr_SetString(PyExc_TypeError, error.what());
231 catch (
const std::bad_alloc& error)
233 PyErr_SetString(PyExc_MemoryError, error.what());
235 catch (
const std::filesystem::filesystem_error& error)
237 const TChar* path1 = error.path1().empty() ? nullptr : error.path1().c_str();
238 const TChar* path2 = error.path2().empty() ? nullptr : error.path2().c_str();
239 setOSErrorFromCode(error.code(), path1, path2);
241 catch (
const std::system_error& error)
243 setOSErrorFromCode(error.code());
245 catch (
const std::exception& error)
247 PyErr_SetString(PyExc_Exception, error.what());
253PythonException::PythonException(
255 util::ExceptionMixin<
PythonException>(extractMessage(type.get(), value.get()), std::move(loc)),
258 traceback_(traceback)
262PythonException::PythonException(PyObject* type,
const std::string& msg, std::string loc):
265 value_(pyBuildSimpleObject(msg)),
270PythonException::PythonException(PyObject* type,
const std::string& msg):
271 util::ExceptionMixin<
PythonException>(extractMessage(type) +
": " + msg),
273 value_(pyBuildSimpleObject(msg)),
278const std::string PythonException::extractMessage(PyObject* type, PyObject* value)
282 const TPyObjPtr typeStr(PyObject_Str(type));
283 if (!typeStr || pyGetSimpleObject(typeStr.get(), message) != 0)
285 message =
"unknown python exception";
288 if (value && value != Py_None)
291 const TPyObjPtr valueStr(PyObject_Str(value));
292 if (!valueStr || pyGetSimpleObject(valueStr.get(), valmsg) != 0)
297 message +=
": " + valmsg;
307 va_start(vargs, format);
318 if (!PyErr_Occurred())
320 return PyErr_FormatV(exception, format, vargs);
324 PyObject *exc, *fromValue, *newValue, *traceback;
325 PyErr_Fetch(&exc, &fromValue, &traceback);
327 PyErr_NormalizeException(&exc, &fromValue, &traceback);
330 PyException_SetTraceback(fromValue, traceback);
331 Py_DECREF(traceback);
334 assert(!PyErr_Occurred());
337 PyErr_FormatV(exception, format, vargs);
339 PyErr_Fetch(&exc, &newValue, &traceback);
340 PyErr_NormalizeException(&exc, &newValue, &traceback);
342 Py_INCREF(fromValue);
343 PyException_SetCause(newValue, fromValue);
344 PyException_SetContext(newValue, fromValue);
346 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.