From e0094c4ad6964e11564777bc0d859c68d8aa9de2 Mon Sep 17 00:00:00 2001
From: say <say@yandex-team.com>
Date: Tue, 14 Feb 2023 17:24:43 +0300
Subject: Migrate black linter on custom_lint pipeline

---
 library/cpp/pybind/exceptions.cpp | 147 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)
 create mode 100644 library/cpp/pybind/exceptions.cpp

(limited to 'library/cpp/pybind/exceptions.cpp')

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);
+    }
+}
-- 
cgit v1.2.3