@@ -538,6 +538,12 @@ int PyType_Ready(PyTypeObject* cls) {
538
538
type_ready_set_new (cls , dict , base );
539
539
540
540
/* fill dict */
541
+
542
+ /*
543
+ * NOTE: ADD_SLOT_CONV won't overwrite existing attributes, so the order is crucial and must
544
+ * reflect CPython's 'slotdefs' array.
545
+ */
546
+
541
547
// add special methods defined directly on the type structs
542
548
ADD_SLOT_CONV ("__dealloc__" , cls -> tp_dealloc , -1 , JWRAPPER_DIRECT );
543
549
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_getattr
@@ -583,20 +589,7 @@ int PyType_Ready(PyTypeObject* cls) {
583
589
ADD_SLOT_CONV ("__del__" , cls -> tp_del , -1 , JWRAPPER_DIRECT );
584
590
ADD_SLOT_CONV ("__finalize__" , cls -> tp_finalize , -1 , JWRAPPER_DIRECT );
585
591
586
- PySequenceMethods * sequences = PyTypeObject_tp_as_sequence (cls );
587
- if (sequences ) {
588
- // sequence functions first, so that the number functions take precendence
589
- ADD_SLOT_CONV ("__len__" , sequences -> sq_length , -1 , JWRAPPER_LENFUNC );
590
- ADD_SLOT_CONV ("__add__" , sequences -> sq_concat , -2 , JWRAPPER_BINARYFUNC );
591
- ADD_SLOT_CONV ("__mul__" , sequences -> sq_repeat , -2 , JWRAPPER_SSIZE_ARG );
592
- ADD_SLOT_CONV ("__getitem__" , sequences -> sq_item , -2 , JWRAPPER_GETITEM );
593
- ADD_SLOT_CONV ("__setitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_SETITEM );
594
- ADD_SLOT_CONV ("__delitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_DELITEM );
595
- ADD_SLOT_CONV ("__contains__" , sequences -> sq_contains , -2 , JWRAPPER_OBJOBJPROC );
596
- ADD_SLOT_CONV ("__iadd__" , sequences -> sq_inplace_concat , -2 , JWRAPPER_BINARYFUNC );
597
- ADD_SLOT_CONV ("__imul__" , sequences -> sq_inplace_repeat , -2 , JWRAPPER_SSIZE_ARG );
598
- }
599
-
592
+ // 'tp_as_number' takes precedence over 'tp_as_mapping' and 'tp_as_sequence' !
600
593
PyNumberMethods * numbers = PyTypeObject_tp_as_number (cls );
601
594
if (numbers ) {
602
595
ADD_SLOT_CONV ("__add__" , numbers -> nb_add , -2 , JWRAPPER_BINARYFUNC_L );
@@ -650,6 +643,7 @@ int PyType_Ready(PyTypeObject* cls) {
650
643
ADD_SLOT_CONV ("__imatmul__" , numbers -> nb_inplace_matrix_multiply , -2 , JWRAPPER_BINARYFUNC_L );
651
644
}
652
645
646
+ // 'tp_as_mapping' takes precedence over 'tp_as_sequence' !
653
647
PyMappingMethods * mappings = PyTypeObject_tp_as_mapping (cls );
654
648
if (mappings ) {
655
649
ADD_SLOT_CONV ("__len__" , mappings -> mp_length , -1 , JWRAPPER_LENFUNC );
@@ -658,6 +652,20 @@ int PyType_Ready(PyTypeObject* cls) {
658
652
ADD_SLOT_CONV ("__delitem__" , mappings -> mp_ass_subscript , -3 , JWRAPPER_MP_DELITEM );
659
653
}
660
654
655
+ PySequenceMethods * sequences = PyTypeObject_tp_as_sequence (cls );
656
+ if (sequences ) {
657
+ // sequence functions first, so that the number functions take precendence
658
+ ADD_SLOT_CONV ("__len__" , sequences -> sq_length , -1 , JWRAPPER_LENFUNC );
659
+ ADD_SLOT_CONV ("__add__" , sequences -> sq_concat , -2 , JWRAPPER_BINARYFUNC );
660
+ ADD_SLOT_CONV ("__mul__" , sequences -> sq_repeat , -2 , JWRAPPER_SSIZE_ARG );
661
+ ADD_SLOT_CONV ("__getitem__" , sequences -> sq_item , -2 , JWRAPPER_GETITEM );
662
+ ADD_SLOT_CONV ("__setitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_SETITEM );
663
+ ADD_SLOT_CONV ("__delitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_DELITEM );
664
+ ADD_SLOT_CONV ("__contains__" , sequences -> sq_contains , -2 , JWRAPPER_OBJOBJPROC );
665
+ ADD_SLOT_CONV ("__iadd__" , sequences -> sq_inplace_concat , -2 , JWRAPPER_BINARYFUNC );
666
+ ADD_SLOT_CONV ("__imul__" , sequences -> sq_inplace_repeat , -2 , JWRAPPER_SSIZE_ARG );
667
+ }
668
+
661
669
PyAsyncMethods * async = PyTypeObject_tp_as_async (cls );
662
670
if (async ) {
663
671
ADD_SLOT_CONV ("__await__" , async -> am_await , -1 , JWRAPPER_DIRECT );
0 commit comments