aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/pybind/exceptions.cpp
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@ydb.tech>2023-11-30 13:26:22 +0300
committervitalyisaev <vitalyisaev@ydb.tech>2023-11-30 15:44:45 +0300
commit0a98fece5a9b54f16afeb3a94b3eb3105e9c3962 (patch)
tree291d72dbd7e9865399f668c84d11ed86fb190bbf /library/cpp/pybind/exceptions.cpp
parentcb2c8d75065e5b3c47094067cb4aa407d4813298 (diff)
downloadydb-0a98fece5a9b54f16afeb3a94b3eb3105e9c3962.tar.gz
YQ Connector:Use docker-compose in integrational tests
Diffstat (limited to 'library/cpp/pybind/exceptions.cpp')
-rw-r--r--library/cpp/pybind/exceptions.cpp147
1 files changed, 147 insertions, 0 deletions
diff --git a/library/cpp/pybind/exceptions.cpp b/library/cpp/pybind/exceptions.cpp
new file mode 100644
index 0000000000..db1531fc63
--- /dev/null
+++ b/library/cpp/pybind/exceptions.cpp
@@ -0,0 +1,147 @@
+#include "exceptions.h"
+#include "cast.h"
+#include "module.h"
+#include <util/generic/algorithm.h>
+
+namespace NPyBind {
+
+ namespace NPrivate {
+ TPyObjectPtr CreatePyBindModule() {
+ return TPyObjectPtr(TExceptionsHolder::DoInitPyBindModule(), true);
+ }
+ }//NPrivate
+
+ TPyObjectPtr TExceptionsHolder::GetException(const TString& name) {
+ if (name == "")
+ return TPyObjectPtr(nullptr);
+ if (!Exceptions[name].Get())
+ ythrow yexception() << "Wrong base class '" << name << "'";
+ return Exceptions[name];
+ }
+
+ TPyObjectPtr TExceptionsHolder::GetExceptions(const TVector<TString>& names) {
+ TVector<TString> tmp(names.begin(), names.end());
+ TVector<TString>::iterator end = std::unique(tmp.begin(), tmp.end());
+ TPyObjectPtr tuple(PyTuple_New(std::distance(tmp.begin(), end)), true);
+ for (size_t i = 0; i < (size_t)std::distance(tmp.begin(), end); ++i) {
+ if (!Exceptions[tmp[i]].Get())
+ ythrow yexception() << "Wrong base class '" << tmp[i] << "'";
+ PyTuple_SetItem(tuple.Get(), i, Exceptions[tmp[i]].Get());
+ }
+ return tuple;
+ }
+
+ // def PyBindObjectReconstructor(cl, props):
+ // return cl(__properties__=props)
+ static PyObject* PyBindObjectReconstructor(PyObject*, PyObject* args) {
+ TPyObjectPtr callable, props;
+ if (!ExtractArgs(args, callable, props))
+ ythrow yexception() << "Wrong method arguments";
+#if PY_MAJOR_VERSION >= 3
+ TPyObjectPtr noArgs(PyTuple_New(0), true);
+#else
+ TPyObjectPtr noArgs(PyList_New(0), true);
+#endif
+ TPyObjectPtr kw(PyDict_New(), true);
+ PyDict_SetItemString(kw.Get(), "__properties__", props.Get());
+ TPyObjectPtr res(PyObject_Call(callable.Get(), noArgs.Get(), kw.Get()), true);
+ return res.RefGet();
+ }
+
+ static PyMethodDef PyBindMethods[] = {
+ {"PyBindObjectReconstructor", PyBindObjectReconstructor, METH_VARARGS, "Tech method. It's required for unpickling."},
+ {nullptr, nullptr, 0, nullptr}};
+
+#if PY_MAJOR_VERSION >= 3
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "pybind",
+ NULL,
+ -1,
+ PyBindMethods,
+ NULL, NULL, NULL, NULL
+ };
+
+ static PyObject* InitPyBind() {
+ return PyModule_Create(&moduledef);
+ }
+#else
+ static PyObject* InitPyBind() {
+ return Py_InitModule("pybind", PyBindMethods);
+ }
+#endif
+
+ void TExceptionsHolder::DoInitPyBindModule2() {
+ DoInitPyBindModule();
+ }
+
+ PyObject* TExceptionsHolder::DoInitPyBindModule() {
+ Instance().Module = NPyBind::TPyObjectPtr(InitPyBind(), true);
+ if (!Instance().Module.Get())
+ return nullptr;
+
+ for (TCheckersVector::const_iterator it = Instance().Checkers.begin(), end = Instance().Checkers.end(); it != end; ++it) {
+ TString name = (*it)->GetName();
+ if (!!name) {
+ //Ref to the object should be incremented before passing to AddObject
+ auto res = PyModule_AddObject(Instance().Module.Get(), name.data(), (*it)->GetException().RefGet());
+ if (res < 0) {
+ ythrow yexception() << "Failed to add object " << name << " to internal module pybind";
+ }
+ }
+ }
+ return Instance().Module.RefGet();
+ }
+
+ void TExceptionsHolder::Clear() {
+ //Unfortunately in Python3 we can't retrack this object because of PyError_NewException
+ //it's only the safe way to preserve GC gens in valid state during the finalization
+ for (auto& ptr: Checkers) {
+ if (!dynamic_cast<const TPyErrExceptionsChecker*>(ptr.Get())) { // no need to untrack standard PyExc_* exceptions from TPyErrExceptionsChecker
+ if (auto exceptionPtr = ptr->GetException()) {
+ PyObject_GC_UnTrack(exceptionPtr.Get());
+ }
+ }
+ }
+ Checkers.clear();
+ Exceptions.clear();
+ Module.Drop();
+ }
+
+ TExceptionsHolder::TExceptionsHolder() {
+ AddException<std::exception>("yexception");
+ AddException<TSystemError>("TSystemError", "yexception");
+ AddException<TIoException>("TIoException", "yexception");
+
+ TVector<TString> names(2);
+ names[0] = "TSystemError";
+ names[1] = "TIoException";
+
+ AddException<TIoSystemError>("TIoSystemError", names);
+ AddException<TFileError>("TFileError", "TIoSystemError");
+ AddException<TBadCastException>("TBadCastException", "yexception");
+
+ Checkers.push_back(new TPyErrExceptionsChecker);
+
+ // XXX: In Python 2.6, PyImport_AppendInittab() function takes non-const char*, this causes
+ // "ISO C++11 does not allow conversion from string literal to 'char *'" warning.
+ static char pybind[] = "pybind";
+#if PY_MAJOR_VERSION >= 3
+ PyImport_AppendInittab(pybind, DoInitPyBindModule);
+
+ NPrivate::AddFinalizationCallBack([this]() {
+ Clear();
+ });
+#else
+ PyImport_AppendInittab(pybind, DoInitPyBindModule2);
+#endif
+ }
+
+ NPyBind::TPyObjectPtr TExceptionsHolder::ToPyException(const std::exception& ex) {
+ for (TCheckersVector::const_reverse_iterator it = Checkers.rbegin(), end = Checkers.rend(); it != end; ++it) {
+ if ((*it)->Check(ex))
+ return (*it)->GetException();
+ }
+ return TPyObjectPtr(nullptr);
+ }
+}