blob: 48e20995e46c25ede5a22f1f59369f6fa3b4d134 (
plain) (
tree)
|
|
#pragma once
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <util/generic/yexception.h>
#include <util/generic/map.h>
#include <util/generic/vector.h>
#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;
};
//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<TString>&);
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 <typename TExcType>
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<const TExcType*>(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<const TPyErr*>(&ex);
if (err) {
Exception = err->GetException();
}
return err != nullptr;
}
TString GetName() const override {
return TString();
}
TPyObjectPtr GetException() const override {
return Exception;
}
};
typedef TSimpleSharedPtr<TExceptionsChecker> TCheckerPtr;
typedef TVector<TCheckerPtr> TCheckersVector;
typedef TMap<TString, TPyObjectPtr> TExceptionsMap;
TPyObjectPtr Module;
TCheckersVector Checkers;
TExceptionsMap Exceptions;
static PyObject* DoInitPyBindModule();
static void DoInitPyBindModule2();
public:
static TExceptionsHolder& Instance() {
static TExceptionsHolder Holder;
return Holder;
}
template <typename TExcType>
void AddException(const TString& name, const TString& base = "") {
TPyObjectPtr baseException(GetException(base));
TString fullName = TString("pybind.") + name;
TPyObjectPtr exception(PyErr_NewException(const_cast<char*>(fullName.c_str()), baseException.Get(), nullptr), true);
Checkers.push_back(new TConcreteExceptionsChecker<TExcType>(name, exception));
Exceptions[name] = exception;
}
template <typename TExcType>
void AddException(const TString& name, const TVector<TString>& bases) {
TPyObjectPtr baseExceptions(GetExceptions(bases));
TString fullName = TString("pybind.") + name;
TPyObjectPtr exception(PyErr_NewException(const_cast<char*>(fullName.c_str()), baseExceptions.Get(), nullptr), true);
Checkers.push_back(new TConcreteExceptionsChecker<TExcType>(name, exception));
Exceptions[name] = exception;
}
NPyBind::TPyObjectPtr ToPyException(const std::exception&);
};
}
|