|
|
|
@ -3164,6 +3164,24 @@ _PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name) |
|
|
|
return _PyType_Lookup(type, oname); |
|
|
|
} |
|
|
|
|
|
|
|
/* Check if the "readied" PyUnicode name |
|
|
|
is a double-underscore special name. */ |
|
|
|
static int |
|
|
|
is_dunder_name(PyObject *name) |
|
|
|
{ |
|
|
|
Py_ssize_t length = PyUnicode_GET_LENGTH(name); |
|
|
|
int kind = PyUnicode_KIND(name); |
|
|
|
/* Special names contain at least "__x__" and are always ASCII. */ |
|
|
|
if (length > 4 && kind == PyUnicode_1BYTE_KIND) { |
|
|
|
Py_UCS1 *characters = PyUnicode_1BYTE_DATA(name); |
|
|
|
return ( |
|
|
|
((characters[length-2] == '_') && (characters[length-1] == '_')) && |
|
|
|
((characters[0] == '_') && (characters[1] == '_')) |
|
|
|
); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* This is similar to PyObject_GenericGetAttr(), |
|
|
|
but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ |
|
|
|
static PyObject * |
|
|
|
@ -3275,12 +3293,14 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) |
|
|
|
if (name == NULL) |
|
|
|
return -1; |
|
|
|
} |
|
|
|
PyUnicode_InternInPlace(&name); |
|
|
|
if (!PyUnicode_CHECK_INTERNED(name)) { |
|
|
|
PyErr_SetString(PyExc_MemoryError, |
|
|
|
"Out of memory interning an attribute name"); |
|
|
|
Py_DECREF(name); |
|
|
|
return -1; |
|
|
|
PyUnicode_InternInPlace(&name); |
|
|
|
if (!PyUnicode_CHECK_INTERNED(name)) { |
|
|
|
PyErr_SetString(PyExc_MemoryError, |
|
|
|
"Out of memory interning an attribute name"); |
|
|
|
Py_DECREF(name); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
@ -3289,7 +3309,16 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) |
|
|
|
} |
|
|
|
res = _PyObject_GenericSetAttrWithDict((PyObject *)type, name, value, NULL); |
|
|
|
if (res == 0) { |
|
|
|
res = update_slot(type, name); |
|
|
|
/* Clear the VALID_VERSION flag of 'type' and all its |
|
|
|
subclasses. This could possibly be unified with the |
|
|
|
update_subclasses() recursion in update_slot(), but carefully: |
|
|
|
they each have their own conditions on which to stop |
|
|
|
recursing into subclasses. */ |
|
|
|
PyType_Modified(type); |
|
|
|
|
|
|
|
if (is_dunder_name(name)) { |
|
|
|
res = update_slot(type, name); |
|
|
|
} |
|
|
|
assert(_PyType_CheckConsistency(type)); |
|
|
|
} |
|
|
|
Py_DECREF(name); |
|
|
|
@ -7236,13 +7265,6 @@ update_slot(PyTypeObject *type, PyObject *name) |
|
|
|
assert(PyUnicode_CheckExact(name)); |
|
|
|
assert(PyUnicode_CHECK_INTERNED(name)); |
|
|
|
|
|
|
|
/* Clear the VALID_VERSION flag of 'type' and all its |
|
|
|
subclasses. This could possibly be unified with the |
|
|
|
update_subclasses() recursion below, but carefully: |
|
|
|
they each have their own conditions on which to stop |
|
|
|
recursing into subclasses. */ |
|
|
|
PyType_Modified(type); |
|
|
|
|
|
|
|
init_slotdefs(); |
|
|
|
pp = ptrs; |
|
|
|
for (p = slotdefs; p->name; p++) { |
|
|
|
@ -7281,6 +7303,9 @@ update_all_slots(PyTypeObject* type) |
|
|
|
{ |
|
|
|
slotdef *p; |
|
|
|
|
|
|
|
/* Clear the VALID_VERSION flag of 'type' and all its subclasses. */ |
|
|
|
PyType_Modified(type); |
|
|
|
|
|
|
|
init_slotdefs(); |
|
|
|
for (p = slotdefs; p->name; p++) { |
|
|
|
/* update_slot returns int but can't actually fail */ |
|
|
|
|