-
-
Notifications
You must be signed in to change notification settings - Fork 34.6k
gh-116946: fully implement GC protocol for _tkinter.Tk{app,tt}Object
#138331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
84f832f
a9c01ef
dbb343f
9eb9f47
8e80641
833a85e
022d71e
168fe43
5e5f698
35915b0
ba9c809
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2742,9 +2742,13 @@ _tkinter_tktimertoken_deletetimerhandler_impl(TkttObject *self) | |||||||||||
| static TkttObject * | ||||||||||||
| Tktt_New(PyObject *func) | ||||||||||||
| { | ||||||||||||
| PyTypeObject *type; | ||||||||||||
| TkttObject *v; | ||||||||||||
|
|
||||||||||||
| v = PyObject_New(TkttObject, (PyTypeObject *) Tktt_Type); | ||||||||||||
| type = (PyTypeObject *)Tktt_Type; | ||||||||||||
| assert(type != NULL); | ||||||||||||
| assert(type->tp_alloc != NULL); | ||||||||||||
| v = (TkttObject *)type->tp_alloc(type, 0); | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, we would need (TkttObject *)((PyTypeObject *)Tktt_Type)->tp_alloc((PyTypeObject *)Tktt_Type, 0);which is a bit unreadable IMO. So I'll keep the temporary type variable. I would prefer having a macro for calling #define _PyObject_New(T, type) \
((T *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0)) |
||||||||||||
| if (v == NULL) | ||||||||||||
| return NULL; | ||||||||||||
|
|
||||||||||||
|
|
@@ -2755,19 +2759,33 @@ Tktt_New(PyObject *func) | |||||||||||
| return (TkttObject*)Py_NewRef(v); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static void | ||||||||||||
| Tktt_Dealloc(PyObject *self) | ||||||||||||
| static int | ||||||||||||
| Tktt_Clear(PyObject *op) | ||||||||||||
| { | ||||||||||||
| TkttObject *v = TkttObject_CAST(self); | ||||||||||||
| PyObject *func = v->func; | ||||||||||||
| PyObject *tp = (PyObject *) Py_TYPE(self); | ||||||||||||
|
|
||||||||||||
| Py_XDECREF(func); | ||||||||||||
| TkttObject *self = TkttObject_CAST(op); | ||||||||||||
| Py_CLEAR(self->func); | ||||||||||||
| return 0; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| PyObject_Free(self); | ||||||||||||
| static void | ||||||||||||
| Tktt_Dealloc(PyObject *op) | ||||||||||||
| { | ||||||||||||
| PyTypeObject *tp = Py_TYPE(op); | ||||||||||||
| PyObject_GC_UnTrack(op); | ||||||||||||
| (void)Tktt_Clear(op); | ||||||||||||
| tp->tp_free(op); | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, this temporary variable is needed as we need |
||||||||||||
| Py_DECREF(tp); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static int | ||||||||||||
| Tktt_Traverse(PyObject *op, visitproc visit, void *arg) | ||||||||||||
| { | ||||||||||||
| TkttObject *self = TkttObject_CAST(op); | ||||||||||||
| Py_VISIT(Py_TYPE(op)); | ||||||||||||
| Py_VISIT(self->func); | ||||||||||||
| return 0; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static PyObject * | ||||||||||||
| Tktt_Repr(PyObject *self) | ||||||||||||
| { | ||||||||||||
|
|
@@ -3058,21 +3076,38 @@ _tkinter_tkapp_willdispatch_impl(TkappObject *self) | |||||||||||
|
|
||||||||||||
| /**** Tkapp Type Methods ****/ | ||||||||||||
|
|
||||||||||||
| static int | ||||||||||||
| Tkapp_Clear(PyObject *op) | ||||||||||||
| { | ||||||||||||
| TkappObject *self = TkappObject_CAST(op); | ||||||||||||
| Py_CLEAR(self->trace); | ||||||||||||
| return 0; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static void | ||||||||||||
| Tkapp_Dealloc(PyObject *op) | ||||||||||||
| { | ||||||||||||
| PyTypeObject *tp = Py_TYPE(op); | ||||||||||||
| PyObject_GC_UnTrack(op); | ||||||||||||
| TkappObject *self = TkappObject_CAST(op); | ||||||||||||
| PyTypeObject *tp = Py_TYPE(self); | ||||||||||||
| /*CHECK_TCL_APPARTMENT;*/ | ||||||||||||
| ENTER_TCL | ||||||||||||
| Tcl_DeleteInterp(Tkapp_Interp(self)); | ||||||||||||
| LEAVE_TCL | ||||||||||||
| Py_XDECREF(self->trace); | ||||||||||||
| PyObject_Free(self); | ||||||||||||
| (void)Tkapp_Clear(op); | ||||||||||||
| tp->tp_free(self); | ||||||||||||
|
picnixz marked this conversation as resolved.
|
||||||||||||
| Py_DECREF(tp); | ||||||||||||
| DisableEventHook(); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| static int | ||||||||||||
| Tkapp_Traverse(PyObject *op, visitproc visit, void *arg) | ||||||||||||
| { | ||||||||||||
| TkappObject *self = TkappObject_CAST(op); | ||||||||||||
| Py_VISIT(Py_TYPE(op)); | ||||||||||||
| Py_VISIT(self->trace); | ||||||||||||
| return 0; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| /**** Tkinter Module ****/ | ||||||||||||
|
|
@@ -3260,18 +3295,23 @@ static PyMethodDef Tktt_methods[] = | |||||||||||
| }; | ||||||||||||
|
|
||||||||||||
| static PyType_Slot Tktt_Type_slots[] = { | ||||||||||||
| {Py_tp_clear, Tktt_Clear}, | ||||||||||||
| {Py_tp_dealloc, Tktt_Dealloc}, | ||||||||||||
| {Py_tp_traverse, Tktt_Traverse}, | ||||||||||||
| {Py_tp_repr, Tktt_Repr}, | ||||||||||||
| {Py_tp_methods, Tktt_methods}, | ||||||||||||
| {0, 0} | ||||||||||||
| }; | ||||||||||||
|
|
||||||||||||
| static PyType_Spec Tktt_Type_spec = { | ||||||||||||
| "_tkinter.tktimertoken", | ||||||||||||
| sizeof(TkttObject), | ||||||||||||
| 0, | ||||||||||||
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, | ||||||||||||
| Tktt_Type_slots, | ||||||||||||
| .name = "_tkinter.tktimertoken", | ||||||||||||
| .basicsize = sizeof(TkttObject), | ||||||||||||
| .flags = ( | ||||||||||||
| Py_TPFLAGS_DEFAULT | ||||||||||||
| | Py_TPFLAGS_DISALLOW_INSTANTIATION | ||||||||||||
| | Py_TPFLAGS_HAVE_GC | ||||||||||||
| ), | ||||||||||||
| .slots = Tktt_Type_slots, | ||||||||||||
| }; | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
|
|
@@ -3316,18 +3356,23 @@ static PyMethodDef Tkapp_methods[] = | |||||||||||
| }; | ||||||||||||
|
|
||||||||||||
| static PyType_Slot Tkapp_Type_slots[] = { | ||||||||||||
| {Py_tp_clear, Tkapp_Clear}, | ||||||||||||
| {Py_tp_dealloc, Tkapp_Dealloc}, | ||||||||||||
| {Py_tp_traverse, Tkapp_Traverse}, | ||||||||||||
| {Py_tp_methods, Tkapp_methods}, | ||||||||||||
| {0, 0} | ||||||||||||
| }; | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| static PyType_Spec Tkapp_Type_spec = { | ||||||||||||
| "_tkinter.tkapp", | ||||||||||||
| sizeof(TkappObject), | ||||||||||||
| 0, | ||||||||||||
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, | ||||||||||||
| Tkapp_Type_slots, | ||||||||||||
| .name = "_tkinter.tkapp", | ||||||||||||
| .basicsize = sizeof(TkappObject), | ||||||||||||
| .flags = ( | ||||||||||||
| Py_TPFLAGS_DEFAULT | ||||||||||||
| | Py_TPFLAGS_DISALLOW_INSTANTIATION | ||||||||||||
| | Py_TPFLAGS_HAVE_GC | ||||||||||||
| ), | ||||||||||||
| .slots = Tkapp_Type_slots, | ||||||||||||
| }; | ||||||||||||
|
|
||||||||||||
| static PyMethodDef moduleMethods[] = | ||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these types cannot be subclassed. So we can simply replace
PyObject_New/PyObject_FreewithPyObject_GC_New/PyObject_GC_Del. I think that this would look clearer than withtp_alloc/tp_free.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but now the docs explicitly say "don't call those functions directly, use tp_alloc/tp_free". I agree that when possible, we could directly call them, but @ZeroIntensity suggested to follow the docs here.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like using
tp_alloc/tp_freemore because it's less refactoring if we need to change the type flags. People follow CPython's source code for inspiration in their extensions, so we should follow what's documented. If we want to change the preference, let's update the docs.Alternatively, we could have a function like this for limited API users:
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point, I would prefer having a macro to avoid the extra cast everytime... Something that unifies
PyObject_[GC_]New(typename, type).