aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/udfs/common/python/bindings/py_errors.cpp
diff options
context:
space:
mode:
authorimunkin <imunkin@yandex-team.com>2024-11-08 10:00:23 +0300
committerimunkin <imunkin@yandex-team.com>2024-11-08 10:12:13 +0300
commita784a2f943d6e15caa6241e2e96d80aac6dbf375 (patch)
tree05f1e5366c916b988a8afb75bdab8ddeee0f6e6d /yql/essentials/udfs/common/python/bindings/py_errors.cpp
parentd70137a7b530ccaa52834274913bbb5a3d1ca06e (diff)
downloadydb-a784a2f943d6e15caa6241e2e96d80aac6dbf375.tar.gz
Move yql/udfs/common/ to /yql/essentials YQL-19206
Except the following directories: * clickhouse/client * datetime * knn * roaring commit_hash:c7da95636144d28db109d6b17ddc762e9bacb59f
Diffstat (limited to 'yql/essentials/udfs/common/python/bindings/py_errors.cpp')
-rw-r--r--yql/essentials/udfs/common/python/bindings/py_errors.cpp72
1 files changed, 72 insertions, 0 deletions
diff --git a/yql/essentials/udfs/common/python/bindings/py_errors.cpp b/yql/essentials/udfs/common/python/bindings/py_errors.cpp
new file mode 100644
index 0000000000..5741978d54
--- /dev/null
+++ b/yql/essentials/udfs/common/python/bindings/py_errors.cpp
@@ -0,0 +1,72 @@
+#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