exceptions.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #pragma once
  2. #define PY_SSIZE_T_CLEAN
  3. #include <Python.h>
  4. #include <util/generic/yexception.h>
  5. #include <util/generic/map.h>
  6. #include <util/generic/vector.h>
  7. #include "ptr.h"
  8. namespace NPyBind {
  9. // Usage:
  10. // ythrow TPyErr(PyExc_TypeError) << "some python type error somewhere in your C++ code";
  11. //
  12. class TPyErr: public virtual yexception {
  13. public:
  14. TPyErr(PyObject* theException = PyExc_RuntimeError)
  15. : Exception(theException)
  16. {
  17. }
  18. TPyObjectPtr GetException() const {
  19. return Exception;
  20. }
  21. private:
  22. NPyBind::TPyObjectPtr Exception;
  23. };
  24. //Private api for creating PyBind python module
  25. //Needs only for overriding pybind python module in library which imports other pybind library
  26. namespace NPrivate {
  27. TPyObjectPtr CreatePyBindModule();
  28. }//NPrivate
  29. class TExceptionsHolder {
  30. friend TPyObjectPtr NPrivate::CreatePyBindModule();
  31. private:
  32. TExceptionsHolder(const TExceptionsHolder&);
  33. TExceptionsHolder& operator=(const TExceptionsHolder&);
  34. TExceptionsHolder();
  35. void Clear();
  36. TPyObjectPtr GetException(const TString&);
  37. TPyObjectPtr GetExceptions(const TVector<TString>&);
  38. private:
  39. class TExceptionsChecker {
  40. public:
  41. virtual ~TExceptionsChecker() {
  42. }
  43. virtual bool Check(const std::exception& ex) const = 0;
  44. virtual TString GetName() const = 0;
  45. virtual TPyObjectPtr GetException() const = 0;
  46. };
  47. template <typename TExcType>
  48. class TConcreteExceptionsChecker: public TExceptionsChecker {
  49. private:
  50. TString Name;
  51. TPyObjectPtr Exception;
  52. public:
  53. TConcreteExceptionsChecker(const TString& name, TPyObjectPtr exception)
  54. : Name(name)
  55. , Exception(exception)
  56. {
  57. }
  58. bool Check(const std::exception& ex) const override {
  59. const std::exception* e = &ex;
  60. return dynamic_cast<const TExcType*>(e);
  61. }
  62. TString GetName() const override {
  63. return Name;
  64. }
  65. TPyObjectPtr GetException() const override {
  66. return Exception;
  67. }
  68. };
  69. class TPyErrExceptionsChecker: public TExceptionsChecker {
  70. private:
  71. mutable TPyObjectPtr Exception;
  72. public:
  73. TPyErrExceptionsChecker() {
  74. }
  75. bool Check(const std::exception& ex) const override {
  76. const TPyErr* err = dynamic_cast<const TPyErr*>(&ex);
  77. if (err) {
  78. Exception = err->GetException();
  79. }
  80. return err != nullptr;
  81. }
  82. TString GetName() const override {
  83. return TString();
  84. }
  85. TPyObjectPtr GetException() const override {
  86. return Exception;
  87. }
  88. };
  89. typedef TSimpleSharedPtr<TExceptionsChecker> TCheckerPtr;
  90. typedef TVector<TCheckerPtr> TCheckersVector;
  91. typedef TMap<TString, TPyObjectPtr> TExceptionsMap;
  92. TPyObjectPtr Module;
  93. TCheckersVector Checkers;
  94. TExceptionsMap Exceptions;
  95. static PyObject* DoInitPyBindModule();
  96. static void DoInitPyBindModule2();
  97. public:
  98. static TExceptionsHolder& Instance() {
  99. static TExceptionsHolder Holder;
  100. return Holder;
  101. }
  102. template <typename TExcType>
  103. void AddException(const TString& name, const TString& base = "") {
  104. TPyObjectPtr baseException(GetException(base));
  105. TString fullName = TString("pybind.") + name;
  106. TPyObjectPtr exception(PyErr_NewException(const_cast<char*>(fullName.c_str()), baseException.Get(), nullptr), true);
  107. Checkers.push_back(new TConcreteExceptionsChecker<TExcType>(name, exception));
  108. Exceptions[name] = exception;
  109. }
  110. template <typename TExcType>
  111. void AddException(const TString& name, const TVector<TString>& bases) {
  112. TPyObjectPtr baseExceptions(GetExceptions(bases));
  113. TString fullName = TString("pybind.") + name;
  114. TPyObjectPtr exception(PyErr_NewException(const_cast<char*>(fullName.c_str()), baseExceptions.Get(), nullptr), true);
  115. Checkers.push_back(new TConcreteExceptionsChecker<TExcType>(name, exception));
  116. Exceptions[name] = exception;
  117. }
  118. NPyBind::TPyObjectPtr ToPyException(const std::exception&);
  119. };
  120. }