Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.3k
Open
Description
Bug report
If a base class is aPyVarObject, classes inheriting from that base cannot add__dict__ or__weakref__ through__slots__ declaration on the class. If__slots__ is not empty, the following exception is raised:TypeError: nonempty __slots__ not supported for subtype of '...'
Assume that we have aPyVarObjectfoo.FooBase class (implementation below). Trying to inherit from the class and requesting weakref support doesn't work.
importfooclassWithWeakrefAndDict(foo.FooBase):__slots__= ('__weakref__','__dict__')
`foo` module implementation
#definePY_SSIZE_T_CLEAN#include<Python.h>staticconstPy_ssize_tN_EXTRA=4;typedefstruct {PyObject_VAR_HEAD}FooBase;staticPyObject**FooBase_get_storage(PyObject*self){char*addr= (char*)self;return (PyObject**)(addr+Py_TYPE(self)->tp_basicsize);}staticintFooBase_traverse(PyObject*self,visitprocvisit,void*arg){PyObject**storage=FooBase_get_storage(self);for (inti=0;i<N_EXTRA;i++) {Py_VISIT(storage[i]); }Py_VISIT(Py_TYPE(self));return0;}staticintFooBase_clear(PyObject*self){PyObject**storage=FooBase_get_storage(self);for (inti=0;i<N_EXTRA;i++) {Py_CLEAR(storage[i]); }return0;}staticvoidFooBase_dealloc(PyObject*self){PyTypeObject*tp=Py_TYPE(self);PyObject_GC_UnTrack(self);FooBase_clear(self);PyObject_GC_Del(self);if (tp->tp_flags&Py_TPFLAGS_HEAPTYPE)Py_DECREF(tp);}staticPyObject*FooBase_new(PyTypeObject*type,PyObject*args,PyObject*kwargs){PyVarObject*obj=PyObject_GC_NewVar(PyVarObject,type,N_EXTRA);if (obj==NULL)returnNULL;PyObject**storage=FooBase_get_storage((PyObject*)obj);for (inti=0;i<Py_SIZE(obj);i++)storage[i]=NULL;PyObject_GC_Track(obj);return (PyObject*)obj;}staticPyObject*FooBase_get_extra(PyObject*self,PyObject*args){Py_ssize_tidx;if (!PyArg_ParseTuple(args,"n",&idx))returnNULL;if (idx<0||idx >=N_EXTRA) {PyErr_Format(PyExc_ValueError,"idx must be >= 0 and < %zd",N_EXTRA);returnNULL; }PyObject**storage=FooBase_get_storage(self);PyObject*value=storage[idx];if (!value) {Py_RETURN_NONE; }else {Py_INCREF(value);returnvalue; }}staticPyObject*FooBase_set_extra(PyObject*self,PyObject*args){Py_ssize_tidx;PyObject*value;if (!PyArg_ParseTuple(args,"nO",&idx,&value))returnNULL;if (idx<0||idx >=N_EXTRA) {PyErr_Format(PyExc_ValueError,"idx must be >= 0 and < %zd",N_EXTRA);returnNULL; }PyObject**storage=FooBase_get_storage(self);Py_CLEAR(storage[idx]);Py_INCREF(value);storage[idx]=value;Py_RETURN_NONE;}staticPyMethodDefFooBase_methods[]= { {"get_extra",FooBase_get_extra,METH_VARARGS,NULL}, {"set_extra",FooBase_set_extra,METH_VARARGS,NULL}, {NULL}};staticPyTypeObjectFooBase_Type= {PyVarObject_HEAD_INIT(NULL,0)"foo.FooBase",sizeof(FooBase), .tp_dealloc= (destructor)FooBase_dealloc, .tp_flags=Py_TPFLAGS_DEFAULT |Py_TPFLAGS_BASETYPE |Py_TPFLAGS_HAVE_GC, .tp_traverse=FooBase_traverse, .tp_clear=FooBase_clear, .tp_methods=FooBase_methods, .tp_new=FooBase_new, .tp_itemsize=sizeof(PyObject*)};staticstructPyModuleDeffoo_module= {PyModuleDef_HEAD_INIT,"foo",NULL,-1,};PyMODINIT_FUNCPyInit_foo(void){PyObject*m=PyModule_Create(&foo_module);if (!m)returnNULL;if (PyType_Ready(&FooBase_Type)<0)returnNULL;Py_INCREF(&FooBase_Type);PyModule_AddObject(m,"FooBase", (PyObject*)&FooBase_Type);returnm;}
Your environment
- CPython versions tested on: 3.11.3
- Operating system and architecture: Linux, x86_64
CC:@encukou