123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- #include "py_errors.h"
- #include "py_ptr.h"
- #include "py_cast.h"
- #include "py_utils.h"
- #include <util/generic/string.h>
- #include <util/stream/output.h>
- namespace NPython {
- // this function in conjuction with code after Py_Initialize
- // does approximately following:
- //
- // sys.stderr = StderrProxy(sys.stderr)
- //
- // ...
- //
- // sys.stderr._toggle_real_mode()
- // sys.excepthook(
- // sys.last_type,
- // sys.last_value,
- // sys.last_traceback)
- // sys.stderr._get_value()
- // sys.stderr._toggle_real_mode()
- //
- // where _toggle_real_mode, _get_value & all calls to stderr not in real mode
- // are handled in a thread-safe way
- //
- TString GetLastErrorAsString()
- {
- PyObject* etype;
- PyObject* evalue;
- PyObject* etraceback;
- PyErr_Fetch(&etype, &evalue, &etraceback);
- if (!etype) {
- return {};
- }
- TPyObjectPtr etypePtr {etype, TPyObjectPtr::ADD_REF};
- TPyObjectPtr evaluePtr {evalue, TPyObjectPtr::ADD_REF};
- TPyObjectPtr etracebackPtr {etraceback, TPyObjectPtr::ADD_REF};
- TPyObjectPtr stderrObject {PySys_GetObject("stderr"), TPyObjectPtr::ADD_REF};
- if (!stderrObject) {
- return {};
- }
- TPyObjectPtr unused = PyObject_CallMethod(stderrObject.Get(), "_toggle_real_mode", nullptr);
- PyErr_Restore(etypePtr.Get(), evaluePtr.Get(), etracebackPtr.Get());
- // in unusual situations there may be low-level write to stderr
- // (by direct C FILE* write), but that's OK
- PyErr_Print();
- TPyObjectPtr error = PyObject_CallMethod(stderrObject.Get(), "_get_value", nullptr);
- if (!error) {
- return {};
- }
- unused.ResetSteal(
- PyObject_CallMethod(stderrObject.Get(), "_toggle_real_mode", nullptr)
- );
- TString errorValue;
- if (!TryPyCast(error.Get(), errorValue)) {
- errorValue = TString("can't get error string from: ") += PyObjectRepr(error.Get());
- }
- return errorValue;
- }
- } // namspace NPython
|