#pragma once #define PY_SSIZE_T_CLEAN #include #include #include #include #include "ptr.h" namespace NPyBind { // Usage: // ythrow TPyErr(PyExc_TypeError) << "some python type error somewhere in your C++ code"; // class TPyErr: public virtual yexception { public: TPyErr(PyObject* theException = PyExc_RuntimeError) : Exception(theException) { } TPyObjectPtr GetException() const { return Exception; } private: NPyBind::TPyObjectPtr Exception; }; // Throw it when you set py error but function return type is not PyObject*. // Look into examples for more details. struct TPyNativeErrorException final: public yexception {}; //Private api for creating PyBind python module //Needs only for overriding pybind python module in library which imports other pybind library namespace NPrivate { TPyObjectPtr CreatePyBindModule(); }//NPrivate class TExceptionsHolder { friend TPyObjectPtr NPrivate::CreatePyBindModule(); private: TExceptionsHolder(const TExceptionsHolder&); TExceptionsHolder& operator=(const TExceptionsHolder&); TExceptionsHolder(); void Clear(); TPyObjectPtr GetException(const TString&); TPyObjectPtr GetExceptions(const TVector&); private: class TExceptionsChecker { public: virtual ~TExceptionsChecker() { } virtual bool Check(const std::exception& ex) const = 0; virtual TString GetName() const = 0; virtual TPyObjectPtr GetException() const = 0; }; template class TConcreteExceptionsChecker: public TExceptionsChecker { private: TString Name; TPyObjectPtr Exception; public: TConcreteExceptionsChecker(const TString& name, TPyObjectPtr exception) : Name(name) , Exception(exception) { } bool Check(const std::exception& ex) const override { const std::exception* e = &ex; return dynamic_cast(e); } TString GetName() const override { return Name; } TPyObjectPtr GetException() const override { return Exception; } }; class TPyErrExceptionsChecker: public TExceptionsChecker { private: mutable TPyObjectPtr Exception; public: TPyErrExceptionsChecker() { } bool Check(const std::exception& ex) const override { const TPyErr* err = dynamic_cast(&ex); if (err) { Exception = err->GetException(); } return err != nullptr; } TString GetName() const override { return TString(); } TPyObjectPtr GetException() const override { return Exception; } }; typedef TSimpleSharedPtr TCheckerPtr; typedef TVector TCheckersVector; typedef TMap TExceptionsMap; TPyObjectPtr Module; TCheckersVector Checkers; TExceptionsMap Exceptions; static PyObject* DoInitPyBindModule(); static void DoInitPyBindModule2(); public: static TExceptionsHolder& Instance() { static TExceptionsHolder Holder; return Holder; } template void AddException(const TString& name, const TString& base = "") { TPyObjectPtr baseException(GetException(base)); TString fullName = TString("pybind.") + name; TPyObjectPtr exception(PyErr_NewException(const_cast(fullName.c_str()), baseException.Get(), nullptr), true); Checkers.push_back(new TConcreteExceptionsChecker(name, exception)); Exceptions[name] = exception; } template void AddException(const TString& name, const TVector& bases) { TPyObjectPtr baseExceptions(GetExceptions(bases)); TString fullName = TString("pybind.") + name; TPyObjectPtr exception(PyErr_NewException(const_cast(fullName.c_str()), baseExceptions.Get(), nullptr), true); Checkers.push_back(new TConcreteExceptionsChecker(name, exception)); Exceptions[name] = exception; } NPyBind::TPyObjectPtr ToPyException(const std::exception&); }; }