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