mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
b73b5fb9ea
commit
3bb09947ec
|
@ -1199,6 +1199,25 @@ and :c:type:`PyType_Type` effectively act as defaults.)
|
||||||
|
|
||||||
.. versionadded:: 3.10
|
.. 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
|
.. 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
|
in :c:member:`~PyTypeObject.tp_new`, while for mutable types, most initialization should be
|
||||||
deferred to :c:member:`~PyTypeObject.tp_init`.
|
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:**
|
**Inheritance:**
|
||||||
|
|
||||||
This field is inherited by subtypes, except it is not inherited by
|
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
|
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 {
|
typedef struct {
|
||||||
PyUnicodeObject raw;
|
PyUnicodeObject raw;
|
||||||
|
@ -2609,8 +2632,7 @@ to create instances (e.g. uses a separate factory func)::
|
||||||
.tp_basicsize = sizeof(MyStr),
|
.tp_basicsize = sizeof(MyStr),
|
||||||
.tp_base = NULL, // set to &PyUnicode_Type in module init
|
.tp_base = NULL, // set to &PyUnicode_Type in module init
|
||||||
.tp_doc = "my custom str",
|
.tp_doc = "my custom str",
|
||||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
||||||
.tp_new = NULL,
|
|
||||||
.tp_repr = (reprfunc)myobj_repr,
|
.tp_repr = (reprfunc)myobj_repr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1708,6 +1708,10 @@ New Features
|
||||||
These functions allow to activate, deactivate and query the state of the garbage collector from C code without
|
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.
|
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
|
Porting to Python 3.10
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -327,6 +327,10 @@ given type object has a specified feature.
|
||||||
#define Py_TPFLAGS_MAPPING (1 << 6)
|
#define Py_TPFLAGS_MAPPING (1 << 6)
|
||||||
#endif
|
#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 */
|
/* Set if the type object is immutable: type attributes cannot be set nor deleted */
|
||||||
#define Py_TPFLAGS_IMMUTABLETYPE (1UL << 8)
|
#define Py_TPFLAGS_IMMUTABLETYPE (1UL << 8)
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,12 @@ PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
|
||||||
PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type,
|
PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type,
|
||||||
PyStructSequence_Desc *desc);
|
PyStructSequence_Desc *desc);
|
||||||
#endif
|
#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(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc);
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type);
|
PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type);
|
||||||
|
|
|
@ -605,11 +605,12 @@ class SysModuleTest(unittest.TestCase):
|
||||||
def assert_raise_on_new_sys_type(self, sys_attr):
|
def assert_raise_on_new_sys_type(self, sys_attr):
|
||||||
# Users are intentionally prevented from creating new instances of
|
# Users are intentionally prevented from creating new instances of
|
||||||
# sys.flags, sys.version_info, and sys.getwindowsversion.
|
# sys.flags, sys.version_info, and sys.getwindowsversion.
|
||||||
|
arg = sys_attr
|
||||||
attr_type = type(sys_attr)
|
attr_type = type(sys_attr)
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
attr_type()
|
attr_type(arg)
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
attr_type.__new__(attr_type)
|
attr_type.__new__(attr_type, arg)
|
||||||
|
|
||||||
def test_sys_flags_no_instantiation(self):
|
def test_sys_flags_no_instantiation(self):
|
||||||
self.assert_raise_on_new_sys_type(sys.flags)
|
self.assert_raise_on_new_sys_type(sys.flags)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add a new :c:data:`Py_TPFLAGS_DISALLOW_INSTANTIATION` type flag to disallow
|
||||||
|
creating type instances. Patch by Victor Stinner.
|
|
@ -520,7 +520,7 @@ static PyType_Slot PyCursesPanel_Type_slots[] = {
|
||||||
static PyType_Spec PyCursesPanel_Type_spec = {
|
static PyType_Spec PyCursesPanel_Type_spec = {
|
||||||
.name = "_curses_panel.panel",
|
.name = "_curses_panel.panel",
|
||||||
.basicsize = sizeof(PyCursesPanelObject),
|
.basicsize = sizeof(PyCursesPanelObject),
|
||||||
.flags = Py_TPFLAGS_DEFAULT,
|
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
||||||
.slots = PyCursesPanel_Type_slots
|
.slots = PyCursesPanel_Type_slots
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -656,7 +656,6 @@ _curses_panel_exec(PyObject *mod)
|
||||||
if (state->PyCursesPanel_Type == NULL) {
|
if (state->PyCursesPanel_Type == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
((PyTypeObject *)state->PyCursesPanel_Type)->tp_new = NULL;
|
|
||||||
|
|
||||||
if (PyModule_AddType(mod, state->PyCursesPanel_Type) < 0) {
|
if (PyModule_AddType(mod, state->PyCursesPanel_Type) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -4793,25 +4793,18 @@ PyInit__curses(void)
|
||||||
#ifdef NCURSES_VERSION
|
#ifdef NCURSES_VERSION
|
||||||
/* ncurses_version */
|
/* ncurses_version */
|
||||||
if (NcursesVersionType.tp_name == NULL) {
|
if (NcursesVersionType.tp_name == NULL) {
|
||||||
if (PyStructSequence_InitType2(&NcursesVersionType,
|
if (_PyStructSequence_InitType(&NcursesVersionType,
|
||||||
&ncurses_version_desc) < 0)
|
&ncurses_version_desc,
|
||||||
|
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
v = make_ncurses_version();
|
v = make_ncurses_version();
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyDict_SetItemString(d, "ncurses_version", v);
|
PyDict_SetItemString(d, "ncurses_version", v);
|
||||||
Py_DECREF(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 */
|
#endif /* NCURSES_VERSION */
|
||||||
|
|
||||||
SetDictInt("ERR", ERR);
|
SetDictInt("ERR", ERR);
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ static PyType_Spec PyTclObject_Type_spec = {
|
||||||
"_tkinter.Tcl_Obj",
|
"_tkinter.Tcl_Obj",
|
||||||
sizeof(PyTclObject),
|
sizeof(PyTclObject),
|
||||||
0,
|
0,
|
||||||
Py_TPFLAGS_DEFAULT,
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
||||||
PyTclObject_Type_slots,
|
PyTclObject_Type_slots,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3294,7 +3294,7 @@ static PyType_Spec Tktt_Type_spec = {
|
||||||
"_tkinter.tktimertoken",
|
"_tkinter.tktimertoken",
|
||||||
sizeof(TkttObject),
|
sizeof(TkttObject),
|
||||||
0,
|
0,
|
||||||
Py_TPFLAGS_DEFAULT,
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
||||||
Tktt_Type_slots,
|
Tktt_Type_slots,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3349,7 +3349,7 @@ static PyType_Spec Tkapp_Type_spec = {
|
||||||
"_tkinter.tkapp",
|
"_tkinter.tkapp",
|
||||||
sizeof(TkappObject),
|
sizeof(TkappObject),
|
||||||
0,
|
0,
|
||||||
Py_TPFLAGS_DEFAULT,
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
||||||
Tkapp_Type_slots,
|
Tkapp_Type_slots,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3537,7 +3537,6 @@ PyInit__tkinter(void)
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
((PyTypeObject *)o)->tp_new = NULL;
|
|
||||||
if (PyModule_AddObject(m, "TkappType", o)) {
|
if (PyModule_AddObject(m, "TkappType", o)) {
|
||||||
Py_DECREF(o);
|
Py_DECREF(o);
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
|
@ -3550,7 +3549,6 @@ PyInit__tkinter(void)
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
((PyTypeObject *)o)->tp_new = NULL;
|
|
||||||
if (PyModule_AddObject(m, "TkttType", o)) {
|
if (PyModule_AddObject(m, "TkttType", o)) {
|
||||||
Py_DECREF(o);
|
Py_DECREF(o);
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
|
@ -3563,7 +3561,6 @@ PyInit__tkinter(void)
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
((PyTypeObject *)o)->tp_new = NULL;
|
|
||||||
if (PyModule_AddObject(m, "Tcl_Obj", o)) {
|
if (PyModule_AddObject(m, "Tcl_Obj", o)) {
|
||||||
Py_DECREF(o);
|
Py_DECREF(o);
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
|
|
|
@ -1780,7 +1780,12 @@ static PyTypeObject ChannelIDtype = {
|
||||||
0, /* tp_getattro */
|
0, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
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 */
|
channelid_doc, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
0, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
|
@ -1791,19 +1796,6 @@ static PyTypeObject ChannelIDtype = {
|
||||||
0, /* tp_methods */
|
0, /* tp_methods */
|
||||||
0, /* tp_members */
|
0, /* tp_members */
|
||||||
channelid_getsets, /* tp_getset */
|
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 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -459,8 +459,10 @@ initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
|
||||||
members[k].name = NULL;
|
members[k].name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
|
_PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
|
||||||
|
unsigned long tp_flags)
|
||||||
{
|
{
|
||||||
PyMemberDef *members;
|
PyMemberDef *members;
|
||||||
Py_ssize_t n_members, n_unnamed_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_base = &PyTuple_Type;
|
||||||
type->tp_methods = structseq_methods;
|
type->tp_methods = structseq_methods;
|
||||||
type->tp_new = structseq_new;
|
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;
|
type->tp_traverse = (traverseproc) structseq_traverse;
|
||||||
|
|
||||||
n_members = count_members(desc, &n_unnamed_members);
|
n_members = count_members(desc, &n_unnamed_members);
|
||||||
|
@ -516,6 +518,12 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
|
||||||
|
{
|
||||||
|
return _PyStructSequence_InitType(type, desc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
|
PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -158,6 +158,11 @@ _PyType_CheckConsistency(PyTypeObject *type)
|
||||||
CHECK(!(type->tp_flags & Py_TPFLAGS_READYING));
|
CHECK(!(type->tp_flags & Py_TPFLAGS_READYING));
|
||||||
CHECK(type->tp_dict != NULL);
|
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;
|
return 1;
|
||||||
#undef CHECK
|
#undef CHECK
|
||||||
}
|
}
|
||||||
|
@ -1111,8 +1116,7 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
if (type->tp_new == NULL) {
|
if (type->tp_new == NULL) {
|
||||||
_PyErr_Format(tstate, PyExc_TypeError,
|
_PyErr_Format(tstate, PyExc_TypeError,
|
||||||
"cannot create '%.100s' instances",
|
"cannot create '%s' instances", type->tp_name);
|
||||||
type->tp_name);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3185,6 +3189,8 @@ type_new_impl(type_new_ctx *ctx)
|
||||||
if (type_new_init_subclass(type, ctx->kwds) < 0) {
|
if (type_new_init_subclass(type, ctx->kwds) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(_PyType_CheckConsistency(type));
|
||||||
return (PyObject *)type;
|
return (PyObject *)type;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -5651,7 +5657,6 @@ type_add_getset(PyTypeObject *type)
|
||||||
static void
|
static void
|
||||||
inherit_special(PyTypeObject *type, PyTypeObject *base)
|
inherit_special(PyTypeObject *type, PyTypeObject *base)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Copying tp_traverse and tp_clear is connected to the GC flags */
|
/* Copying tp_traverse and tp_clear is connected to the GC flags */
|
||||||
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
|
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
|
||||||
(base->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)
|
if (type->tp_clear == NULL)
|
||||||
type->tp_clear = base->tp_clear;
|
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)
|
if (type->tp_basicsize == 0)
|
||||||
type->tp_basicsize = base->tp_basicsize;
|
type->tp_basicsize = base->tp_basicsize;
|
||||||
|
|
||||||
|
@ -5941,6 +5930,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_operators(PyTypeObject *);
|
static int add_operators(PyTypeObject *);
|
||||||
|
static int add_tp_new_wrapper(PyTypeObject *type);
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -5991,6 +5981,7 @@ type_ready_set_bases(PyTypeObject *type)
|
||||||
type->tp_base = base;
|
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
|
/* Now the only way base can still be NULL is if type is
|
||||||
* &PyBaseObject_Type. */
|
* &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
|
static int
|
||||||
type_ready(PyTypeObject *type)
|
type_ready(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
|
@ -6275,6 +6310,9 @@ type_ready(PyTypeObject *type)
|
||||||
if (type_ready_mro(type) < 0) {
|
if (type_ready_mro(type) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (type_ready_set_new(type) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (type_ready_fill_dict(type) < 0) {
|
if (type_ready_fill_dict(type) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -6898,8 +6936,8 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
"__new__() called with non-type 'self'");
|
"__new__() called with non-type 'self'");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
type = (PyTypeObject *)self;
|
type = (PyTypeObject *)self;
|
||||||
|
|
||||||
if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) {
|
if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%s.__new__(): not enough arguments",
|
"%s.__new__(): not enough arguments",
|
||||||
|
@ -6961,16 +6999,18 @@ static struct PyMethodDef tp_new_methoddef[] = {
|
||||||
static int
|
static int
|
||||||
add_tp_new_wrapper(PyTypeObject *type)
|
add_tp_new_wrapper(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
PyObject *func;
|
|
||||||
|
|
||||||
int r = _PyDict_ContainsId(type->tp_dict, &PyId___new__);
|
int r = _PyDict_ContainsId(type->tp_dict, &PyId___new__);
|
||||||
if (r > 0)
|
if (r > 0) {
|
||||||
return 0;
|
return 0;
|
||||||
if (r < 0)
|
}
|
||||||
|
if (r < 0) {
|
||||||
return -1;
|
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;
|
return -1;
|
||||||
|
}
|
||||||
r = _PyDict_SetItemId(type->tp_dict, &PyId___new__, func);
|
r = _PyDict_SetItemId(type->tp_dict, &PyId___new__, func);
|
||||||
Py_DECREF(func);
|
Py_DECREF(func);
|
||||||
return r;
|
return r;
|
||||||
|
@ -8558,11 +8598,6 @@ add_operators(PyTypeObject *type)
|
||||||
Py_DECREF(descr);
|
Py_DECREF(descr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type->tp_new != NULL) {
|
|
||||||
if (add_tp_new_wrapper(type) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2810,56 +2810,35 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
|
||||||
|
|
||||||
/* version_info */
|
/* version_info */
|
||||||
if (VersionInfoType.tp_name == NULL) {
|
if (VersionInfoType.tp_name == NULL) {
|
||||||
if (PyStructSequence_InitType2(&VersionInfoType,
|
if (_PyStructSequence_InitType(&VersionInfoType,
|
||||||
&version_info_desc) < 0) {
|
&version_info_desc,
|
||||||
|
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
|
||||||
goto type_init_failed;
|
goto type_init_failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
version_info = make_version_info(tstate);
|
version_info = make_version_info(tstate);
|
||||||
SET_SYS("version_info", version_info);
|
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 */
|
/* implementation */
|
||||||
SET_SYS("implementation", make_impl_info(version_info));
|
SET_SYS("implementation", make_impl_info(version_info));
|
||||||
|
|
||||||
// sys.flags: updated in-place later by _PySys_UpdateConfig()
|
// sys.flags: updated in-place later by _PySys_UpdateConfig()
|
||||||
if (FlagsType.tp_name == 0) {
|
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;
|
goto type_init_failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SET_SYS("flags", make_flags(tstate->interp));
|
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)
|
#if defined(MS_WINDOWS)
|
||||||
/* getwindowsversion */
|
/* getwindowsversion */
|
||||||
if (WindowsVersionType.tp_name == 0)
|
if (WindowsVersionType.tp_name == 0) {
|
||||||
if (PyStructSequence_InitType2(&WindowsVersionType,
|
if (_PyStructSequence_InitType(&WindowsVersionType,
|
||||||
&windows_version_desc) < 0) {
|
&windows_version_desc,
|
||||||
|
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
|
||||||
goto type_init_failed;
|
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
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue