summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-04-30 10:46:15 (GMT)
committerGitHub <noreply@github.com>2021-04-30 10:46:15 (GMT)
commit3bb09947ec4837de75532e21dd4bd25db0a1f1b7 (patch)
tree46469716b18eda1c8af7c311b6187fda39a146c1 /Modules
parentb73b5fb9ea08156991a065c1696e8d8cf7622482 (diff)
downloadcpython-3bb09947ec4837de75532e21dd4bd25db0a1f1b7.zip
cpython-3bb09947ec4837de75532e21dd4bd25db0a1f1b7.tar.gz
cpython-3bb09947ec4837de75532e21dd4bd25db0a1f1b7.tar.bz2
bpo-43916: Add Py_TPFLAGS_DISALLOW_INSTANTIATION type flag (GH-25721)
Add a new Py_TPFLAGS_DISALLOW_INSTANTIATION type flag to disallow creating type instances: set tp_new to NULL and don't create the "__new__" key in the type dictionary. The flag is set automatically on static types if tp_base is NULL or &PyBaseObject_Type and tp_new is NULL. Use the flag on the following types: * _curses.ncurses_version type * _curses_panel.panel * _tkinter.Tcl_Obj * _tkinter.tkapp * _tkinter.tktimertoken * _xxsubinterpretersmodule.ChannelID * sys.flags type * sys.getwindowsversion() type * sys.version_info type Update MyStr example in the C API documentation to use Py_TPFLAGS_DISALLOW_INSTANTIATION. Add _PyStructSequence_InitType() function to create a structseq type with the Py_TPFLAGS_DISALLOW_INSTANTIATION flag set. type_new() calls _PyType_CheckConsistency() at exit.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_curses_panel.c3
-rw-r--r--Modules/_cursesmodule.c15
-rw-r--r--Modules/_tkinter.c9
-rw-r--r--Modules/_xxsubinterpretersmodule.c20
4 files changed, 14 insertions, 33 deletions
diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c
index 94caf8c..0b328f9 100644
--- a/Modules/_curses_panel.c
+++ b/Modules/_curses_panel.c
@@ -520,7 +520,7 @@ static PyType_Slot PyCursesPanel_Type_slots[] = {
static PyType_Spec PyCursesPanel_Type_spec = {
.name = "_curses_panel.panel",
.basicsize = sizeof(PyCursesPanelObject),
- .flags = Py_TPFLAGS_DEFAULT,
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
.slots = PyCursesPanel_Type_slots
};
@@ -656,7 +656,6 @@ _curses_panel_exec(PyObject *mod)
if (state->PyCursesPanel_Type == NULL) {
return -1;
}
- ((PyTypeObject *)state->PyCursesPanel_Type)->tp_new = NULL;
if (PyModule_AddType(mod, state->PyCursesPanel_Type) < 0) {
return -1;
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index d221cf1..bcf9ad1 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -4793,9 +4793,11 @@ PyInit__curses(void)
#ifdef NCURSES_VERSION
/* ncurses_version */
if (NcursesVersionType.tp_name == NULL) {
- if (PyStructSequence_InitType2(&NcursesVersionType,
- &ncurses_version_desc) < 0)
+ if (_PyStructSequence_InitType(&NcursesVersionType,
+ &ncurses_version_desc,
+ Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
return NULL;
+ }
}
v = make_ncurses_version();
if (v == NULL) {
@@ -4803,15 +4805,6 @@ PyInit__curses(void)
}
PyDict_SetItemString(d, "ncurses_version", v);
Py_DECREF(v);
-
- /* prevent user from creating new instances */
- NcursesVersionType.tp_init = NULL;
- NcursesVersionType.tp_new = NULL;
- if (PyDict_DelItemString(NcursesVersionType.tp_dict, "__new__") < 0 &&
- PyErr_ExceptionMatches(PyExc_KeyError))
- {
- PyErr_Clear();
- }
#endif /* NCURSES_VERSION */
SetDictInt("ERR", ERR);
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 46d6a6e..3a0e5de 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -1002,7 +1002,7 @@ static PyType_Spec PyTclObject_Type_spec = {
"_tkinter.Tcl_Obj",
sizeof(PyTclObject),
0,
- Py_TPFLAGS_DEFAULT,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
PyTclObject_Type_slots,
};
@@ -3294,7 +3294,7 @@ static PyType_Spec Tktt_Type_spec = {
"_tkinter.tktimertoken",
sizeof(TkttObject),
0,
- Py_TPFLAGS_DEFAULT,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
Tktt_Type_slots,
};
@@ -3349,7 +3349,7 @@ static PyType_Spec Tkapp_Type_spec = {
"_tkinter.tkapp",
sizeof(TkappObject),
0,
- Py_TPFLAGS_DEFAULT,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
Tkapp_Type_slots,
};
@@ -3537,7 +3537,6 @@ PyInit__tkinter(void)
Py_DECREF(m);
return NULL;
}
- ((PyTypeObject *)o)->tp_new = NULL;
if (PyModule_AddObject(m, "TkappType", o)) {
Py_DECREF(o);
Py_DECREF(m);
@@ -3550,7 +3549,6 @@ PyInit__tkinter(void)
Py_DECREF(m);
return NULL;
}
- ((PyTypeObject *)o)->tp_new = NULL;
if (PyModule_AddObject(m, "TkttType", o)) {
Py_DECREF(o);
Py_DECREF(m);
@@ -3563,7 +3561,6 @@ PyInit__tkinter(void)
Py_DECREF(m);
return NULL;
}
- ((PyTypeObject *)o)->tp_new = NULL;
if (PyModule_AddObject(m, "Tcl_Obj", o)) {
Py_DECREF(o);
Py_DECREF(m);
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index b94b130..9290255 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1780,7 +1780,12 @@ static PyTypeObject ChannelIDtype = {
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ // Use Py_TPFLAGS_DISALLOW_INSTANTIATION so the type cannot be instantiated
+ // from Python code. We do this because there is a strong relationship
+ // between channel IDs and the channel lifecycle, so this limitation avoids
+ // related complications. Use the _channel_id() function instead.
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+ | Py_TPFLAGS_DISALLOW_INSTANTIATION, /* tp_flags */
channelid_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
@@ -1791,19 +1796,6 @@ static PyTypeObject ChannelIDtype = {
0, /* tp_methods */
0, /* tp_members */
channelid_getsets, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- // Note that we do not set tp_new to channelid_new. Instead we
- // set it to NULL, meaning it cannot be instantiated from Python
- // code. We do this because there is a strong relationship between
- // channel IDs and the channel lifecycle, so this limitation avoids
- // related complications.
- NULL, /* tp_new */
};