py_wrappers.cxx 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795
  1. /**
  2. * @file py_wrappers.cxx
  3. * @author rdb
  4. * @date 2017-11-26
  5. */
  6. #include "py_wrappers.h"
  7. #ifdef HAVE_PYTHON
  8. #if PY_VERSION_HEX >= 0x03040000
  9. #define _COLLECTIONS_ABC "_collections_abc"
  10. #elif PY_VERSION_HEX >= 0x03030000
  11. #define _COLLECTIONS_ABC "collections.abc"
  12. #else
  13. #define _COLLECTIONS_ABC "_abcoll"
  14. #endif
  15. static void _register_collection(PyTypeObject *type, const char *abc) {
  16. PyObject *sys_modules = PyImport_GetModuleDict();
  17. if (sys_modules != nullptr) {
  18. PyObject *module = PyDict_GetItemString(sys_modules, _COLLECTIONS_ABC);
  19. if (module != nullptr) {
  20. PyObject *dict = PyModule_GetDict(module);
  21. if (module != nullptr) {
  22. #if PY_MAJOR_VERSION >= 3
  23. static PyObject *register_str = PyUnicode_InternFromString("register");
  24. #else
  25. static PyObject *register_str = PyString_InternFromString("register");
  26. #endif
  27. PyObject *sequence = PyDict_GetItemString(dict, abc);
  28. if (sequence != nullptr) {
  29. if (PyObject_CallMethodObjArgs(sequence, register_str, (PyObject *)type, nullptr) == nullptr) {
  30. PyErr_Print();
  31. }
  32. }
  33. }
  34. }
  35. }
  36. }
  37. /**
  38. * These classes are returned from properties that require a subscript
  39. * interface, ie. something.children[i] = 3.
  40. */
  41. static void Dtool_WrapperBase_dealloc(PyObject *self) {
  42. Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
  43. nassertv(wrap);
  44. Py_XDECREF(wrap->_self);
  45. Py_TYPE(self)->tp_free(self);
  46. }
  47. static PyObject *Dtool_WrapperBase_repr(PyObject *self) {
  48. Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
  49. nassertr(wrap, nullptr);
  50. PyObject *repr = PyObject_Repr(wrap->_self);
  51. PyObject *result;
  52. #if PY_MAJOR_VERSION >= 3
  53. result = PyUnicode_FromFormat("<%s[] of %s>", wrap->_name, PyUnicode_AsUTF8(repr));
  54. #else
  55. result = PyString_FromFormat("<%s[] of %s>", wrap->_name, PyString_AS_STRING(repr));
  56. #endif
  57. Py_DECREF(repr);
  58. return result;
  59. }
  60. static PyObject *Dtool_SequenceWrapper_repr(PyObject *self) {
  61. Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
  62. nassertr(wrap, nullptr);
  63. Py_ssize_t len = -1;
  64. if (wrap->_len_func != nullptr) {
  65. len = wrap->_len_func(wrap->_base._self);
  66. }
  67. if (len < 0) {
  68. PyErr_Restore(nullptr, nullptr, nullptr);
  69. return Dtool_WrapperBase_repr(self);
  70. }
  71. PyObject *repr = PyObject_Repr(wrap->_base._self);
  72. PyObject *result;
  73. #if PY_MAJOR_VERSION >= 3
  74. result = PyUnicode_FromFormat("<%s[%zd] of %s>", wrap->_base._name, len, PyUnicode_AsUTF8(repr));
  75. #else
  76. result = PyString_FromFormat("<%s[%zd] of %s>", wrap->_base._name, len, PyString_AS_STRING(repr));
  77. #endif
  78. Py_DECREF(repr);
  79. return result;
  80. }
  81. static Py_ssize_t Dtool_SequenceWrapper_length(PyObject *self) {
  82. Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
  83. nassertr(wrap, -1);
  84. if (wrap->_len_func != nullptr) {
  85. return wrap->_len_func(wrap->_base._self);
  86. } else {
  87. Dtool_Raise_TypeError("property does not support len()");
  88. return -1;
  89. }
  90. }
  91. static PyObject *Dtool_SequenceWrapper_getitem(PyObject *self, Py_ssize_t index) {
  92. Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
  93. nassertr(wrap, nullptr);
  94. nassertr(wrap->_getitem_func, nullptr);
  95. return wrap->_getitem_func(wrap->_base._self, index);
  96. }
  97. /**
  98. * Implementation of (x in property)
  99. */
  100. static int Dtool_SequenceWrapper_contains(PyObject *self, PyObject *value) {
  101. Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
  102. nassertr(wrap, -1);
  103. nassertr(wrap->_len_func, -1);
  104. nassertr(wrap->_getitem_func, -1);
  105. Py_ssize_t length = wrap->_len_func(wrap->_base._self);
  106. // Iterate through the items, invoking the equality function for each, until
  107. // we have found the matching one.
  108. for (Py_ssize_t index = 0; index < length; ++index) {
  109. PyObject *item = wrap->_getitem_func(wrap->_base._self, index);
  110. if (item != nullptr) {
  111. int cmp = PyObject_RichCompareBool(item, value, Py_EQ);
  112. if (cmp > 0) {
  113. return 1;
  114. }
  115. if (cmp < 0) {
  116. return -1;
  117. }
  118. } else {
  119. return -1;
  120. }
  121. }
  122. return 0;
  123. }
  124. /**
  125. * Implementation of property.index(x) which returns the index of the first
  126. * occurrence of x in the sequence, or raises a ValueError if it isn't found.
  127. */
  128. static PyObject *Dtool_SequenceWrapper_index(PyObject *self, PyObject *value) {
  129. Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
  130. nassertr(wrap, nullptr);
  131. nassertr(wrap->_len_func, nullptr);
  132. nassertr(wrap->_getitem_func, nullptr);
  133. Py_ssize_t length = wrap->_len_func(wrap->_base._self);
  134. // Iterate through the items, invoking the equality function for each, until
  135. // we have found the right one.
  136. for (Py_ssize_t index = 0; index < length; ++index) {
  137. PyObject *item = wrap->_getitem_func(wrap->_base._self, index);
  138. if (item != nullptr) {
  139. int cmp = PyObject_RichCompareBool(item, value, Py_EQ);
  140. if (cmp > 0) {
  141. return Dtool_WrapValue(index);
  142. }
  143. if (cmp < 0) {
  144. return nullptr;
  145. }
  146. } else {
  147. return nullptr;
  148. }
  149. }
  150. // Not found, raise ValueError.
  151. return PyErr_Format(PyExc_ValueError, "%s.index() did not find value", wrap->_base._name);
  152. }
  153. /**
  154. * Implementation of property.count(x) which returns the number of occurrences
  155. * of x in the sequence.
  156. */
  157. static PyObject *Dtool_SequenceWrapper_count(PyObject *self, PyObject *value) {
  158. Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self;
  159. nassertr(wrap, nullptr);
  160. Py_ssize_t index = 0;
  161. if (wrap->_len_func != nullptr) {
  162. index = wrap->_len_func(wrap->_base._self);
  163. } else {
  164. return Dtool_Raise_TypeError("property does not support count()");
  165. }
  166. // Iterate through the items, invoking the == operator for each.
  167. long count = 0;
  168. nassertr(wrap->_getitem_func, nullptr);
  169. while (index > 0) {
  170. --index;
  171. PyObject *item = wrap->_getitem_func(wrap->_base._self, index);
  172. if (item == nullptr) {
  173. return nullptr;
  174. }
  175. int cmp = PyObject_RichCompareBool(item, value, Py_EQ);
  176. if (cmp > 0) {
  177. ++count;
  178. }
  179. if (cmp < 0) {
  180. return nullptr;
  181. }
  182. }
  183. #if PY_MAJOR_VERSION >= 3
  184. return PyLong_FromLong(count);
  185. #else
  186. return PyInt_FromLong(count);
  187. #endif
  188. }
  189. /**
  190. * Implementation of `property[i] = x`
  191. */
  192. static int Dtool_MutableSequenceWrapper_setitem(PyObject *self, Py_ssize_t index, PyObject *value) {
  193. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self;
  194. nassertr(wrap, -1);
  195. if (wrap->_setitem_func != nullptr) {
  196. return wrap->_setitem_func(wrap->_base._self, index, value);
  197. } else {
  198. Dtool_Raise_TypeError("property does not support item assignment");
  199. return -1;
  200. }
  201. }
  202. /**
  203. * Implementation of property.clear() which removes all elements in the
  204. * sequence, starting with the last.
  205. */
  206. static PyObject *Dtool_MutableSequenceWrapper_clear(PyObject *self, PyObject *) {
  207. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self;
  208. nassertr(wrap, nullptr);
  209. Py_ssize_t index = 0;
  210. if (wrap->_len_func != nullptr && wrap->_setitem_func != nullptr) {
  211. index = wrap->_len_func(wrap->_base._self);
  212. } else {
  213. return Dtool_Raise_TypeError("property does not support clear()");
  214. }
  215. // Iterate through the items, invoking the delete function for each. We do
  216. // this in reverse order, which may be more efficient.
  217. while (index > 0) {
  218. --index;
  219. if (wrap->_setitem_func(wrap->_base._self, index, nullptr) != 0) {
  220. return nullptr;
  221. }
  222. }
  223. Py_INCREF(Py_None);
  224. return Py_None;
  225. }
  226. /**
  227. * Implementation of property.remove(x) which removes the first occurrence of
  228. * x in the sequence, or raises a ValueError if it isn't found.
  229. */
  230. static PyObject *Dtool_MutableSequenceWrapper_remove(PyObject *self, PyObject *value) {
  231. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self;
  232. nassertr(wrap, nullptr);
  233. Py_ssize_t length = 0;
  234. if (wrap->_len_func != nullptr && wrap->_setitem_func != nullptr) {
  235. length = wrap->_len_func(wrap->_base._self);
  236. } else {
  237. return Dtool_Raise_TypeError("property does not support remove()");
  238. }
  239. // Iterate through the items, invoking the equality function for each, until
  240. // we have found the right one.
  241. nassertr(wrap->_getitem_func, nullptr);
  242. for (Py_ssize_t index = 0; index < length; ++index) {
  243. PyObject *item = wrap->_getitem_func(wrap->_base._self, index);
  244. if (item != nullptr) {
  245. int cmp = PyObject_RichCompareBool(item, value, Py_EQ);
  246. if (cmp > 0) {
  247. if (wrap->_setitem_func(wrap->_base._self, index, nullptr) == 0) {
  248. Py_INCREF(Py_None);
  249. return Py_None;
  250. } else {
  251. return nullptr;
  252. }
  253. }
  254. if (cmp < 0) {
  255. return nullptr;
  256. }
  257. } else {
  258. return nullptr;
  259. }
  260. }
  261. // Not found, raise ValueError.
  262. return PyErr_Format(PyExc_ValueError, "%s.remove() did not find value", wrap->_base._name);
  263. }
  264. /**
  265. * Implementation of property.pop([i=-1]) which returns and removes the
  266. * element at the indicated index in the sequence. If no index is provided,
  267. * it removes from the end of the list.
  268. */
  269. static PyObject *Dtool_MutableSequenceWrapper_pop(PyObject *self, PyObject *args) {
  270. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self;
  271. nassertr(wrap, nullptr);
  272. if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr ||
  273. wrap->_len_func == nullptr) {
  274. return Dtool_Raise_TypeError("property does not support pop()");
  275. }
  276. Py_ssize_t length = wrap->_len_func(wrap->_base._self);
  277. Py_ssize_t index;
  278. switch (PyTuple_GET_SIZE(args)) {
  279. case 0:
  280. index = length - 1;
  281. break;
  282. case 1:
  283. index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 0), PyExc_IndexError);
  284. if (index == -1 && _PyErr_OCCURRED()) {
  285. return nullptr;
  286. }
  287. if (index < 0) {
  288. index += length;
  289. }
  290. break;
  291. default:
  292. return Dtool_Raise_TypeError("pop([i=-1]) takes 0 or 1 arguments");
  293. }
  294. if (length <= 0) {
  295. return PyErr_Format(PyExc_IndexError, "%s.pop() from empty sequence", wrap->_base._name);
  296. }
  297. // Index error will be caught by getitem_func.
  298. PyObject *value = wrap->_getitem_func(wrap->_base._self, index);
  299. if (value != nullptr) {
  300. if (wrap->_setitem_func(wrap->_base._self, index, nullptr) != 0) {
  301. return nullptr;
  302. }
  303. return value;
  304. }
  305. return nullptr;
  306. }
  307. /**
  308. * Implementation of property.append(x) which is an alias for
  309. * property.insert(len(property), x).
  310. */
  311. static PyObject *Dtool_MutableSequenceWrapper_append(PyObject *self, PyObject *arg) {
  312. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self;
  313. nassertr(wrap, nullptr);
  314. if (wrap->_insert_func == nullptr) {
  315. return Dtool_Raise_TypeError("property does not support append()");
  316. }
  317. return wrap->_insert_func(wrap->_base._self, (size_t)-1, arg);
  318. }
  319. /**
  320. * Implementation of property.insert(i, x) which inserts the given item at the
  321. * given position.
  322. */
  323. static PyObject *Dtool_MutableSequenceWrapper_insert(PyObject *self, PyObject *args) {
  324. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self;
  325. nassertr(wrap, nullptr);
  326. if (wrap->_insert_func == nullptr) {
  327. return Dtool_Raise_TypeError("property does not support insert()");
  328. }
  329. if (PyTuple_GET_SIZE(args) != 2) {
  330. return Dtool_Raise_TypeError("insert() takes exactly 2 arguments");
  331. }
  332. Py_ssize_t index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 0), PyExc_IndexError);
  333. if (index == -1 && _PyErr_OCCURRED()) {
  334. return nullptr;
  335. }
  336. if (index < 0) {
  337. if (wrap->_len_func != nullptr) {
  338. index += wrap->_len_func(wrap->_base._self);
  339. } else {
  340. return PyErr_Format(PyExc_TypeError, "%s.insert() does not support negative indices", wrap->_base._name);
  341. }
  342. }
  343. return wrap->_insert_func(wrap->_base._self, (ssize_t)std::max(index, (Py_ssize_t)0), PyTuple_GET_ITEM(args, 1));
  344. }
  345. /**
  346. * Implementation of property.extend(seq) which is equivalent to:
  347. * @code
  348. * for x in seq:
  349. * property.append(seq)
  350. * @endcode
  351. */
  352. static PyObject *Dtool_MutableSequenceWrapper_extend(PyObject *self, PyObject *arg) {
  353. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self;
  354. nassertr(wrap, nullptr);
  355. if (wrap->_insert_func == nullptr) {
  356. return Dtool_Raise_TypeError("property does not support extend()");
  357. }
  358. PyObject *iter = PyObject_GetIter(arg);
  359. if (iter == nullptr) {
  360. return nullptr;
  361. }
  362. PyObject *next = PyIter_Next(iter);
  363. PyObject *retval = nullptr;
  364. while (next != nullptr) {
  365. retval = wrap->_insert_func(wrap->_base._self, (size_t)-1, next);
  366. Py_DECREF(next);
  367. if (retval == nullptr) {
  368. Py_DECREF(iter);
  369. return nullptr;
  370. }
  371. Py_DECREF(retval);
  372. next = PyIter_Next(iter);
  373. }
  374. Py_DECREF(iter);
  375. Py_INCREF(Py_None);
  376. return Py_None;
  377. }
  378. /**
  379. * Implementation of `x in mapping`.
  380. */
  381. static int Dtool_MappingWrapper_contains(PyObject *self, PyObject *key) {
  382. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  383. nassertr(wrap, -1);
  384. nassertr(wrap->_getitem_func, -1);
  385. PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
  386. if (value != nullptr) {
  387. Py_DECREF(value);
  388. return 1;
  389. } else if (_PyErr_OCCURRED() == PyExc_KeyError ||
  390. _PyErr_OCCURRED() == PyExc_TypeError) {
  391. PyErr_Restore(nullptr, nullptr, nullptr);
  392. return 0;
  393. } else {
  394. return -1;
  395. }
  396. }
  397. static PyObject *Dtool_MappingWrapper_getitem(PyObject *self, PyObject *key) {
  398. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  399. nassertr(wrap, nullptr);
  400. nassertr(wrap->_getitem_func, nullptr);
  401. return wrap->_getitem_func(wrap->_base._self, key);
  402. }
  403. /**
  404. * Implementation of iter(property) that returns an iterable over all the
  405. * keys.
  406. */
  407. static PyObject *Dtool_MappingWrapper_iter(PyObject *self) {
  408. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  409. nassertr(wrap, nullptr);
  410. if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) {
  411. return PyErr_Format(PyExc_TypeError, "%s is not iterable", wrap->_base._name);
  412. }
  413. Dtool_SequenceWrapper *keys = Dtool_NewSequenceWrapper(wrap->_base._self, wrap->_base._name);
  414. if (keys != nullptr) {
  415. keys->_len_func = wrap->_keys._len_func;
  416. keys->_getitem_func = wrap->_keys._getitem_func;
  417. return PySeqIter_New((PyObject *)keys);
  418. } else {
  419. return nullptr;
  420. }
  421. }
  422. /**
  423. * Implementation of property.get(key[,def=None]) which returns the value with
  424. * the given key in the mapping, or the given default value (which defaults to
  425. * None) if the key isn't found in the mapping.
  426. */
  427. static PyObject *Dtool_MappingWrapper_get(PyObject *self, PyObject *args) {
  428. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  429. nassertr(wrap, nullptr);
  430. nassertr(wrap->_getitem_func, nullptr);
  431. Py_ssize_t size = PyTuple_GET_SIZE(args);
  432. if (size != 1 && size != 2) {
  433. return PyErr_Format(PyExc_TypeError, "%s.get() takes 1 or 2 arguments", wrap->_base._name);
  434. }
  435. PyObject *defvalue = Py_None;
  436. if (size >= 2) {
  437. defvalue = PyTuple_GET_ITEM(args, 1);
  438. }
  439. PyObject *key = PyTuple_GET_ITEM(args, 0);
  440. PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
  441. if (value != nullptr) {
  442. return value;
  443. } else if (_PyErr_OCCURRED() == PyExc_KeyError) {
  444. PyErr_Restore(nullptr, nullptr, nullptr);
  445. Py_INCREF(defvalue);
  446. return defvalue;
  447. } else {
  448. return nullptr;
  449. }
  450. }
  451. /**
  452. * This is returned by mapping.keys().
  453. */
  454. static PyObject *Dtool_MappingWrapper_Keys_repr(PyObject *self) {
  455. Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
  456. nassertr(wrap, nullptr);
  457. PyObject *repr = PyObject_Repr(wrap->_self);
  458. PyObject *result;
  459. #if PY_MAJOR_VERSION >= 3
  460. result = PyUnicode_FromFormat("<%s.keys() of %s>", wrap->_name, PyUnicode_AsUTF8(repr));
  461. #else
  462. result = PyString_FromFormat("<%s.keys() of %s>", wrap->_name, PyString_AS_STRING(repr));
  463. #endif
  464. Py_DECREF(repr);
  465. return result;
  466. }
  467. /**
  468. * Implementation of property.keys(...) that returns a view of all the keys.
  469. */
  470. static PyObject *Dtool_MappingWrapper_keys(PyObject *self, PyObject *) {
  471. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  472. nassertr(wrap, nullptr);
  473. if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) {
  474. return Dtool_Raise_TypeError("property does not support keys()");
  475. }
  476. Dtool_MappingWrapper *keys = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper));
  477. if (keys == nullptr) {
  478. return PyErr_NoMemory();
  479. }
  480. static PySequenceMethods seq_methods = {
  481. Dtool_SequenceWrapper_length,
  482. nullptr, // sq_concat
  483. nullptr, // sq_repeat
  484. Dtool_SequenceWrapper_getitem,
  485. nullptr, // sq_slice
  486. nullptr, // sq_ass_item
  487. nullptr, // sq_ass_slice
  488. Dtool_SequenceWrapper_contains,
  489. nullptr, // sq_inplace_concat
  490. nullptr, // sq_inplace_repeat
  491. };
  492. static PyTypeObject wrapper_type = {
  493. PyVarObject_HEAD_INIT(nullptr, 0)
  494. "sequence wrapper",
  495. sizeof(Dtool_SequenceWrapper),
  496. 0, // tp_itemsize
  497. Dtool_WrapperBase_dealloc,
  498. 0, // tp_vectorcall_offset
  499. nullptr, // tp_getattr
  500. nullptr, // tp_setattr
  501. nullptr, // tp_compare
  502. Dtool_MappingWrapper_Keys_repr,
  503. nullptr, // tp_as_number
  504. &seq_methods,
  505. nullptr, // tp_as_mapping
  506. nullptr, // tp_hash
  507. nullptr, // tp_call
  508. nullptr, // tp_str
  509. PyObject_GenericGetAttr,
  510. PyObject_GenericSetAttr,
  511. nullptr, // tp_as_buffer
  512. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  513. nullptr, // tp_doc
  514. nullptr, // tp_traverse
  515. nullptr, // tp_clear
  516. nullptr, // tp_richcompare
  517. 0, // tp_weaklistoffset
  518. PySeqIter_New,
  519. nullptr, // tp_iternext
  520. nullptr, // tp_methods
  521. nullptr, // tp_members
  522. nullptr, // tp_getset
  523. nullptr, // tp_base
  524. nullptr, // tp_dict
  525. nullptr, // tp_descr_get
  526. nullptr, // tp_descr_set
  527. 0, // tp_dictoffset
  528. nullptr, // tp_init
  529. PyType_GenericAlloc,
  530. nullptr, // tp_new
  531. PyObject_Del,
  532. nullptr, // tp_is_gc
  533. nullptr, // tp_bases
  534. nullptr, // tp_mro
  535. nullptr, // tp_cache
  536. nullptr, // tp_subclasses
  537. nullptr, // tp_weaklist
  538. nullptr, // tp_del
  539. 0, // tp_version_tag,
  540. #if PY_VERSION_HEX >= 0x03040000
  541. nullptr, // tp_finalize
  542. #endif
  543. #if PY_VERSION_HEX >= 0x03080000
  544. nullptr, // tp_vectorcall
  545. #endif
  546. };
  547. static bool registered = false;
  548. if (!registered) {
  549. registered = true;
  550. if (PyType_Ready(&wrapper_type) < 0) {
  551. return nullptr;
  552. }
  553. // If the collections.abc module is loaded, register this as a subclass.
  554. _register_collection((PyTypeObject *)&wrapper_type, "MappingView");
  555. }
  556. (void)PyObject_INIT(keys, &wrapper_type);
  557. Py_XINCREF(wrap->_base._self);
  558. keys->_base._self = wrap->_base._self;
  559. keys->_base._name = wrap->_base._name;
  560. keys->_keys._len_func = wrap->_keys._len_func;
  561. keys->_keys._getitem_func = wrap->_keys._getitem_func;
  562. keys->_getitem_func = wrap->_getitem_func;
  563. keys->_setitem_func = nullptr;
  564. return (PyObject *)keys;
  565. }
  566. /**
  567. * This is returned by mapping.values().
  568. */
  569. static PyObject *Dtool_MappingWrapper_Values_repr(PyObject *self) {
  570. Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
  571. nassertr(wrap, nullptr);
  572. PyObject *repr = PyObject_Repr(wrap->_self);
  573. PyObject *result;
  574. #if PY_MAJOR_VERSION >= 3
  575. result = PyUnicode_FromFormat("<%s.values() of %s>", wrap->_name, PyUnicode_AsUTF8(repr));
  576. #else
  577. result = PyString_FromFormat("<%s.values() of %s>", wrap->_name, PyString_AS_STRING(repr));
  578. #endif
  579. Py_DECREF(repr);
  580. return result;
  581. }
  582. static PyObject *Dtool_MappingWrapper_Values_getitem(PyObject *self, Py_ssize_t index) {
  583. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  584. nassertr(wrap, nullptr);
  585. nassertr(wrap->_keys._getitem_func, nullptr);
  586. PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, index);
  587. if (key != nullptr) {
  588. PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
  589. Py_DECREF(key);
  590. return value;
  591. }
  592. return nullptr;
  593. }
  594. /**
  595. * Implementation of property.values(...) that returns a view of the values.
  596. */
  597. static PyObject *Dtool_MappingWrapper_values(PyObject *self, PyObject *) {
  598. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  599. nassertr(wrap, nullptr);
  600. nassertr(wrap->_getitem_func, nullptr);
  601. if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) {
  602. return Dtool_Raise_TypeError("property does not support values()");
  603. }
  604. Dtool_MappingWrapper *values = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper));
  605. if (values == nullptr) {
  606. return PyErr_NoMemory();
  607. }
  608. static PySequenceMethods seq_methods = {
  609. Dtool_SequenceWrapper_length,
  610. nullptr, // sq_concat
  611. nullptr, // sq_repeat
  612. Dtool_MappingWrapper_Values_getitem,
  613. nullptr, // sq_slice
  614. nullptr, // sq_ass_item
  615. nullptr, // sq_ass_slice
  616. Dtool_MappingWrapper_contains,
  617. nullptr, // sq_inplace_concat
  618. nullptr, // sq_inplace_repeat
  619. };
  620. static PyTypeObject wrapper_type = {
  621. PyVarObject_HEAD_INIT(nullptr, 0)
  622. "sequence wrapper",
  623. sizeof(Dtool_MappingWrapper),
  624. 0, // tp_itemsize
  625. Dtool_WrapperBase_dealloc,
  626. 0, // tp_vectorcall_offset
  627. nullptr, // tp_getattr
  628. nullptr, // tp_setattr
  629. nullptr, // tp_compare
  630. Dtool_MappingWrapper_Values_repr,
  631. nullptr, // tp_as_number
  632. &seq_methods,
  633. nullptr, // tp_as_mapping
  634. nullptr, // tp_hash
  635. nullptr, // tp_call
  636. nullptr, // tp_str
  637. PyObject_GenericGetAttr,
  638. PyObject_GenericSetAttr,
  639. nullptr, // tp_as_buffer
  640. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  641. nullptr, // tp_doc
  642. nullptr, // tp_traverse
  643. nullptr, // tp_clear
  644. nullptr, // tp_richcompare
  645. 0, // tp_weaklistoffset
  646. PySeqIter_New,
  647. nullptr, // tp_iternext
  648. nullptr, // tp_methods
  649. nullptr, // tp_members
  650. nullptr, // tp_getset
  651. nullptr, // tp_base
  652. nullptr, // tp_dict
  653. nullptr, // tp_descr_get
  654. nullptr, // tp_descr_set
  655. 0, // tp_dictoffset
  656. nullptr, // tp_init
  657. PyType_GenericAlloc,
  658. nullptr, // tp_new
  659. PyObject_Del,
  660. nullptr, // tp_is_gc
  661. nullptr, // tp_bases
  662. nullptr, // tp_mro
  663. nullptr, // tp_cache
  664. nullptr, // tp_subclasses
  665. nullptr, // tp_weaklist
  666. nullptr, // tp_del
  667. 0, // tp_version_tag,
  668. #if PY_VERSION_HEX >= 0x03040000
  669. nullptr, // tp_finalize
  670. #endif
  671. #if PY_VERSION_HEX >= 0x03080000
  672. nullptr, // tp_vectorcall
  673. #endif
  674. };
  675. static bool registered = false;
  676. if (!registered) {
  677. registered = true;
  678. if (PyType_Ready(&wrapper_type) < 0) {
  679. return nullptr;
  680. }
  681. // If the collections.abc module is loaded, register this as a subclass.
  682. _register_collection((PyTypeObject *)&wrapper_type, "ValuesView");
  683. }
  684. (void)PyObject_INIT(values, &wrapper_type);
  685. Py_XINCREF(wrap->_base._self);
  686. values->_base._self = wrap->_base._self;
  687. values->_base._name = wrap->_base._name;
  688. values->_keys._len_func = wrap->_keys._len_func;
  689. values->_keys._getitem_func = wrap->_keys._getitem_func;
  690. values->_getitem_func = wrap->_getitem_func;
  691. values->_setitem_func = nullptr;
  692. return (PyObject *)values;
  693. }
  694. /**
  695. * This is returned by mapping.items().
  696. */
  697. static PyObject *Dtool_MappingWrapper_Items_repr(PyObject *self) {
  698. Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self;
  699. nassertr(wrap, nullptr);
  700. PyObject *repr = PyObject_Repr(wrap->_self);
  701. PyObject *result;
  702. #if PY_MAJOR_VERSION >= 3
  703. result = PyUnicode_FromFormat("<%s.items() of %s>", wrap->_name, PyUnicode_AsUTF8(repr));
  704. #else
  705. result = PyString_FromFormat("<%s.items() of %s>", wrap->_name, PyString_AS_STRING(repr));
  706. #endif
  707. Py_DECREF(repr);
  708. return result;
  709. }
  710. static PyObject *Dtool_MappingWrapper_Items_getitem(PyObject *self, Py_ssize_t index) {
  711. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  712. nassertr(wrap, nullptr);
  713. nassertr(wrap->_keys._getitem_func, nullptr);
  714. PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, index);
  715. if (key != nullptr) {
  716. PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
  717. if (value != nullptr) {
  718. // PyTuple_SET_ITEM steals the reference.
  719. PyObject *item = PyTuple_New(2);
  720. PyTuple_SET_ITEM(item, 0, key);
  721. PyTuple_SET_ITEM(item, 1, value);
  722. return item;
  723. } else {
  724. Py_DECREF(key);
  725. }
  726. }
  727. return nullptr;
  728. }
  729. /**
  730. * Implementation of property.items(...) that returns an iterable yielding a
  731. * `(key, value)` tuple for every item.
  732. */
  733. static PyObject *Dtool_MappingWrapper_items(PyObject *self, PyObject *) {
  734. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  735. nassertr(wrap, nullptr);
  736. nassertr(wrap->_getitem_func, nullptr);
  737. if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) {
  738. return Dtool_Raise_TypeError("property does not support items()");
  739. }
  740. Dtool_MappingWrapper *items = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper));
  741. if (items == nullptr) {
  742. return PyErr_NoMemory();
  743. }
  744. static PySequenceMethods seq_methods = {
  745. Dtool_SequenceWrapper_length,
  746. nullptr, // sq_concat
  747. nullptr, // sq_repeat
  748. Dtool_MappingWrapper_Items_getitem,
  749. nullptr, // sq_slice
  750. nullptr, // sq_ass_item
  751. nullptr, // sq_ass_slice
  752. Dtool_MappingWrapper_contains,
  753. nullptr, // sq_inplace_concat
  754. nullptr, // sq_inplace_repeat
  755. };
  756. static PyTypeObject wrapper_type = {
  757. PyVarObject_HEAD_INIT(nullptr, 0)
  758. "sequence wrapper",
  759. sizeof(Dtool_MappingWrapper),
  760. 0, // tp_itemsize
  761. Dtool_WrapperBase_dealloc,
  762. 0, // tp_vectorcall_offset
  763. nullptr, // tp_getattr
  764. nullptr, // tp_setattr
  765. nullptr, // tp_compare
  766. Dtool_MappingWrapper_Items_repr,
  767. nullptr, // tp_as_number
  768. &seq_methods,
  769. nullptr, // tp_as_mapping
  770. nullptr, // tp_hash
  771. nullptr, // tp_call
  772. nullptr, // tp_str
  773. PyObject_GenericGetAttr,
  774. PyObject_GenericSetAttr,
  775. nullptr, // tp_as_buffer
  776. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  777. nullptr, // tp_doc
  778. nullptr, // tp_traverse
  779. nullptr, // tp_clear
  780. nullptr, // tp_richcompare
  781. 0, // tp_weaklistoffset
  782. PySeqIter_New,
  783. nullptr, // tp_iternext
  784. nullptr, // tp_methods
  785. nullptr, // tp_members
  786. nullptr, // tp_getset
  787. nullptr, // tp_base
  788. nullptr, // tp_dict
  789. nullptr, // tp_descr_get
  790. nullptr, // tp_descr_set
  791. 0, // tp_dictoffset
  792. nullptr, // tp_init
  793. PyType_GenericAlloc,
  794. nullptr, // tp_new
  795. PyObject_Del,
  796. nullptr, // tp_is_gc
  797. nullptr, // tp_bases
  798. nullptr, // tp_mro
  799. nullptr, // tp_cache
  800. nullptr, // tp_subclasses
  801. nullptr, // tp_weaklist
  802. nullptr, // tp_del
  803. 0, // tp_version_tag,
  804. #if PY_VERSION_HEX >= 0x03040000
  805. nullptr, // tp_finalize
  806. #endif
  807. #if PY_VERSION_HEX >= 0x03080000
  808. nullptr, // tp_vectorcall
  809. #endif
  810. };
  811. static bool registered = false;
  812. if (!registered) {
  813. registered = true;
  814. if (PyType_Ready(&wrapper_type) < 0) {
  815. return nullptr;
  816. }
  817. // If the collections.abc module is loaded, register this as a subclass.
  818. _register_collection((PyTypeObject *)&wrapper_type, "MappingView");
  819. }
  820. (void)PyObject_INIT(items, &wrapper_type);
  821. Py_XINCREF(wrap->_base._self);
  822. items->_base._self = wrap->_base._self;
  823. items->_base._name = wrap->_base._name;
  824. items->_keys._len_func = wrap->_keys._len_func;
  825. items->_keys._getitem_func = wrap->_keys._getitem_func;
  826. items->_getitem_func = wrap->_getitem_func;
  827. items->_setitem_func = nullptr;
  828. return (PyObject *)items;
  829. }
  830. /**
  831. * Implementation of `property[key] = value`
  832. */
  833. static int Dtool_MutableMappingWrapper_setitem(PyObject *self, PyObject *key, PyObject *value) {
  834. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  835. nassertr(wrap->_setitem_func != nullptr, -1);
  836. return wrap->_setitem_func(wrap->_base._self, key, value);
  837. }
  838. /**
  839. * Implementation of property.pop(key[,def=None]) which is the same as get()
  840. * except that it also removes the element from the mapping.
  841. */
  842. static PyObject *Dtool_MutableMappingWrapper_pop(PyObject *self, PyObject *args) {
  843. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  844. nassertr(wrap, nullptr);
  845. if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) {
  846. return Dtool_Raise_TypeError("property does not support pop()");
  847. }
  848. Py_ssize_t size = PyTuple_GET_SIZE(args);
  849. if (size != 1 && size != 2) {
  850. return PyErr_Format(PyExc_TypeError, "%s.pop() takes 1 or 2 arguments", wrap->_base._name);
  851. }
  852. PyObject *defvalue = Py_None;
  853. if (size >= 2) {
  854. defvalue = PyTuple_GET_ITEM(args, 1);
  855. }
  856. PyObject *key = PyTuple_GET_ITEM(args, 0);
  857. PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
  858. if (value != nullptr) {
  859. // OK, now set unset this value.
  860. if (wrap->_setitem_func(wrap->_base._self, key, nullptr) == 0) {
  861. return value;
  862. } else {
  863. Py_DECREF(value);
  864. return nullptr;
  865. }
  866. } else if (_PyErr_OCCURRED() == PyExc_KeyError) {
  867. PyErr_Restore(nullptr, nullptr, nullptr);
  868. Py_INCREF(defvalue);
  869. return defvalue;
  870. } else {
  871. return nullptr;
  872. }
  873. }
  874. /**
  875. * Implementation of property.popitem() which returns and removes an arbitrary
  876. * (key, value) pair from the mapping. Useful for destructive iteration.
  877. */
  878. static PyObject *Dtool_MutableMappingWrapper_popitem(PyObject *self, PyObject *) {
  879. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  880. nassertr(wrap, nullptr);
  881. if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr ||
  882. wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) {
  883. return Dtool_Raise_TypeError("property does not support popitem()");
  884. }
  885. Py_ssize_t length = wrap->_keys._len_func(wrap->_base._self);
  886. if (length < 1) {
  887. return PyErr_Format(PyExc_KeyError, "%s is empty", wrap->_base._name);
  888. }
  889. PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, length - 1);
  890. if (key != nullptr) {
  891. PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
  892. if (value != nullptr) {
  893. // OK, now set unset this value.
  894. if (wrap->_setitem_func(wrap->_base._self, key, nullptr) == 0) {
  895. PyObject *item = PyTuple_New(2);
  896. PyTuple_SET_ITEM(item, 0, key);
  897. PyTuple_SET_ITEM(item, 1, value);
  898. return item;
  899. }
  900. Py_DECREF(value);
  901. }
  902. }
  903. return nullptr;
  904. }
  905. /*
  906. * Implementation of property.clear() which removes all elements in the
  907. * mapping.
  908. */
  909. static PyObject *Dtool_MutableMappingWrapper_clear(PyObject *self, PyObject *) {
  910. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  911. nassertr(wrap, nullptr);
  912. Py_ssize_t index = 0;
  913. if (wrap->_keys._len_func != nullptr && wrap->_keys._getitem_func != nullptr &&
  914. wrap->_setitem_func != nullptr) {
  915. index = wrap->_keys._len_func(wrap->_base._self);
  916. } else {
  917. return Dtool_Raise_TypeError("property does not support clear()");
  918. }
  919. // Iterate through the items, invoking the delete function for each. We do
  920. // this in reverse order, which may be more efficient.
  921. while (index > 0) {
  922. --index;
  923. PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, index);
  924. if (key != nullptr) {
  925. int result = wrap->_setitem_func(wrap->_base._self, key, nullptr);
  926. Py_DECREF(key);
  927. if (result != 0) {
  928. return nullptr;
  929. }
  930. }
  931. }
  932. Py_INCREF(Py_None);
  933. return Py_None;
  934. }
  935. /**
  936. * Implementation of property.setdefault(key[,def=None]) which is the same as
  937. * get() except that it also writes the default value back to the mapping if
  938. * the key was not found is missing.
  939. */
  940. static PyObject *Dtool_MutableMappingWrapper_setdefault(PyObject *self, PyObject *args) {
  941. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  942. nassertr(wrap, nullptr);
  943. if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) {
  944. return Dtool_Raise_TypeError("property does not support setdefault()");
  945. }
  946. Py_ssize_t size = PyTuple_GET_SIZE(args);
  947. if (size != 1 && size != 2) {
  948. return PyErr_Format(PyExc_TypeError, "%s.setdefault() takes 1 or 2 arguments", wrap->_base._name);
  949. }
  950. PyObject *defvalue = Py_None;
  951. if (size >= 2) {
  952. defvalue = PyTuple_GET_ITEM(args, 1);
  953. }
  954. PyObject *key = PyTuple_GET_ITEM(args, 0);
  955. PyObject *value = wrap->_getitem_func(wrap->_base._self, key);
  956. if (value != nullptr) {
  957. return value;
  958. } else if (_PyErr_OCCURRED() == PyExc_KeyError) {
  959. PyErr_Restore(nullptr, nullptr, nullptr);
  960. if (wrap->_setitem_func(wrap->_base._self, key, defvalue) == 0) {
  961. Py_INCREF(defvalue);
  962. return defvalue;
  963. }
  964. }
  965. return nullptr;
  966. }
  967. /**
  968. * Implementation of property.update(...) which sets multiple values in one
  969. * go. It accepts either a single dictionary or keyword arguments, not both.
  970. */
  971. static PyObject *Dtool_MutableMappingWrapper_update(PyObject *self, PyObject *args, PyObject *kwargs) {
  972. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self;
  973. nassertr(wrap, nullptr);
  974. if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) {
  975. return Dtool_Raise_TypeError("property does not support update()");
  976. }
  977. // We accept either a dict argument or keyword arguments, but not both.
  978. PyObject *dict;
  979. switch (PyTuple_GET_SIZE(args)) {
  980. case 0:
  981. if (kwargs == nullptr) {
  982. // This is legal.
  983. Py_INCREF(Py_None);
  984. return Py_None;
  985. }
  986. dict = kwargs;
  987. break;
  988. case 1:
  989. if (PyDict_Check(PyTuple_GET_ITEM(args, 0)) && (kwargs == nullptr || Py_SIZE(kwargs) == 0)) {
  990. dict = PyTuple_GET_ITEM(args, 0);
  991. break;
  992. }
  993. // Fall through
  994. default:
  995. return PyErr_Format(PyExc_TypeError, "%s.update() takes either a dict argument or keyword arguments", wrap->_base._name);
  996. }
  997. PyObject *key, *value;
  998. Py_ssize_t pos = 0;
  999. while (PyDict_Next(dict, &pos, &key, &value)) {
  1000. if (wrap->_setitem_func(wrap->_base._self, key, value) != 0) {
  1001. return nullptr;
  1002. }
  1003. }
  1004. Py_INCREF(Py_None);
  1005. return Py_None;
  1006. }
  1007. /**
  1008. * This variant defines only a generator interface.
  1009. */
  1010. static PyObject *Dtool_GeneratorWrapper_iternext(PyObject *self) {
  1011. Dtool_GeneratorWrapper *wrap = (Dtool_GeneratorWrapper *)self;
  1012. nassertr(wrap, nullptr);
  1013. nassertr(wrap->_iternext_func, nullptr);
  1014. return wrap->_iternext_func(wrap->_base._self);
  1015. }
  1016. /**
  1017. * This is a variant of the Python getset mechanism that permits static
  1018. * properties.
  1019. */
  1020. static void
  1021. Dtool_StaticProperty_dealloc(PyDescrObject *descr) {
  1022. #if PY_VERSION_HEX >= 0x03080000
  1023. PyObject_GC_UnTrack(descr);
  1024. #else
  1025. _PyObject_GC_UNTRACK(descr);
  1026. #endif
  1027. Py_XDECREF(descr->d_type);
  1028. Py_XDECREF(descr->d_name);
  1029. //#if PY_MAJOR_VERSION >= 3
  1030. // Py_XDECREF(descr->d_qualname);
  1031. //#endif
  1032. PyObject_GC_Del(descr);
  1033. }
  1034. static PyObject *
  1035. Dtool_StaticProperty_repr(PyDescrObject *descr, const char *format) {
  1036. #if PY_MAJOR_VERSION >= 3
  1037. return PyUnicode_FromFormat("<attribute '%s' of '%s'>",
  1038. PyUnicode_AsUTF8(descr->d_name),
  1039. descr->d_type->tp_name);
  1040. #else
  1041. return PyString_FromFormat("<attribute '%s' of '%s'>",
  1042. PyString_AS_STRING(descr->d_name),
  1043. descr->d_type->tp_name);
  1044. #endif
  1045. }
  1046. static int
  1047. Dtool_StaticProperty_traverse(PyObject *self, visitproc visit, void *arg) {
  1048. PyDescrObject *descr = (PyDescrObject *)self;
  1049. Py_VISIT(descr->d_type);
  1050. return 0;
  1051. }
  1052. static PyObject *
  1053. Dtool_StaticProperty_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) {
  1054. if (descr->d_getset->get != nullptr) {
  1055. return descr->d_getset->get(obj, descr->d_getset->closure);
  1056. } else {
  1057. return PyErr_Format(PyExc_AttributeError,
  1058. "attribute '%s' of type '%.100s' is not readable",
  1059. #if PY_MAJOR_VERSION >= 3
  1060. PyUnicode_AsUTF8(((PyDescrObject *)descr)->d_name),
  1061. #else
  1062. PyString_AS_STRING(((PyDescrObject *)descr)->d_name),
  1063. #endif
  1064. ((PyDescrObject *)descr)->d_type->tp_name);
  1065. }
  1066. }
  1067. static int
  1068. Dtool_StaticProperty_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) {
  1069. if (descr->d_getset->set != nullptr) {
  1070. return descr->d_getset->set(obj, value, descr->d_getset->closure);
  1071. } else {
  1072. PyErr_Format(PyExc_AttributeError,
  1073. "attribute '%s' of type '%.100s' is not writable",
  1074. #if PY_MAJOR_VERSION >= 3
  1075. PyUnicode_AsUTF8(((PyDescrObject *)descr)->d_name),
  1076. #else
  1077. PyString_AS_STRING(((PyDescrObject *)descr)->d_name),
  1078. #endif
  1079. ((PyDescrObject *)descr)->d_type->tp_name);
  1080. return -1;
  1081. }
  1082. }
  1083. /**
  1084. * This wraps around a property that exposes a sequence interface.
  1085. */
  1086. Dtool_SequenceWrapper *Dtool_NewSequenceWrapper(PyObject *self, const char *name) {
  1087. Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)PyObject_MALLOC(sizeof(Dtool_SequenceWrapper));
  1088. if (wrap == nullptr) {
  1089. return (Dtool_SequenceWrapper *)PyErr_NoMemory();
  1090. }
  1091. static PySequenceMethods seq_methods = {
  1092. Dtool_SequenceWrapper_length,
  1093. nullptr, // sq_concat
  1094. nullptr, // sq_repeat
  1095. Dtool_SequenceWrapper_getitem,
  1096. nullptr, // sq_slice
  1097. nullptr, // sq_ass_item
  1098. nullptr, // sq_ass_slice
  1099. Dtool_SequenceWrapper_contains,
  1100. nullptr, // sq_inplace_concat
  1101. nullptr, // sq_inplace_repeat
  1102. };
  1103. static PyMethodDef methods[] = {
  1104. {"index", &Dtool_SequenceWrapper_index, METH_O, nullptr},
  1105. {"count", &Dtool_SequenceWrapper_count, METH_O, nullptr},
  1106. {nullptr, nullptr, 0, nullptr}
  1107. };
  1108. static PyTypeObject wrapper_type = {
  1109. PyVarObject_HEAD_INIT(nullptr, 0)
  1110. "sequence wrapper",
  1111. sizeof(Dtool_SequenceWrapper),
  1112. 0, // tp_itemsize
  1113. Dtool_WrapperBase_dealloc,
  1114. 0, // tp_vectorcall_offset
  1115. nullptr, // tp_getattr
  1116. nullptr, // tp_setattr
  1117. nullptr, // tp_compare
  1118. Dtool_SequenceWrapper_repr,
  1119. nullptr, // tp_as_number
  1120. &seq_methods,
  1121. nullptr, // tp_as_mapping
  1122. nullptr, // tp_hash
  1123. nullptr, // tp_call
  1124. nullptr, // tp_str
  1125. PyObject_GenericGetAttr,
  1126. PyObject_GenericSetAttr,
  1127. nullptr, // tp_as_buffer
  1128. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  1129. nullptr, // tp_doc
  1130. nullptr, // tp_traverse
  1131. nullptr, // tp_clear
  1132. nullptr, // tp_richcompare
  1133. 0, // tp_weaklistoffset
  1134. PySeqIter_New,
  1135. nullptr, // tp_iternext
  1136. methods,
  1137. nullptr, // tp_members
  1138. nullptr, // tp_getset
  1139. nullptr, // tp_base
  1140. nullptr, // tp_dict
  1141. nullptr, // tp_descr_get
  1142. nullptr, // tp_descr_set
  1143. 0, // tp_dictoffset
  1144. nullptr, // tp_init
  1145. PyType_GenericAlloc,
  1146. nullptr, // tp_new
  1147. PyObject_Del,
  1148. nullptr, // tp_is_gc
  1149. nullptr, // tp_bases
  1150. nullptr, // tp_mro
  1151. nullptr, // tp_cache
  1152. nullptr, // tp_subclasses
  1153. nullptr, // tp_weaklist
  1154. nullptr, // tp_del
  1155. 0, // tp_version_tag,
  1156. #if PY_VERSION_HEX >= 0x03040000
  1157. nullptr, // tp_finalize
  1158. #endif
  1159. #if PY_VERSION_HEX >= 0x03080000
  1160. nullptr, // tp_vectorcall
  1161. #endif
  1162. };
  1163. static bool registered = false;
  1164. if (!registered) {
  1165. registered = true;
  1166. if (PyType_Ready(&wrapper_type) < 0) {
  1167. return nullptr;
  1168. }
  1169. // If the collections.abc module is loaded, register this as a subclass.
  1170. _register_collection((PyTypeObject *)&wrapper_type, "Sequence");
  1171. }
  1172. (void)PyObject_INIT(wrap, &wrapper_type);
  1173. Py_XINCREF(self);
  1174. wrap->_base._self = self;
  1175. wrap->_base._name = name;
  1176. wrap->_len_func = nullptr;
  1177. wrap->_getitem_func = nullptr;
  1178. return wrap;
  1179. }
  1180. /**
  1181. * This wraps around a property that exposes a mutable sequence interface.
  1182. */
  1183. Dtool_MutableSequenceWrapper *Dtool_NewMutableSequenceWrapper(PyObject *self, const char *name) {
  1184. Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)PyObject_MALLOC(sizeof(Dtool_MutableSequenceWrapper));
  1185. if (wrap == nullptr) {
  1186. return (Dtool_MutableSequenceWrapper *)PyErr_NoMemory();
  1187. }
  1188. static PySequenceMethods seq_methods = {
  1189. Dtool_SequenceWrapper_length,
  1190. nullptr, // sq_concat
  1191. nullptr, // sq_repeat
  1192. Dtool_SequenceWrapper_getitem,
  1193. nullptr, // sq_slice
  1194. Dtool_MutableSequenceWrapper_setitem,
  1195. nullptr, // sq_ass_slice
  1196. Dtool_SequenceWrapper_contains,
  1197. Dtool_MutableSequenceWrapper_extend,
  1198. nullptr, // sq_inplace_repeat
  1199. };
  1200. static PyMethodDef methods[] = {
  1201. {"index", &Dtool_SequenceWrapper_index, METH_O, nullptr},
  1202. {"count", &Dtool_SequenceWrapper_count, METH_O, nullptr},
  1203. {"clear", &Dtool_MutableSequenceWrapper_clear, METH_NOARGS, nullptr},
  1204. {"pop", &Dtool_MutableSequenceWrapper_pop, METH_VARARGS, nullptr},
  1205. {"remove", &Dtool_MutableSequenceWrapper_remove, METH_O, nullptr},
  1206. {"append", &Dtool_MutableSequenceWrapper_append, METH_O, nullptr},
  1207. {"insert", &Dtool_MutableSequenceWrapper_insert, METH_VARARGS, nullptr},
  1208. {"extend", &Dtool_MutableSequenceWrapper_extend, METH_O, nullptr},
  1209. {nullptr, nullptr, 0, nullptr}
  1210. };
  1211. static PyTypeObject wrapper_type = {
  1212. PyVarObject_HEAD_INIT(nullptr, 0)
  1213. "sequence wrapper",
  1214. sizeof(Dtool_MutableSequenceWrapper),
  1215. 0, // tp_itemsize
  1216. Dtool_WrapperBase_dealloc,
  1217. 0, // tp_vectorcall_offset
  1218. nullptr, // tp_getattr
  1219. nullptr, // tp_setattr
  1220. nullptr, // tp_compare
  1221. Dtool_SequenceWrapper_repr,
  1222. nullptr, // tp_as_number
  1223. &seq_methods,
  1224. nullptr, // tp_as_mapping
  1225. nullptr, // tp_hash
  1226. nullptr, // tp_call
  1227. nullptr, // tp_str
  1228. PyObject_GenericGetAttr,
  1229. PyObject_GenericSetAttr,
  1230. nullptr, // tp_as_buffer
  1231. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  1232. nullptr, // tp_doc
  1233. nullptr, // tp_traverse
  1234. nullptr, // tp_clear
  1235. nullptr, // tp_richcompare
  1236. 0, // tp_weaklistoffset
  1237. PySeqIter_New,
  1238. nullptr, // tp_iternext
  1239. methods,
  1240. nullptr, // tp_members
  1241. nullptr, // tp_getset
  1242. nullptr, // tp_base
  1243. nullptr, // tp_dict
  1244. nullptr, // tp_descr_get
  1245. nullptr, // tp_descr_set
  1246. 0, // tp_dictoffset
  1247. nullptr, // tp_init
  1248. PyType_GenericAlloc,
  1249. nullptr, // tp_new
  1250. PyObject_Del,
  1251. nullptr, // tp_is_gc
  1252. nullptr, // tp_bases
  1253. nullptr, // tp_mro
  1254. nullptr, // tp_cache
  1255. nullptr, // tp_subclasses
  1256. nullptr, // tp_weaklist
  1257. nullptr, // tp_del
  1258. 0, // tp_version_tag,
  1259. #if PY_VERSION_HEX >= 0x03040000
  1260. nullptr, // tp_finalize
  1261. #endif
  1262. #if PY_VERSION_HEX >= 0x03080000
  1263. nullptr, // tp_vectorcall
  1264. #endif
  1265. };
  1266. static bool registered = false;
  1267. if (!registered) {
  1268. registered = true;
  1269. if (PyType_Ready(&wrapper_type) < 0) {
  1270. return nullptr;
  1271. }
  1272. // If the collections.abc module is loaded, register this as a subclass.
  1273. _register_collection((PyTypeObject *)&wrapper_type, "MutableSequence");
  1274. }
  1275. (void)PyObject_INIT(wrap, &wrapper_type);
  1276. Py_XINCREF(self);
  1277. wrap->_base._self = self;
  1278. wrap->_base._name = name;
  1279. wrap->_len_func = nullptr;
  1280. wrap->_getitem_func = nullptr;
  1281. wrap->_setitem_func = nullptr;
  1282. wrap->_insert_func = nullptr;
  1283. return wrap;
  1284. }
  1285. /**
  1286. * This wraps around a mapping interface, with getitem function.
  1287. */
  1288. Dtool_MappingWrapper *Dtool_NewMappingWrapper(PyObject *self, const char *name) {
  1289. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper));
  1290. if (wrap == nullptr) {
  1291. return (Dtool_MappingWrapper *)PyErr_NoMemory();
  1292. }
  1293. static PySequenceMethods seq_methods = {
  1294. Dtool_SequenceWrapper_length,
  1295. nullptr, // sq_concat
  1296. nullptr, // sq_repeat
  1297. nullptr, // sq_item
  1298. nullptr, // sq_slice
  1299. nullptr, // sq_ass_item
  1300. nullptr, // sq_ass_slice
  1301. Dtool_MappingWrapper_contains,
  1302. nullptr, // sq_inplace_concat
  1303. nullptr, // sq_inplace_repeat
  1304. };
  1305. static PyMappingMethods map_methods = {
  1306. Dtool_SequenceWrapper_length,
  1307. Dtool_MappingWrapper_getitem,
  1308. nullptr, // mp_ass_subscript
  1309. };
  1310. static PyMethodDef methods[] = {
  1311. {"get", &Dtool_MappingWrapper_get, METH_VARARGS, nullptr},
  1312. {"keys", &Dtool_MappingWrapper_keys, METH_NOARGS, nullptr},
  1313. {"values", &Dtool_MappingWrapper_values, METH_NOARGS, nullptr},
  1314. {"items", &Dtool_MappingWrapper_items, METH_NOARGS, nullptr},
  1315. {nullptr, nullptr, 0, nullptr}
  1316. };
  1317. static PyTypeObject wrapper_type = {
  1318. PyVarObject_HEAD_INIT(nullptr, 0)
  1319. "mapping wrapper",
  1320. sizeof(Dtool_MappingWrapper),
  1321. 0, // tp_itemsize
  1322. Dtool_WrapperBase_dealloc,
  1323. 0, // tp_vectorcall_offset
  1324. nullptr, // tp_getattr
  1325. nullptr, // tp_setattr
  1326. nullptr, // tp_compare
  1327. Dtool_WrapperBase_repr,
  1328. nullptr, // tp_as_number
  1329. &seq_methods,
  1330. &map_methods,
  1331. nullptr, // tp_hash
  1332. nullptr, // tp_call
  1333. nullptr, // tp_str
  1334. PyObject_GenericGetAttr,
  1335. PyObject_GenericSetAttr,
  1336. nullptr, // tp_as_buffer
  1337. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  1338. nullptr, // tp_doc
  1339. nullptr, // tp_traverse
  1340. nullptr, // tp_clear
  1341. nullptr, // tp_richcompare
  1342. 0, // tp_weaklistoffset
  1343. Dtool_MappingWrapper_iter,
  1344. nullptr, // tp_iternext
  1345. methods,
  1346. nullptr, // tp_members
  1347. nullptr, // tp_getset
  1348. nullptr, // tp_base
  1349. nullptr, // tp_dict
  1350. nullptr, // tp_descr_get
  1351. nullptr, // tp_descr_set
  1352. 0, // tp_dictoffset
  1353. nullptr, // tp_init
  1354. PyType_GenericAlloc,
  1355. nullptr, // tp_new
  1356. PyObject_Del,
  1357. nullptr, // tp_is_gc
  1358. nullptr, // tp_bases
  1359. nullptr, // tp_mro
  1360. nullptr, // tp_cache
  1361. nullptr, // tp_subclasses
  1362. nullptr, // tp_weaklist
  1363. nullptr, // tp_del
  1364. 0, // tp_version_tag,
  1365. #if PY_VERSION_HEX >= 0x03040000
  1366. nullptr, // tp_finalize
  1367. #endif
  1368. #if PY_VERSION_HEX >= 0x03080000
  1369. nullptr, // tp_vectorcall
  1370. #endif
  1371. };
  1372. static bool registered = false;
  1373. if (!registered) {
  1374. registered = true;
  1375. if (PyType_Ready(&wrapper_type) < 0) {
  1376. return nullptr;
  1377. }
  1378. // If the collections.abc module is loaded, register this as a subclass.
  1379. _register_collection((PyTypeObject *)&wrapper_type, "Mapping");
  1380. }
  1381. (void)PyObject_INIT(wrap, &wrapper_type);
  1382. Py_XINCREF(self);
  1383. wrap->_base._self = self;
  1384. wrap->_base._name = name;
  1385. wrap->_keys._len_func = nullptr;
  1386. wrap->_keys._getitem_func = nullptr;
  1387. wrap->_getitem_func = nullptr;
  1388. wrap->_setitem_func = nullptr;
  1389. return wrap;
  1390. }
  1391. /**
  1392. * This wraps around a mapping interface, with getitem/setitem functions.
  1393. */
  1394. Dtool_MappingWrapper *Dtool_NewMutableMappingWrapper(PyObject *self, const char *name) {
  1395. Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper));
  1396. if (wrap == nullptr) {
  1397. return (Dtool_MappingWrapper *)PyErr_NoMemory();
  1398. }
  1399. static PySequenceMethods seq_methods = {
  1400. Dtool_SequenceWrapper_length,
  1401. nullptr, // sq_concat
  1402. nullptr, // sq_repeat
  1403. nullptr, // sq_item
  1404. nullptr, // sq_slice
  1405. nullptr, // sq_ass_item
  1406. nullptr, // sq_ass_slice
  1407. Dtool_MappingWrapper_contains,
  1408. nullptr, // sq_inplace_concat
  1409. nullptr, // sq_inplace_repeat
  1410. };
  1411. static PyMappingMethods map_methods = {
  1412. Dtool_SequenceWrapper_length,
  1413. Dtool_MappingWrapper_getitem,
  1414. Dtool_MutableMappingWrapper_setitem,
  1415. };
  1416. static PyMethodDef methods[] = {
  1417. {"get", &Dtool_MappingWrapper_get, METH_VARARGS, nullptr},
  1418. {"pop", &Dtool_MutableMappingWrapper_pop, METH_VARARGS, nullptr},
  1419. {"popitem", &Dtool_MutableMappingWrapper_popitem, METH_NOARGS, nullptr},
  1420. {"clear", &Dtool_MutableMappingWrapper_clear, METH_VARARGS, nullptr},
  1421. {"setdefault", &Dtool_MutableMappingWrapper_setdefault, METH_VARARGS, nullptr},
  1422. {"update", (PyCFunction) &Dtool_MutableMappingWrapper_update, METH_VARARGS | METH_KEYWORDS, nullptr},
  1423. {"keys", &Dtool_MappingWrapper_keys, METH_NOARGS, nullptr},
  1424. {"values", &Dtool_MappingWrapper_values, METH_NOARGS, nullptr},
  1425. {"items", &Dtool_MappingWrapper_items, METH_NOARGS, nullptr},
  1426. {nullptr, nullptr, 0, nullptr}
  1427. };
  1428. static PyTypeObject wrapper_type = {
  1429. PyVarObject_HEAD_INIT(nullptr, 0)
  1430. "mapping wrapper",
  1431. sizeof(Dtool_MappingWrapper),
  1432. 0, // tp_itemsize
  1433. Dtool_WrapperBase_dealloc,
  1434. 0, // tp_vectorcall_offset
  1435. nullptr, // tp_getattr
  1436. nullptr, // tp_setattr
  1437. nullptr, // tp_compare
  1438. Dtool_WrapperBase_repr,
  1439. nullptr, // tp_as_number
  1440. &seq_methods,
  1441. &map_methods,
  1442. nullptr, // tp_hash
  1443. nullptr, // tp_call
  1444. nullptr, // tp_str
  1445. PyObject_GenericGetAttr,
  1446. PyObject_GenericSetAttr,
  1447. nullptr, // tp_as_buffer
  1448. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  1449. nullptr, // tp_doc
  1450. nullptr, // tp_traverse
  1451. nullptr, // tp_clear
  1452. nullptr, // tp_richcompare
  1453. 0, // tp_weaklistoffset
  1454. Dtool_MappingWrapper_iter,
  1455. nullptr, // tp_iternext
  1456. methods,
  1457. nullptr, // tp_members
  1458. nullptr, // tp_getset
  1459. nullptr, // tp_base
  1460. nullptr, // tp_dict
  1461. nullptr, // tp_descr_get
  1462. nullptr, // tp_descr_set
  1463. 0, // tp_dictoffset
  1464. nullptr, // tp_init
  1465. PyType_GenericAlloc,
  1466. nullptr, // tp_new
  1467. PyObject_Del,
  1468. nullptr, // tp_is_gc
  1469. nullptr, // tp_bases
  1470. nullptr, // tp_mro
  1471. nullptr, // tp_cache
  1472. nullptr, // tp_subclasses
  1473. nullptr, // tp_weaklist
  1474. nullptr, // tp_del
  1475. 0, // tp_version_tag,
  1476. #if PY_VERSION_HEX >= 0x03040000
  1477. nullptr, // tp_finalize
  1478. #endif
  1479. #if PY_VERSION_HEX >= 0x03080000
  1480. nullptr, // tp_vectorcall
  1481. #endif
  1482. };
  1483. static bool registered = false;
  1484. if (!registered) {
  1485. registered = true;
  1486. if (PyType_Ready(&wrapper_type) < 0) {
  1487. return nullptr;
  1488. }
  1489. // If the collections.abc module is loaded, register this as a subclass.
  1490. _register_collection((PyTypeObject *)&wrapper_type, "MutableMapping");
  1491. }
  1492. (void)PyObject_INIT(wrap, &wrapper_type);
  1493. Py_XINCREF(self);
  1494. wrap->_base._self = self;
  1495. wrap->_base._name = name;
  1496. wrap->_keys._len_func = nullptr;
  1497. wrap->_keys._getitem_func = nullptr;
  1498. wrap->_getitem_func = nullptr;
  1499. wrap->_setitem_func = nullptr;
  1500. return wrap;
  1501. }
  1502. /**
  1503. * Creates a generator that invokes a given function with the given self arg.
  1504. */
  1505. PyObject *
  1506. Dtool_NewGenerator(PyObject *self, iternextfunc gen_next) {
  1507. static PyTypeObject wrapper_type = {
  1508. PyVarObject_HEAD_INIT(nullptr, 0)
  1509. "generator wrapper",
  1510. sizeof(Dtool_GeneratorWrapper),
  1511. 0, // tp_itemsize
  1512. Dtool_WrapperBase_dealloc,
  1513. 0, // tp_vectorcall_offset
  1514. nullptr, // tp_getattr
  1515. nullptr, // tp_setattr
  1516. nullptr, // tp_compare
  1517. nullptr, // tp_repr
  1518. nullptr, // tp_as_number
  1519. nullptr, // tp_as_sequence
  1520. nullptr, // tp_as_mapping
  1521. nullptr, // tp_hash
  1522. nullptr, // tp_call
  1523. nullptr, // tp_str
  1524. PyObject_GenericGetAttr,
  1525. PyObject_GenericSetAttr,
  1526. nullptr, // tp_as_buffer
  1527. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,
  1528. nullptr, // tp_doc
  1529. nullptr, // tp_traverse
  1530. nullptr, // tp_clear
  1531. nullptr, // tp_richcompare
  1532. 0, // tp_weaklistoffset
  1533. PyObject_SelfIter,
  1534. Dtool_GeneratorWrapper_iternext,
  1535. nullptr, // tp_methods
  1536. nullptr, // tp_members
  1537. nullptr, // tp_getset
  1538. nullptr, // tp_base
  1539. nullptr, // tp_dict
  1540. nullptr, // tp_descr_get
  1541. nullptr, // tp_descr_set
  1542. 0, // tp_dictoffset
  1543. nullptr, // tp_init
  1544. PyType_GenericAlloc,
  1545. nullptr, // tp_new
  1546. PyObject_Del,
  1547. nullptr, // tp_is_gc
  1548. nullptr, // tp_bases
  1549. nullptr, // tp_mro
  1550. nullptr, // tp_cache
  1551. nullptr, // tp_subclasses
  1552. nullptr, // tp_weaklist
  1553. nullptr, // tp_del
  1554. 0, // tp_version_tag,
  1555. #if PY_VERSION_HEX >= 0x03040000
  1556. nullptr, // tp_finalize
  1557. #endif
  1558. #if PY_VERSION_HEX >= 0x03080000
  1559. nullptr, // tp_vectorcall
  1560. #endif
  1561. };
  1562. if (PyType_Ready(&wrapper_type) < 0) {
  1563. return nullptr;
  1564. }
  1565. Dtool_GeneratorWrapper *gen;
  1566. gen = (Dtool_GeneratorWrapper *)PyType_GenericAlloc(&wrapper_type, 0);
  1567. if (gen != nullptr) {
  1568. Py_INCREF(self);
  1569. gen->_base._self = self;
  1570. gen->_iternext_func = gen_next;
  1571. }
  1572. return (PyObject *)gen;
  1573. }
  1574. /**
  1575. * This is a variant of the Python getset mechanism that permits static
  1576. * properties.
  1577. */
  1578. PyObject *
  1579. Dtool_NewStaticProperty(PyTypeObject *type, const PyGetSetDef *getset) {
  1580. static PyTypeObject wrapper_type = {
  1581. PyVarObject_HEAD_INIT(&PyType_Type, 0)
  1582. "getset_descriptor",
  1583. sizeof(PyGetSetDescrObject),
  1584. 0, // tp_itemsize
  1585. (destructor)Dtool_StaticProperty_dealloc,
  1586. 0, // tp_vectorcall_offset
  1587. nullptr, // tp_getattr
  1588. nullptr, // tp_setattr
  1589. nullptr, // tp_reserved
  1590. (reprfunc)Dtool_StaticProperty_repr,
  1591. nullptr, // tp_as_number
  1592. nullptr, // tp_as_sequence
  1593. nullptr, // tp_as_mapping
  1594. nullptr, // tp_hash
  1595. nullptr, // tp_call
  1596. nullptr, // tp_str
  1597. PyObject_GenericGetAttr,
  1598. nullptr, // tp_setattro
  1599. nullptr, // tp_as_buffer
  1600. Py_TPFLAGS_DEFAULT,
  1601. nullptr, // tp_doc
  1602. Dtool_StaticProperty_traverse,
  1603. nullptr, // tp_clear
  1604. nullptr, // tp_richcompare
  1605. 0, // tp_weaklistoffset
  1606. nullptr, // tp_iter
  1607. nullptr, // tp_iternext
  1608. nullptr, // tp_methods
  1609. nullptr, // tp_members
  1610. nullptr, // tp_getset
  1611. nullptr, // tp_base
  1612. nullptr, // tp_dict
  1613. (descrgetfunc)Dtool_StaticProperty_get,
  1614. (descrsetfunc)Dtool_StaticProperty_set,
  1615. 0, // tp_dictoffset
  1616. nullptr, // tp_init
  1617. nullptr, // tp_alloc
  1618. nullptr, // tp_new
  1619. nullptr, // tp_free
  1620. nullptr, // tp_is_gc
  1621. nullptr, // tp_bases
  1622. nullptr, // tp_mro
  1623. nullptr, // tp_cache
  1624. nullptr, // tp_subclasses
  1625. nullptr, // tp_weaklist
  1626. nullptr, // tp_del
  1627. 0, // tp_version_tag,
  1628. #if PY_VERSION_HEX >= 0x03040000
  1629. nullptr, // tp_finalize
  1630. #endif
  1631. #if PY_VERSION_HEX >= 0x03080000
  1632. nullptr, // tp_vectorcall
  1633. #endif
  1634. };
  1635. if (PyType_Ready(&wrapper_type) < 0) {
  1636. return nullptr;
  1637. }
  1638. PyGetSetDescrObject *descr;
  1639. descr = (PyGetSetDescrObject *)PyType_GenericAlloc(&wrapper_type, 0);
  1640. if (descr != nullptr) {
  1641. Py_XINCREF(type);
  1642. descr->d_getset = (PyGetSetDef *)getset;
  1643. #if PY_MAJOR_VERSION >= 3
  1644. descr->d_common.d_type = type;
  1645. descr->d_common.d_name = PyUnicode_InternFromString(getset->name);
  1646. #if PY_VERSION_HEX >= 0x03030000
  1647. descr->d_common.d_qualname = nullptr;
  1648. #endif
  1649. #else
  1650. descr->d_type = type;
  1651. descr->d_name = PyString_InternFromString(getset->name);
  1652. #endif
  1653. }
  1654. return (PyObject *)descr;
  1655. }
  1656. #endif // HAVE_PYTHON