tp_(get|set)attro? inheritance bug?
Documentation says, regarding tp_getattr: « This field is inherited by subtypes together with tp_getattro: a subtype inherits both tp_getattr and tp_getattro from its base type when the subtype's tp_getattr and tp_getattro are both NULL. » Implementation disagrees, at least in cvs head, but the effect of the bug (non-inheritance of tp_getattr) happens in 2.3.3. Follow with me: In function type_new (typeobject.c) line 1927: /* Special case some slots */ if (type->tp_dictoffset != 0 || nslots > 0) { if (base->tp_getattr == NULL && base->tp_getattro == NULL) type->tp_getattro = PyObject_GenericGetAttr; if (base->tp_setattr == NULL && base->tp_setattro == NULL) type->tp_setattro = PyObject_GenericSetAttr; } ...later in the same function... line /* Initialize the rest */ if (PyType_Ready(type) < 0) { Py_DECREF(type); return NULL; } Inside PyType_Ready(), line 3208: for (i = 1; i < n; i++) { PyObject *b = PyTuple_GET_ITEM(bases, i); if (PyType_Check(b)) inherit_slots(type, (PyTypeObject *)b); } Inside inherit_slots, line (3056): if (type->tp_getattr == NULL && type->tp_getattro == NULL) { type->tp_getattr = base->tp_getattr; type->tp_getattro = base->tp_getattro; } if (type->tp_setattr == NULL && type->tp_setattro == NULL) { type->tp_setattr = base->tp_setattr; type->tp_setattro = base->tp_setattro; } So, if you have followed through, you'll notice that type_new first sets tp_getattro = GenericGetAttr, in case 'base' has neither tp_getattr nor tp_getattro. So, you are thinking that there is no problem. If base has tp_getattr, that code path won't be execute. The problem is with multiple inheritance. In type_new, 'base' is determined by calling best_base(). But the selected base may not have tp_getattr, while another might have. In this case, setting tp_getattro based on information from the wrong base precludes the slot from being inherited from the right base. This is happening in pygtk, unfortunately. One possible solution would be to move the first code block to after the PyType_Ready() call. -- Gustavo João Alves Marques Carneiro <gjc@inescporto.pt> <gustavo@users.sourceforge.net> The universe is always one step beyond logic.
Did an SF bug report ever get filed for this? On Jun 11, 2004, at 10:58, Gustavo J. A. M. Carneiro wrote:
Documentation says, regarding tp_getattr: « This field is inherited by subtypes together with tp_getattro: a subtype inherits both tp_getattr and tp_getattro from its base type when the subtype's tp_getattr and tp_getattro are both NULL. »
Implementation disagrees, at least in cvs head, but the effect of the bug (non-inheritance of tp_getattr) happens in 2.3.3. Follow with me:
In function type_new (typeobject.c) line 1927: /* Special case some slots */ if (type->tp_dictoffset != 0 || nslots > 0) { if (base->tp_getattr == NULL && base->tp_getattro == NULL) type->tp_getattro = PyObject_GenericGetAttr; if (base->tp_setattr == NULL && base->tp_setattro == NULL) type->tp_setattro = PyObject_GenericSetAttr; } ...later in the same function... line
/* Initialize the rest */ if (PyType_Ready(type) < 0) { Py_DECREF(type); return NULL; }
Inside PyType_Ready(), line 3208: for (i = 1; i < n; i++) { PyObject *b = PyTuple_GET_ITEM(bases, i); if (PyType_Check(b)) inherit_slots(type, (PyTypeObject *)b); }
Inside inherit_slots, line (3056): if (type->tp_getattr == NULL && type->tp_getattro == NULL) { type->tp_getattr = base->tp_getattr; type->tp_getattro = base->tp_getattro; } if (type->tp_setattr == NULL && type->tp_setattro == NULL) { type->tp_setattr = base->tp_setattr; type->tp_setattro = base->tp_setattro; }
So, if you have followed through, you'll notice that type_new first sets tp_getattro = GenericGetAttr, in case 'base' has neither tp_getattr nor tp_getattro. So, you are thinking that there is no problem. If base has tp_getattr, that code path won't be execute. The problem is with multiple inheritance. In type_new, 'base' is determined by calling best_base(). But the selected base may not have tp_getattr, while another might have. In this case, setting tp_getattro based on information from the wrong base precludes the slot from being inherited from the right base. This is happening in pygtk, unfortunately.
One possible solution would be to move the first code block to after the PyType_Ready() call.
-- Gustavo João Alves Marques Carneiro <gjc@inescporto.pt> <gustavo@users.sourceforge.net> The universe is always one step beyond logic.
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/brett%40python.org
On Thu, Jun 17, 2004 at 02:37:38PM -0700, Brett wrote:
Did an SF bug report ever get filed for this?
Yes. Gustavo endured the bugtracker and it was filed today as bug 975646: http://sourceforge.net/tracker/index.php?func=detail&aid=975646&group_id=5470&atid=105470 Let us know if any further info is necessary, or if we're barking up the wrong tree. Thanks.
On Jun 11, 2004, at 10:58, Gustavo J. A. M. Carneiro wrote:
Documentation says, regarding tp_getattr: « This field is inherited by subtypes together with tp_getattro: a subtype inherits both tp_getattr and tp_getattro from its base type when the subtype's tp_getattr and tp_getattro are both NULL. »
Implementation disagrees, at least in cvs head, but the effect of the bug (non-inheritance of tp_getattr) happens in 2.3.3. Follow with me: [snip]
Take care, -- Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 261 2331
participants (3)
-
Brett -
Christian Robottom Reis -
Gustavo J. A. M. Carneiro