cast.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #pragma once
  2. #define PY_SSIZE_T_CLEAN
  3. #include <Python.h>
  4. #include <util/generic/strbuf.h>
  5. #include <util/generic/vector.h>
  6. #include <util/generic/set.h>
  7. #include <util/generic/yexception.h>
  8. #include <util/generic/hash.h>
  9. #include <util/generic/map.h>
  10. #include <util/generic/maybe.h>
  11. #include <utility>
  12. #include <initializer_list>
  13. #include "ptr.h"
  14. namespace NPyBind {
  15. PyObject* GetTrueRef(bool incref = true);
  16. PyObject* GetFalseRef(bool incref = true);
  17. PyObject* BuildPyObject(int val);
  18. PyObject* BuildPyObject(unsigned int val);
  19. PyObject* BuildPyObject(long int val);
  20. PyObject* BuildPyObject(unsigned long int val);
  21. #ifdef PY_LONG_LONG
  22. PyObject* BuildPyObject(PY_LONG_LONG val);
  23. PyObject* BuildPyObject(unsigned PY_LONG_LONG val);
  24. #endif
  25. PyObject* BuildPyObject(float val);
  26. PyObject* BuildPyObject(double val);
  27. PyObject* BuildPyObject(const TStringBuf& val);
  28. PyObject* BuildPyObject(const char* val);
  29. PyObject* BuildPyObject(const TWtringBuf& val);
  30. PyObject* BuildPyObject(const TBuffer& val);
  31. PyObject* BuildPyObject(bool val);
  32. PyObject* BuildPyObject(PyObject*);
  33. PyObject* BuildPyObject(TPyObjectPtr);
  34. template <typename T>
  35. PyObject* BuildPyObject(const TVector<T>& val);
  36. template <typename T>
  37. PyObject* BuildPyObject(const TSet<T>& val);
  38. template <typename TKey, typename TVal>
  39. PyObject* BuildPyObject(const THashMap<TKey, TVal>& val);
  40. template <typename T1, typename T2>
  41. PyObject* BuildPyObject(const std::pair<T1, T2>& val) {
  42. TPyObjectPtr first(BuildPyObject(val.first), true);
  43. if (!first) {
  44. return nullptr;
  45. }
  46. TPyObjectPtr second(BuildPyObject(val.second), true);
  47. if (!first || !second) {
  48. return nullptr;
  49. }
  50. TPyObjectPtr res(PyList_New(2), true);
  51. PyList_SetItem(res.Get(), 0, first.RefGet());
  52. PyList_SetItem(res.Get(), 1, second.RefGet());
  53. return res.RefGet();
  54. }
  55. template <typename T>
  56. PyObject* BuildPyObject(const TVector<T>& val) {
  57. TPyObjectPtr res(PyList_New(val.size()), true);
  58. for (size_t i = 0, size = val.size(); i < size; ++i) {
  59. auto pythonVal = BuildPyObject(std::move(val[i]));
  60. if (!pythonVal) {
  61. return nullptr;
  62. }
  63. PyList_SetItem(res.Get(), i, pythonVal);
  64. }
  65. return res.RefGet();
  66. }
  67. template <typename T>
  68. PyObject* BuildPyObject(TVector<T>&& val) {
  69. TPyObjectPtr res(PyList_New(val.size()), true);
  70. for (size_t i = 0, size = val.size(); i < size; ++i) {
  71. auto pythonVal = BuildPyObject(std::move(val[i]));
  72. if (!pythonVal) {
  73. return nullptr;
  74. }
  75. PyList_SetItem(res.Get(), i, pythonVal);
  76. }
  77. return res.RefGet();
  78. }
  79. template <typename T>
  80. PyObject* BuildPyObject(const TSet<T>& val) {
  81. TPyObjectPtr res(PySet_New(nullptr), true);
  82. for (const auto& v : val) {
  83. auto pythonVal = BuildPyObject(std::move(v));
  84. if (!pythonVal) {
  85. return nullptr;
  86. }
  87. PySet_Add(res.Get(), pythonVal);
  88. }
  89. return res.RefGet();
  90. }
  91. template <typename T>
  92. PyObject* BuildPyObject(const THashSet<T>& val) {
  93. TPyObjectPtr res(PySet_New(nullptr), true);
  94. for (const auto& v : val) {
  95. auto pythonVal = BuildPyObject(std::move(v));
  96. if (!pythonVal) {
  97. return nullptr;
  98. }
  99. PySet_Add(res.Get(), pythonVal);
  100. }
  101. return res.RefGet();
  102. }
  103. template <typename TKey, typename TVal>
  104. PyObject* BuildPyObject(const THashMap<TKey, TVal>& val) {
  105. TPyObjectPtr res(PyDict_New(), true);
  106. for (typename THashMap<TKey, TVal>::const_iterator it = val.begin(), end = val.end(); it != end; ++it) {
  107. auto prevOccurred = PyErr_Occurred();
  108. Y_UNUSED(prevOccurred);
  109. TPyObjectPtr k(BuildPyObject(it->first), true);
  110. if (!k) {
  111. return nullptr;
  112. }
  113. TPyObjectPtr v(BuildPyObject(it->second), true);
  114. if (!v) {
  115. return nullptr;
  116. }
  117. PyDict_SetItem(res.Get(), k.Get(), v.Get());
  118. }
  119. return res.RefGet();
  120. }
  121. template <typename TKey, typename TVal>
  122. PyObject* BuildPyObject(const TMap<TKey, TVal>& val) {
  123. TPyObjectPtr res(PyDict_New(), true);
  124. for (typename TMap<TKey, TVal>::const_iterator it = val.begin(), end = val.end(); it != end; ++it) {
  125. TPyObjectPtr k(BuildPyObject(it->first), true);
  126. if (!k) {
  127. return nullptr;
  128. }
  129. TPyObjectPtr v(BuildPyObject(it->second), true);
  130. if (!v) {
  131. return nullptr;
  132. }
  133. PyDict_SetItem(res.Get(), k.Get(), v.Get());
  134. }
  135. return res.RefGet();
  136. }
  137. template <typename TKey, typename TVal>
  138. PyObject* BuildPyObject(const TMultiMap<TKey, TVal>& val) {
  139. TPyObjectPtr res(PyDict_New(), true);
  140. TMaybe<TKey> prevKey;
  141. TPyObjectPtr currentEntry(PyList_New(0), true);
  142. for (const auto& [key, value]: val) {
  143. if (prevKey.Defined() && prevKey != key) {
  144. TPyObjectPtr pyPrevKey(BuildPyObject(*prevKey), true);
  145. if (!pyPrevKey) {
  146. return nullptr;
  147. }
  148. PyDict_SetItem(res.Get(), pyPrevKey.Get(), currentEntry.Get());
  149. currentEntry = TPyObjectPtr(PyList_New(0), true);
  150. }
  151. TPyObjectPtr pyValue(BuildPyObject(value), true);
  152. if (!pyValue) {
  153. return nullptr;
  154. }
  155. PyList_Append(currentEntry.Get(), pyValue.Get());
  156. prevKey = key;
  157. }
  158. if (prevKey.Defined()) {
  159. TPyObjectPtr pyPrevKey(BuildPyObject(*prevKey), true);
  160. if (!pyPrevKey) {
  161. return nullptr;
  162. }
  163. PyDict_SetItem(res.Get(), pyPrevKey.Get(), currentEntry.Get());
  164. }
  165. return res.RefGet();
  166. }
  167. template <typename T>
  168. PyObject* BuildPyObject(const TMaybe<T>& val) {
  169. if (!val.Defined())
  170. Py_RETURN_NONE;
  171. return BuildPyObject(val.GetRef());
  172. }
  173. template <typename T, typename C, typename D>
  174. PyObject* BuildPyObject(const TSharedPtr<T, C, D>& val) {
  175. if (!val.Get())
  176. Py_RETURN_NONE;
  177. return BuildPyObject(*val.Get());
  178. }
  179. template <typename T>
  180. bool FromPyObject(PyObject* obj, T& res);
  181. bool FromPyObject(PyObject* obj, TString& res);
  182. bool FromPyObject(PyObject* obj, TStringBuf& res);
  183. bool FromPyObject(PyObject* obj, TUtf16String& res);
  184. bool FromPyObject(PyObject* obj, TBuffer& res);
  185. template <typename T>
  186. bool FromPyObject(PyObject* obj, TMaybe<T>& res) {
  187. //we need to save current error before trying derserialize the value
  188. //because it can produce conversion errors in python that we don't need to handle
  189. struct TError {
  190. public:
  191. TError() {
  192. PyErr_Fetch(&Type, &Value, &Traceback);
  193. }
  194. ~TError() {
  195. PyErr_Restore(Type, Value, Traceback);
  196. }
  197. private:
  198. PyObject* Type = nullptr;
  199. PyObject* Value = nullptr;
  200. PyObject* Traceback = nullptr;
  201. } currentPyExcInfo;
  202. T val;
  203. if (FromPyObject(obj, val)) {
  204. res = val;
  205. return true;
  206. }
  207. if (obj == Py_None) {
  208. res = Nothing();
  209. return true;
  210. }
  211. return false;
  212. }
  213. template <typename T1, typename T2>
  214. bool FromPyObject(PyObject* obj, std::pair<T1, T2>& res) {
  215. PyObject* first;
  216. PyObject* second;
  217. if (PyTuple_Check(obj) && 2 == PyTuple_Size(obj)) {
  218. first = PyTuple_GET_ITEM(obj, 0);
  219. second = PyTuple_GET_ITEM(obj, 1);
  220. } else if (PyList_Check(obj) && 2 == PyList_Size(obj)) {
  221. first = PyList_GET_ITEM(obj, 0);
  222. second = PyList_GET_ITEM(obj, 1);
  223. } else {
  224. return false;
  225. }
  226. return FromPyObject(first, res.first) && FromPyObject(second, res.second);
  227. }
  228. template <typename T>
  229. bool FromPyObject(PyObject* obj, TVector<T>& res) {
  230. if (!PyList_Check(obj))
  231. return false;
  232. size_t cnt = PyList_Size(obj);
  233. res.resize(cnt);
  234. for (size_t i = 0; i < cnt; ++i) {
  235. PyObject* item = PyList_GET_ITEM(obj, i);
  236. if (!FromPyObject(item, res[i]))
  237. return false;
  238. }
  239. return true;
  240. }
  241. template <typename K, typename V>
  242. bool FromPyObject(PyObject* obj, THashMap<K, V>& res) {
  243. if (!PyDict_Check(obj))
  244. return false;
  245. TPyObjectPtr list(PyDict_Keys(obj), true);
  246. size_t cnt = PyList_Size(list.Get());
  247. for (size_t i = 0; i < cnt; ++i) {
  248. PyObject* key = PyList_GET_ITEM(list.Get(), i);
  249. PyObject* value = PyDict_GetItem(obj, key);
  250. K rkey;
  251. V rvalue;
  252. if (!FromPyObject(key, rkey))
  253. return false;
  254. if (!FromPyObject(value, rvalue))
  255. return false;
  256. res[rkey] = rvalue;
  257. }
  258. return true;
  259. }
  260. template <typename K, typename V>
  261. bool FromPyObject(PyObject* obj, TMap<K, V>& res) {
  262. if (!PyDict_Check(obj))
  263. return false;
  264. TPyObjectPtr list(PyDict_Keys(obj), true);
  265. size_t cnt = PyList_Size(list.Get());
  266. for (size_t i = 0; i < cnt; ++i) {
  267. PyObject* key = PyList_GET_ITEM(list.Get(), i);
  268. PyObject* value = PyDict_GetItem(obj, key);
  269. K rkey;
  270. V rvalue;
  271. if (!FromPyObject(key, rkey))
  272. return false;
  273. if (!FromPyObject(value, rvalue))
  274. return false;
  275. res[rkey] = rvalue;
  276. }
  277. return true;
  278. }
  279. class cast_exception: public TBadCastException {
  280. };
  281. template <typename T>
  282. T FromPyObject(PyObject* obj) {
  283. T res;
  284. if (!FromPyObject(obj, res))
  285. ythrow cast_exception() << "Cannot cast argument to " << TypeName<T>();
  286. return res;
  287. }
  288. template <class... Args, std::size_t... I>
  289. bool ExtractArgs(std::index_sequence<I...>, PyObject* args, Args&... outArgs) {
  290. if (!args || !PyTuple_Check(args) || PyTuple_Size(args) != sizeof...(Args))
  291. return false;
  292. bool res = true;
  293. (void)std::initializer_list<bool>{(res = res && NPyBind::FromPyObject(PyTuple_GET_ITEM(args, I), outArgs))...};
  294. return res;
  295. }
  296. template <class... Args>
  297. bool ExtractArgs(PyObject* args, Args&... outArgs) {
  298. return ExtractArgs(std::index_sequence_for<Args...>(), args, outArgs...);
  299. }
  300. template <class... Args, std::size_t... I>
  301. bool ExtractOptionalArgs(std::index_sequence<I...>, PyObject* args, PyObject* kwargs, const char* keywords[], Args&... outArgs) {
  302. PyObject* pargs[sizeof...(Args)] = {};
  303. static const char format[sizeof...(Args) + 2] = {'|', ((void)I, 'O')..., 0};
  304. if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, const_cast<char**>(keywords), &pargs[I]...))
  305. return false;
  306. bool res = true;
  307. (void)std::initializer_list<bool>{(res = res && (!pargs[I] || NPyBind::FromPyObject(pargs[I], outArgs)))...};
  308. return res;
  309. }
  310. template <class... Args>
  311. bool ExtractOptionalArgs(PyObject* args, PyObject* kwargs, const char* keywords[], Args&... outArgs) {
  312. return ExtractOptionalArgs(std::index_sequence_for<Args...>(), args, kwargs, keywords, outArgs...);
  313. }
  314. template <typename... Args, std::size_t... I>
  315. static auto GetArguments(std::index_sequence<I...>, PyObject* args) {
  316. Y_UNUSED(args); // gcc bug
  317. return std::make_tuple(FromPyObject<std::remove_cv_t<std::remove_reference_t<Args>>>(PyTuple_GetItem(args, I))...);
  318. }
  319. template <typename... Args>
  320. static auto GetArguments(PyObject* args) {
  321. return GetArguments<Args...>(std::index_sequence_for<Args...>(), args);
  322. }
  323. inline PyObject* ReturnString(TStringBuf s) {
  324. #if PY_MAJOR_VERSION >= 3
  325. return PyUnicode_FromStringAndSize(s.data(), s.size());
  326. #else
  327. return PyBytes_FromStringAndSize(s.data(), s.size());
  328. #endif
  329. }
  330. inline TPyObjectPtr ReturnBytes(TStringBuf s) {
  331. return TPyObjectPtr(PyBytes_FromStringAndSize(s.data(), s.size()), true);
  332. }
  333. inline TPyObjectPtr NameFromString(TStringBuf s) {
  334. return TPyObjectPtr(ReturnString(s), true);
  335. }
  336. }