attr.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. #pragma once
  2. #define PY_SSIZE_T_CLEAN
  3. #include <Python.h>
  4. #include <util/generic/string.h>
  5. #include <util/generic/map.h>
  6. #include <util/generic/set.h>
  7. #include <util/generic/vector.h>
  8. #include <util/generic/ptr.h>
  9. #include "cast.h"
  10. #include "exceptions.h"
  11. namespace NPyBind {
  12. // TBaseAttrGetter
  13. template <typename TObjType>
  14. class TBaseAttrGetter {
  15. public:
  16. virtual ~TBaseAttrGetter() {
  17. }
  18. virtual bool GetAttr(PyObject* owner, const TObjType& self, const TString& attr, PyObject*& res) const = 0;
  19. virtual bool HasAttr(PyObject* owner, const TObjType& self, const TString& attr, const TSet<TString>& hiddenNames) const {
  20. if (hiddenNames.find(attr) != hiddenNames.end())
  21. return false;
  22. PyObject* res = nullptr;
  23. if (!GetAttr(owner, self, attr, res))
  24. return false;
  25. Py_XDECREF(res);
  26. return true;
  27. }
  28. };
  29. template <typename TObjType>
  30. class TBaseAttrSetter {
  31. public:
  32. virtual ~TBaseAttrSetter() {
  33. }
  34. virtual bool SetAttr(PyObject* owner, TObjType& self, const TString& attr, PyObject* val) = 0;
  35. };
  36. template <typename TObjType>
  37. class TAttrGetters {
  38. public:
  39. typedef TSimpleSharedPtr<TBaseAttrGetter<TObjType>> TGetterPtr;
  40. private:
  41. typedef TVector<TGetterPtr> TGetterList;
  42. typedef TMap<TString, TGetterList> TGetterMap;
  43. const TSet<TString>& HiddenAttrNames;
  44. TGetterMap Getters;
  45. public:
  46. TAttrGetters(const TSet<TString>& hiddenNames)
  47. : HiddenAttrNames(hiddenNames)
  48. {
  49. }
  50. void AddGetter(const TString& attr, TGetterPtr getter) {
  51. Getters[attr].push_back(getter);
  52. }
  53. PyObject* GetAttr(PyObject* owner, const TObjType& self, const TString& attr) const {
  54. typename TGetterMap::const_iterator it1 = Getters.find(attr);
  55. if (it1 == Getters.end())
  56. it1 = Getters.find("");
  57. if (it1 == Getters.end())
  58. return nullptr;
  59. const TGetterList& lst = it1->second;
  60. for (typename TGetterList::const_iterator it2 = lst.begin(), end = lst.end(); it2 != end; ++it2) {
  61. PyObject* res = nullptr;
  62. if ((*it2)->GetAttr(owner, self, attr, res))
  63. return res;
  64. // IMPORTANT!
  65. // we have to fail GetAttr right there because we've failed because of internal python error/exception and can't continue iterating because
  66. // it cause subsequent exceptions during call to Py_BuildValue
  67. // moreover we have to preserve original exception right there
  68. if (PyErr_Occurred()) {
  69. break;
  70. }
  71. }
  72. return nullptr;
  73. }
  74. bool HasAttr(PyObject* owner, const TObjType& self, const TString& attr) const {
  75. typename TGetterMap::const_iterator it1 = Getters.find(attr);
  76. if (it1 == Getters.end())
  77. return false;
  78. const TGetterList& lst = it1->second;
  79. for (typename TGetterList::const_iterator it2 = lst.begin(), end = lst.end(); it2 != end; ++it2) {
  80. if ((*it2)->HasAttr(owner, self, attr, HiddenAttrNames))
  81. return true;
  82. }
  83. return false;
  84. }
  85. void GetAttrsDictionary(PyObject* owner, const TObjType& self, TMap<TString, PyObject*>& res) const {
  86. for (typename TGetterMap::const_iterator it = Getters.begin(), end = Getters.end(); it != end; ++it) {
  87. try {
  88. if (HasAttr(owner, self, it->first)) {
  89. auto attrPtr = GetAttr(owner, self, it->first);
  90. if (attrPtr) {
  91. res[it->first] = attrPtr;
  92. }
  93. if (PyErr_Occurred()) {
  94. PyErr_Clear(); // Skip python errors as well
  95. }
  96. }
  97. } catch (const std::exception&) {
  98. // ignore this field
  99. }
  100. }
  101. }
  102. void GetAttrsNames(PyObject* owner, const TObjType& self, TVector<TString>& resultNames) const {
  103. for (typename TGetterMap::const_iterator it = Getters.begin(), end = Getters.end(); it != end; ++it) {
  104. if (HasAttr(owner, self, it->first))
  105. resultNames.push_back(it->first);
  106. }
  107. }
  108. };
  109. template <typename TObjType>
  110. class TGenericAttrGetter: public TBaseAttrGetter<TObjType> {
  111. private:
  112. TString AttrName;
  113. public:
  114. TGenericAttrGetter(const TString& attrName)
  115. : AttrName(attrName)
  116. {
  117. }
  118. bool GetAttr(PyObject* obj, const TObjType&, const TString&, PyObject*& res) const override {
  119. auto str = NameFromString(AttrName);
  120. res = PyObject_GenericGetAttr(obj, str.Get());
  121. if (!res && !PyErr_Occurred())
  122. ythrow TPyErr(PyExc_AttributeError) << "Can't get generic attribute '" << AttrName << "'";
  123. return res;
  124. }
  125. };
  126. template <typename TObjType>
  127. class TAttrSetters {
  128. private:
  129. typedef TSimpleSharedPtr<TBaseAttrSetter<TObjType>> TSetterPtr;
  130. typedef TVector<TSetterPtr> TSetterList;
  131. typedef TMap<TString, TSetterList> TSetterMap;
  132. TSetterMap Setters;
  133. public:
  134. void AddSetter(const TString& attr, TSetterPtr setter) {
  135. Setters[attr].push_back(setter);
  136. }
  137. bool SetAttr(PyObject* owner, TObjType& self, const TString& attr, PyObject* val) {
  138. typename TSetterMap::const_iterator it1 = Setters.find(attr);
  139. if (it1 == Setters.end())
  140. it1 = Setters.find("");
  141. if (it1 == Setters.end())
  142. return false;
  143. const TSetterList& lst = it1->second;
  144. for (typename TSetterList::const_iterator it2 = lst.begin(), end = lst.end(); it2 != end; ++it2) {
  145. if ((*it2)->SetAttr(owner, self, attr, val))
  146. return true;
  147. }
  148. return false;
  149. }
  150. bool SetAttrDictionary(PyObject* owner, TObjType& self, TMap<TString, PyObject*>& dict) {
  151. for (TMap<TString, PyObject*>::const_iterator it = dict.begin(), end = dict.end(); it != end; ++it) {
  152. try {
  153. SetAttr(owner, self, it->first, it->second);
  154. } catch (std::exception&) {
  155. // ignore this field
  156. }
  157. }
  158. return true;
  159. }
  160. };
  161. /**
  162. * TMethodAttrGetter - this class maps Python attribute read to C++ method call
  163. */
  164. template <typename TObjType, typename TResult, typename TSubObject>
  165. class TMethodAttrGetter: public TBaseAttrGetter<TObjType> {
  166. private:
  167. typedef TResult (TSubObject::*TMethod)() const;
  168. TMethod Method;
  169. public:
  170. TMethodAttrGetter(TMethod method)
  171. : Method(method)
  172. {
  173. }
  174. bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
  175. const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
  176. if (sub == nullptr)
  177. return false;
  178. res = BuildPyObject((sub->*Method)());
  179. return (res != nullptr);
  180. }
  181. };
  182. template <typename TObjType, typename TFunctor>
  183. class TFunctorAttrGetter: public TBaseAttrGetter<TObjType> {
  184. TFunctor Functor;
  185. public:
  186. explicit TFunctorAttrGetter(TFunctor functor)
  187. : Functor(functor)
  188. {
  189. }
  190. bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
  191. res = BuildPyObject(Functor(self));
  192. return (res != nullptr);
  193. }
  194. };
  195. /**
  196. * TMethodAttrGetterWithCheck - this class maps Python attribute read to C++ HasAttr/GetAttr call
  197. * If HasAttr returns false, None is returned.
  198. * Otherwise GetAttr is called.
  199. */
  200. template <typename TObjType, typename TResult, typename TSubObject>
  201. class TMethodAttrGetterWithCheck: public TBaseAttrGetter<TObjType> {
  202. private:
  203. typedef TResult (TSubObject::*TMethod)() const;
  204. typedef bool (TSubObject::*TCheckerMethod)() const;
  205. TMethod Method;
  206. TCheckerMethod CheckerMethod;
  207. public:
  208. TMethodAttrGetterWithCheck(TMethod method, TCheckerMethod checkerMethod)
  209. : Method(method)
  210. , CheckerMethod(checkerMethod)
  211. {
  212. }
  213. bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
  214. const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
  215. if (sub == nullptr)
  216. return false;
  217. if ((sub->*CheckerMethod)())
  218. res = BuildPyObject((sub->*Method)());
  219. else {
  220. Py_INCREF(Py_None);
  221. res = Py_None;
  222. }
  223. return (res != nullptr);
  224. }
  225. };
  226. template <typename TObjType, typename TResult, typename TSubObject, typename TMapper>
  227. class TMethodAttrMappingGetter: public TBaseAttrGetter<TObjType> {
  228. private:
  229. typedef TResult (TSubObject::*TMethod)() const;
  230. TMethod Method;
  231. TMapper Mapper;
  232. public:
  233. TMethodAttrMappingGetter(TMethod method, TMapper mapper)
  234. : Method(method)
  235. , Mapper(mapper)
  236. {
  237. }
  238. bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
  239. const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
  240. if (sub == nullptr)
  241. return false;
  242. res = BuildPyObject(Mapper((sub->*Method)()));
  243. return (res != nullptr);
  244. }
  245. };
  246. template <typename TObjType, typename TResult, typename TSubObject, typename TMapper>
  247. TSimpleSharedPtr<TBaseAttrGetter<TObjType>>
  248. CreateMethodAttrMappingGetter(TResult (TSubObject::*method)() const,
  249. TMapper mapper) {
  250. return new TMethodAttrMappingGetter<TObjType, TResult, TSubObject, TMapper>(method,
  251. mapper);
  252. }
  253. template <typename TObjType, typename TResult, typename TValue, typename TSubObject>
  254. class TMethodAttrSetter: public TBaseAttrSetter<TObjType> {
  255. private:
  256. typedef TResult (TSubObject::*TMethod)(TValue&);
  257. TMethod Method;
  258. public:
  259. TMethodAttrSetter(TMethod method)
  260. : Method(method)
  261. {
  262. }
  263. virtual bool SetAttr(PyObject*, TObjType& self, const TString&, PyObject* val) {
  264. TSubObject* sub = dynamic_cast<TSubObject*>(&self);
  265. if (sub == nullptr)
  266. return false;
  267. TValue value;
  268. if (!FromPyObject(val, value))
  269. return false;
  270. (sub->*Method)(value);
  271. return true;
  272. }
  273. };
  274. template <typename TObjType, typename TValue, typename TFunctor>
  275. class TFunctorAttrSetter: public TBaseAttrSetter<TObjType> {
  276. TFunctor Functor;
  277. public:
  278. explicit TFunctorAttrSetter(TFunctor functor)
  279. : Functor(functor)
  280. {
  281. }
  282. bool SetAttr(PyObject*, TObjType& self, const TString&, PyObject* val) const override {
  283. TValue value;
  284. if (!FromPyObject(val, value))
  285. return false;
  286. auto res = BuildPyObject(Functor(self, value));
  287. return (res != nullptr);
  288. }
  289. };
  290. template <typename TObjType, typename TResult, typename TSubObject>
  291. TSimpleSharedPtr<TBaseAttrGetter<TObjType>> CreateMethodAttrGetter(TResult (TSubObject::*method)() const) {
  292. return new TMethodAttrGetter<TObjType, TResult, TSubObject>(method);
  293. }
  294. template <typename TObjType, typename TFunctor>
  295. TSimpleSharedPtr<TFunctorAttrGetter<TObjType, TFunctor>> CreateFunctorAttrGetter(TFunctor functor) {
  296. return MakeSimpleShared<TFunctorAttrGetter<TObjType, TFunctor>>(functor);
  297. }
  298. template <typename TObjType, typename TResult, typename TSubObject>
  299. TSimpleSharedPtr<TBaseAttrGetter<TObjType>> CreateMethodAttrGetterWithCheck(
  300. TResult (TSubObject::*method)() const,
  301. bool (TSubObject::*checkerMethod)() const) {
  302. return new TMethodAttrGetterWithCheck<TObjType, TResult, TSubObject>(method, checkerMethod);
  303. }
  304. template <typename TObjType, typename TResult, typename TValue, typename TSubObject>
  305. TSimpleSharedPtr<TBaseAttrSetter<TObjType>> CreateMethodAttrSetter(TResult (TSubObject::*method)(TValue&)) {
  306. return new TMethodAttrSetter<TObjType, TResult, TValue, TSubObject>(method);
  307. }
  308. template <typename TObjType, typename TFunctor, typename TValue>
  309. TSimpleSharedPtr<TFunctorAttrSetter<TObjType, TValue, TFunctor>> CreateFunctorAttrSetter(TFunctor functor) {
  310. return MakeSimpleShared<TFunctorAttrSetter<TObjType, TValue, TFunctor>>(functor);
  311. }
  312. template <typename TObjType, typename TValue, typename TSubObject>
  313. class TDirectAttrSetter: public TBaseAttrSetter<TObjType> {
  314. private:
  315. typedef TValue TSubObject::*TValueType;
  316. TValueType Value;
  317. public:
  318. TDirectAttrSetter(TValueType value)
  319. : Value(value)
  320. {
  321. }
  322. bool SetAttr(PyObject*, TObjType& self, const TString&, PyObject* val) override {
  323. TSubObject* sub = dynamic_cast<TSubObject*>(&self);
  324. if (sub == NULL)
  325. return false;
  326. if (!FromPyObject(val, sub->*Value))
  327. return false;
  328. return true;
  329. }
  330. };
  331. template <typename TObjType, typename TValue, typename TSubObject>
  332. TSimpleSharedPtr<TBaseAttrSetter<TObjType>> CreateAttrSetter(TValue TSubObject::*value) {
  333. return new TDirectAttrSetter<TObjType, TValue, TSubObject>(value);
  334. }
  335. template <typename TObjType, typename TValue, typename TSubObject>
  336. class TDirectAttrGetter: public TBaseAttrGetter<TObjType> {
  337. private:
  338. typedef TValue TSubObject::*TValueType;
  339. TValueType Value;
  340. public:
  341. TDirectAttrGetter(TValueType value)
  342. : Value(value)
  343. {
  344. }
  345. bool GetAttr(PyObject*, const TObjType& self, const TString&, PyObject*& res) const override {
  346. const TSubObject* sub = dynamic_cast<const TSubObject*>(&self);
  347. if (sub == nullptr)
  348. return false;
  349. res = BuildPyObject(sub->*Value);
  350. return (res != nullptr);
  351. }
  352. };
  353. template <typename TObjType, typename TValue, typename TSubObject>
  354. TSimpleSharedPtr<TBaseAttrGetter<TObjType>> CreateAttrGetter(TValue TSubObject::*value) {
  355. return new TDirectAttrGetter<TObjType, TValue, TSubObject>(value);
  356. }
  357. }