[Python-checkins] bpo-43916: Add Py_TPFLAGS_DISALLOW_INSTANTIATION type flag (GH-25721)

vstinner webhook-mailer at python.org
Fri Apr 30 06:46:19 EDT 2021


https://github.com/python/cpython/commit/3bb09947ec4837de75532e21dd4bd25db0a1f1b7
commit: 3bb09947ec4837de75532e21dd4bd25db0a1f1b7
branch: master
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2021-04-30T12:46:15+02:00
summary:

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.

files:
A Misc/NEWS.d/next/C API/2021-04-29-17-35-48.bpo-43916.wvWt23.rst
M Doc/c-api/typeobj.rst
M Doc/whatsnew/3.10.rst
M Include/object.h
M Include/structseq.h
M Lib/test/test_sys.py
M Modules/_curses_panel.c
M Modules/_cursesmodule.c
M Modules/_tkinter.c
M Modules/_xxsubinterpretersmodule.c
M Objects/structseq.c
M Objects/typeobject.c
M Python/sysmodule.c

diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index 85f0262d10138..5e731bd5a6cbd 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -1199,6 +1199,25 @@ and :c:type:`PyType_Type` effectively act as defaults.)
 
       .. versionadded:: 3.10
 
+   .. data:: Py_TPFLAGS_DISALLOW_INSTANTIATION
+
+      Disallow creating instances of the type: set
+      :c:member:`~PyTypeObject.tp_new` to NULL and don't create the ``__new__``
+      key in the type dictionary.
+
+      The flag must be set before creating the type, not after. For example, it
+      must be set before :c:func:`PyType_Ready` is called on the type.
+
+      The flag is set automatically on :ref:`static types <static-types>` if
+      :c:member:`~PyTypeObject.tp_base` is NULL or ``&PyBaseObject_Type`` and
+      :c:member:`~PyTypeObject.tp_new` is NULL.
+
+      **Inheritance:**
+
+      This flag is not inherited.
+
+      .. versionadded:: 3.10
+
 
 .. c:member:: const char* PyTypeObject.tp_doc
 
@@ -1761,6 +1780,9 @@ and :c:type:`PyType_Type` effectively act as defaults.)
    in :c:member:`~PyTypeObject.tp_new`, while for mutable types, most initialization should be
    deferred to :c:member:`~PyTypeObject.tp_init`.
 
+   Set the :const:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag to disallow creating
+   instances of the type in Python.
+
    **Inheritance:**
 
    This field is inherited by subtypes, except it is not inherited by
@@ -2596,7 +2618,8 @@ A type that supports weakrefs, instance dicts, and hashing::
    };
 
 A str subclass that cannot be subclassed and cannot be called
-to create instances (e.g. uses a separate factory func)::
+to create instances (e.g. uses a separate factory func) using
+:c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag::
 
    typedef struct {
        PyUnicodeObject raw;
@@ -2609,8 +2632,7 @@ to create instances (e.g. uses a separate factory func)::
        .tp_basicsize = sizeof(MyStr),
        .tp_base = NULL,  // set to &PyUnicode_Type in module init
        .tp_doc = "my custom str",
-       .tp_flags = Py_TPFLAGS_DEFAULT,
-       .tp_new = NULL,
+       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
        .tp_repr = (reprfunc)myobj_repr,
    };
 
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 2580a0368d0b3..1a390663c8a40 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -1708,6 +1708,10 @@ New Features
   These functions allow to activate, deactivate and query the state of the garbage collector from C code without
   having to import the :mod:`gc` module.
 
+* Add a new :c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` type flag to disallow
+  creating type instances.
+  (Contributed by Victor Stinner in :issue:`43916`.)
+
 Porting to Python 3.10
 ----------------------
 
diff --git a/Include/object.h b/Include/object.h
index cffe72cda869f..4c069998574b4 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -327,6 +327,10 @@ given type object has a specified feature.
 #define Py_TPFLAGS_MAPPING (1 << 6)
 #endif
 
+/* Disallow creating instances of the type: set tp_new to NULL and don't create
+ * the "__new__" key in the type dictionary. */
+#define Py_TPFLAGS_DISALLOW_INSTANTIATION (1UL << 7)
+
 /* Set if the type object is immutable: type attributes cannot be set nor deleted */
 #define Py_TPFLAGS_IMMUTABLETYPE (1UL << 8)
 
diff --git a/Include/structseq.h b/Include/structseq.h
index 8f51c89163a4e..af3af415b013a 100644
--- a/Include/structseq.h
+++ b/Include/structseq.h
@@ -27,6 +27,12 @@ PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
 PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type,
                                            PyStructSequence_Desc *desc);
 #endif
+#ifdef Py_BUILD_CORE
+extern int _PyStructSequence_InitType(
+    PyTypeObject *type,
+    PyStructSequence_Desc *desc,
+    unsigned long tp_flags);
+#endif
 PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc);
 
 PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type);
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index ee39375af3160..1fd5247a91bb5 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -605,11 +605,12 @@ def test_sys_flags(self):
     def assert_raise_on_new_sys_type(self, sys_attr):
         # Users are intentionally prevented from creating new instances of
         # sys.flags, sys.version_info, and sys.getwindowsversion.
+        arg = sys_attr
         attr_type = type(sys_attr)
         with self.assertRaises(TypeError):
-            attr_type()
+            attr_type(arg)
         with self.assertRaises(TypeError):
-            attr_type.__new__(attr_type)
+            attr_type.__new__(attr_type, arg)
 
     def test_sys_flags_no_instantiation(self):
         self.assert_raise_on_new_sys_type(sys.flags)
diff --git a/Misc/NEWS.d/next/C API/2021-04-29-17-35-48.bpo-43916.wvWt23.rst b/Misc/NEWS.d/next/C API/2021-04-29-17-35-48.bpo-43916.wvWt23.rst
new file mode 100644
index 0000000000000..0cec8103645e3
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2021-04-29-17-35-48.bpo-43916.wvWt23.rst	
@@ -0,0 +1,2 @@
+Add a new :c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` type flag to disallow
+creating type instances. Patch by Victor Stinner.
diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c
index 94caf8c93bc8c..0b328f9665a0a 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 d221cf1a92520..bcf9ad19386b2 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 46d6a6e0954f5..3a0e5def0cf3c 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 b94b130d70df7..9290255c66c3f 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 */
 };
 
 
diff --git a/Objects/structseq.c b/Objects/structseq.c
index 88e63b658a420..bf59f47fcf073 100644
--- a/Objects/structseq.c
+++ b/Objects/structseq.c
@@ -459,8 +459,10 @@ initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
     members[k].name = NULL;
 }
 
+
 int
-PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
+_PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
+                           unsigned long tp_flags)
 {
     PyMemberDef *members;
     Py_ssize_t n_members, n_unnamed_members;
@@ -488,7 +490,7 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
     type->tp_base = &PyTuple_Type;
     type->tp_methods = structseq_methods;
     type->tp_new = structseq_new;
-    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC;
+    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
     type->tp_traverse = (traverseproc) structseq_traverse;
 
     n_members = count_members(desc, &n_unnamed_members);
@@ -516,6 +518,12 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
     return 0;
 }
 
+int
+PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
+{
+    return _PyStructSequence_InitType(type, desc, 0);
+}
+
 void
 PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
 {
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 1f8e2572a2daf..0f7f280bca0d6 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -158,6 +158,11 @@ _PyType_CheckConsistency(PyTypeObject *type)
     CHECK(!(type->tp_flags & Py_TPFLAGS_READYING));
     CHECK(type->tp_dict != NULL);
 
+    if (type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION) {
+        CHECK(type->tp_new == NULL);
+        CHECK(_PyDict_ContainsId(type->tp_dict, &PyId___new__) == 0);
+    }
+
     return 1;
 #undef CHECK
 }
@@ -1111,8 +1116,7 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
     if (type->tp_new == NULL) {
         _PyErr_Format(tstate, PyExc_TypeError,
-                      "cannot create '%.100s' instances",
-                      type->tp_name);
+                      "cannot create '%s' instances", type->tp_name);
         return NULL;
     }
 
@@ -3185,6 +3189,8 @@ type_new_impl(type_new_ctx *ctx)
     if (type_new_init_subclass(type, ctx->kwds) < 0) {
         goto error;
     }
+
+    assert(_PyType_CheckConsistency(type));
     return (PyObject *)type;
 
 error:
@@ -5651,7 +5657,6 @@ type_add_getset(PyTypeObject *type)
 static void
 inherit_special(PyTypeObject *type, PyTypeObject *base)
 {
-
     /* Copying tp_traverse and tp_clear is connected to the GC flags */
     if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
         (base->tp_flags & Py_TPFLAGS_HAVE_GC) &&
@@ -5662,23 +5667,7 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
         if (type->tp_clear == NULL)
             type->tp_clear = base->tp_clear;
     }
-    {
-        /* The condition below could use some explanation.
-           It appears that tp_new is not inherited for static types
-           whose base class is 'object'; this seems to be a precaution
-           so that old extension types don't suddenly become
-           callable (object.__new__ wouldn't insure the invariants
-           that the extension type's own factory function ensures).
-           Heap types, of course, are under our control, so they do
-           inherit tp_new; static extension types that specify some
-           other built-in type as the default also
-           inherit object.__new__. */
-        if (base != &PyBaseObject_Type ||
-            (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
-            if (type->tp_new == NULL)
-                type->tp_new = base->tp_new;
-        }
-    }
+
     if (type->tp_basicsize == 0)
         type->tp_basicsize = base->tp_basicsize;
 
@@ -5941,6 +5930,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
 }
 
 static int add_operators(PyTypeObject *);
+static int add_tp_new_wrapper(PyTypeObject *type);
 
 
 static int
@@ -5991,6 +5981,7 @@ type_ready_set_bases(PyTypeObject *type)
             type->tp_base = base;
         }
     }
+    assert(type->tp_base != NULL || type == &PyBaseObject_Type);
 
     /* Now the only way base can still be NULL is if type is
      * &PyBaseObject_Type. */
@@ -6249,6 +6240,50 @@ type_ready_add_subclasses(PyTypeObject *type)
 }
 
 
+// Set tp_new and the "__new__" key in the type dictionary.
+// Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag.
+static int
+type_ready_set_new(PyTypeObject *type)
+{
+    PyTypeObject *base = type->tp_base;
+    /* The condition below could use some explanation.
+
+       It appears that tp_new is not inherited for static types whose base
+       class is 'object'; this seems to be a precaution so that old extension
+       types don't suddenly become callable (object.__new__ wouldn't insure the
+       invariants that the extension type's own factory function ensures).
+
+       Heap types, of course, are under our control, so they do inherit tp_new;
+       static extension types that specify some other built-in type as the
+       default also inherit object.__new__. */
+    if (type->tp_new == NULL
+        && base == &PyBaseObject_Type
+        && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
+    {
+        type->tp_flags |= Py_TPFLAGS_DISALLOW_INSTANTIATION;
+    }
+
+    if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
+        if (type->tp_new != NULL) {
+            // If "__new__" key does not exists in the type dictionary,
+            // set it to tp_new_wrapper().
+            if (add_tp_new_wrapper(type) < 0) {
+                return -1;
+            }
+        }
+        else {
+            // tp_new is NULL: inherit tp_new from base
+            type->tp_new = base->tp_new;
+        }
+    }
+    else {
+        // Py_TPFLAGS_DISALLOW_INSTANTIATION sets tp_new to NULL
+        type->tp_new = NULL;
+    }
+    return 0;
+}
+
+
 static int
 type_ready(PyTypeObject *type)
 {
@@ -6275,6 +6310,9 @@ type_ready(PyTypeObject *type)
     if (type_ready_mro(type) < 0) {
         return -1;
     }
+    if (type_ready_set_new(type) < 0) {
+        return -1;
+    }
     if (type_ready_fill_dict(type) < 0) {
         return -1;
     }
@@ -6898,8 +6936,8 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
                      "__new__() called with non-type 'self'");
         return NULL;
     }
-
     type = (PyTypeObject *)self;
+
     if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) {
         PyErr_Format(PyExc_TypeError,
                      "%s.__new__(): not enough arguments",
@@ -6961,16 +6999,18 @@ static struct PyMethodDef tp_new_methoddef[] = {
 static int
 add_tp_new_wrapper(PyTypeObject *type)
 {
-    PyObject *func;
-
     int r = _PyDict_ContainsId(type->tp_dict, &PyId___new__);
-    if (r > 0)
+    if (r > 0) {
         return 0;
-    if (r < 0)
+    }
+    if (r < 0) {
         return -1;
-    func = PyCFunction_NewEx(tp_new_methoddef, (PyObject *)type, NULL);
-    if (func == NULL)
+    }
+
+    PyObject *func = PyCFunction_NewEx(tp_new_methoddef, (PyObject *)type, NULL);
+    if (func == NULL) {
         return -1;
+    }
     r = _PyDict_SetItemId(type->tp_dict, &PyId___new__, func);
     Py_DECREF(func);
     return r;
@@ -8558,11 +8598,6 @@ add_operators(PyTypeObject *type)
             Py_DECREF(descr);
         }
     }
-    if (type->tp_new != NULL) {
-        if (add_tp_new_wrapper(type) < 0) {
-            return -1;
-        }
-    }
     return 0;
 }
 
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 911c2d967b010..36297ff82e1c3 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -2810,56 +2810,35 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
 
     /* version_info */
     if (VersionInfoType.tp_name == NULL) {
-        if (PyStructSequence_InitType2(&VersionInfoType,
-                                       &version_info_desc) < 0) {
+        if (_PyStructSequence_InitType(&VersionInfoType,
+                                       &version_info_desc,
+                                       Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
             goto type_init_failed;
         }
     }
     version_info = make_version_info(tstate);
     SET_SYS("version_info", version_info);
-    /* prevent user from creating new instances */
-    VersionInfoType.tp_init = NULL;
-    VersionInfoType.tp_new = NULL;
-    res = PyDict_DelItemString(VersionInfoType.tp_dict, "__new__");
-    if (res < 0 && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
-        _PyErr_Clear(tstate);
-    }
 
     /* implementation */
     SET_SYS("implementation", make_impl_info(version_info));
 
     // sys.flags: updated in-place later by _PySys_UpdateConfig()
     if (FlagsType.tp_name == 0) {
-        if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) {
+        if (_PyStructSequence_InitType(&FlagsType, &flags_desc,
+                                       Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
             goto type_init_failed;
         }
     }
     SET_SYS("flags", make_flags(tstate->interp));
-    /* prevent user from creating new instances */
-    FlagsType.tp_init = NULL;
-    FlagsType.tp_new = NULL;
-    res = PyDict_DelItemString(FlagsType.tp_dict, "__new__");
-    if (res < 0) {
-        if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
-            goto err_occurred;
-        }
-        _PyErr_Clear(tstate);
-    }
 
 #if defined(MS_WINDOWS)
     /* getwindowsversion */
-    if (WindowsVersionType.tp_name == 0)
-        if (PyStructSequence_InitType2(&WindowsVersionType,
-                                       &windows_version_desc) < 0) {
+    if (WindowsVersionType.tp_name == 0) {
+        if (_PyStructSequence_InitType(&WindowsVersionType,
+                                       &windows_version_desc,
+                                       Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
             goto type_init_failed;
         }
-    /* prevent user from creating new instances */
-    WindowsVersionType.tp_init = NULL;
-    WindowsVersionType.tp_new = NULL;
-    assert(!_PyErr_Occurred(tstate));
-    res = PyDict_DelItemString(WindowsVersionType.tp_dict, "__new__");
-    if (res < 0 && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
-        _PyErr_Clear(tstate);
     }
 #endif
 



More information about the Python-checkins mailing list