mirror of https://github.com/python/cpython
add generic implementation of a __dict__ descriptor for C types
This commit is contained in:
parent
4a57846efe
commit
8eb1269c34
|
@ -101,6 +101,18 @@ Object Protocol
|
||||||
This is the equivalent of the Python statement ``del o.attr_name``.
|
This is the equivalent of the Python statement ``del o.attr_name``.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyType_GenericGetDict(PyObject *o, void *context)
|
||||||
|
|
||||||
|
A generic implementation for the getter of a ``__dict__`` descriptor. It
|
||||||
|
creates the dictionary if necessary.
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyType_GenericSetDict(PyObject *o, void *context)
|
||||||
|
|
||||||
|
A generic implementation for the setter of a ``__dict__`` descriptor. This
|
||||||
|
implementation does not allow the dictionary to be deleted.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyObject_RichCompare(PyObject *o1, PyObject *o2, int opid)
|
.. c:function:: PyObject* PyObject_RichCompare(PyObject *o1, PyObject *o2, int opid)
|
||||||
|
|
||||||
Compare the values of *o1* and *o2* using the operation specified by *opid*,
|
Compare the values of *o1* and *o2* using the operation specified by *opid*,
|
||||||
|
|
|
@ -77,7 +77,6 @@ Type Objects
|
||||||
|
|
||||||
XXX: Document.
|
XXX: Document.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: int PyType_Ready(PyTypeObject *type)
|
.. c:function:: int PyType_Ready(PyTypeObject *type)
|
||||||
|
|
||||||
Finalize a type object. This should be called on all type objects to finish
|
Finalize a type object. This should be called on all type objects to finish
|
||||||
|
|
|
@ -516,6 +516,8 @@ PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *);
|
||||||
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
|
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
|
||||||
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
|
PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
|
||||||
PyObject *, PyObject *);
|
PyObject *, PyObject *);
|
||||||
|
PyAPI_FUNC(PyObject *) PyObject_GenericGetDict(PyObject *, void *);
|
||||||
|
PyAPI_FUNC(int) PyObject_GenericSetDict(PyObject *, PyObject *, void *);
|
||||||
PyAPI_FUNC(Py_hash_t) PyObject_Hash(PyObject *);
|
PyAPI_FUNC(Py_hash_t) PyObject_Hash(PyObject *);
|
||||||
PyAPI_FUNC(Py_hash_t) PyObject_HashNotImplemented(PyObject *);
|
PyAPI_FUNC(Py_hash_t) PyObject_HashNotImplemented(PyObject *);
|
||||||
PyAPI_FUNC(int) PyObject_IsTrue(PyObject *);
|
PyAPI_FUNC(int) PyObject_IsTrue(PyObject *);
|
||||||
|
|
|
@ -2253,6 +2253,10 @@ Tests
|
||||||
C-API
|
C-API
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
- Add PyObject_GenericGetDict and PyObject_GeneriSetDict. They are generic
|
||||||
|
implementations for the getter and setter of a ``__dict__`` descriptor of C
|
||||||
|
types.
|
||||||
|
|
||||||
- Issue #13727: Add 3 macros to access PyDateTime_Delta members:
|
- Issue #13727: Add 3 macros to access PyDateTime_Delta members:
|
||||||
PyDateTime_DELTA_GET_DAYS, PyDateTime_DELTA_GET_SECONDS,
|
PyDateTime_DELTA_GET_DAYS, PyDateTime_DELTA_GET_SECONDS,
|
||||||
PyDateTime_DELTA_GET_MICROSECONDS.
|
PyDateTime_DELTA_GET_MICROSECONDS.
|
||||||
|
|
|
@ -1210,6 +1210,48 @@ PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
|
||||||
return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL);
|
return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyObject_GenericGetDict(PyObject *obj, void *context)
|
||||||
|
{
|
||||||
|
PyObject *dict, **dictptr = _PyObject_GetDictPtr(obj);
|
||||||
|
if (dictptr == NULL) {
|
||||||
|
PyErr_SetString(PyExc_AttributeError,
|
||||||
|
"This object has no __dict__");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dict = *dictptr;
|
||||||
|
if (dict == NULL)
|
||||||
|
*dictptr = dict = PyDict_New();
|
||||||
|
Py_XINCREF(dict);
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context)
|
||||||
|
{
|
||||||
|
PyObject *dict, **dictptr = _PyObject_GetDictPtr(obj);
|
||||||
|
if (dictptr == NULL) {
|
||||||
|
PyErr_SetString(PyExc_AttributeError,
|
||||||
|
"This object has no __dict__");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (value == NULL) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "cannot delete __dict__");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!PyDict_Check(value)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"__dict__ must be set to a dictionary, "
|
||||||
|
"not a '%.200s'", Py_TYPE(value)->tp_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dict = *dictptr;
|
||||||
|
Py_XINCREF(value);
|
||||||
|
*dictptr = value;
|
||||||
|
Py_XDECREF(dict);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Test a value used as condition, e.g., in a for or if statement.
|
/* Test a value used as condition, e.g., in a for or if statement.
|
||||||
Return -1 if an error occurred */
|
Return -1 if an error occurred */
|
||||||
|
|
|
@ -1759,8 +1759,6 @@ raise_dict_descr_error(PyObject *obj)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
subtype_dict(PyObject *obj, void *context)
|
subtype_dict(PyObject *obj, void *context)
|
||||||
{
|
{
|
||||||
PyObject **dictptr;
|
|
||||||
PyObject *dict;
|
|
||||||
PyTypeObject *base;
|
PyTypeObject *base;
|
||||||
|
|
||||||
base = get_builtin_base_with_dict(Py_TYPE(obj));
|
base = get_builtin_base_with_dict(Py_TYPE(obj));
|
||||||
|
@ -1778,25 +1776,13 @@ subtype_dict(PyObject *obj, void *context)
|
||||||
}
|
}
|
||||||
return func(descr, obj, (PyObject *)(Py_TYPE(obj)));
|
return func(descr, obj, (PyObject *)(Py_TYPE(obj)));
|
||||||
}
|
}
|
||||||
|
return PyObject_GenericGetDict(obj, context);
|
||||||
dictptr = _PyObject_GetDictPtr(obj);
|
|
||||||
if (dictptr == NULL) {
|
|
||||||
PyErr_SetString(PyExc_AttributeError,
|
|
||||||
"This object has no __dict__");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
dict = *dictptr;
|
|
||||||
if (dict == NULL)
|
|
||||||
*dictptr = dict = PyDict_New();
|
|
||||||
Py_XINCREF(dict);
|
|
||||||
return dict;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
subtype_setdict(PyObject *obj, PyObject *value, void *context)
|
subtype_setdict(PyObject *obj, PyObject *value, void *context)
|
||||||
{
|
{
|
||||||
PyObject **dictptr;
|
PyObject *dict, **dictptr;
|
||||||
PyObject *dict;
|
|
||||||
PyTypeObject *base;
|
PyTypeObject *base;
|
||||||
|
|
||||||
base = get_builtin_base_with_dict(Py_TYPE(obj));
|
base = get_builtin_base_with_dict(Py_TYPE(obj));
|
||||||
|
@ -1814,14 +1800,14 @@ subtype_setdict(PyObject *obj, PyObject *value, void *context)
|
||||||
}
|
}
|
||||||
return func(descr, obj, value);
|
return func(descr, obj, value);
|
||||||
}
|
}
|
||||||
|
/* Almost like PyObject_GenericSetDict, but allow __dict__ to be deleted. */
|
||||||
dictptr = _PyObject_GetDictPtr(obj);
|
dictptr = _PyObject_GetDictPtr(obj);
|
||||||
if (dictptr == NULL) {
|
if (dictptr == NULL) {
|
||||||
PyErr_SetString(PyExc_AttributeError,
|
PyErr_SetString(PyExc_AttributeError,
|
||||||
"This object has no __dict__");
|
"This object has no __dict__");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (value != NULL && !PyDict_Check(value)) {
|
if (!PyDict_Check(value)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"__dict__ must be set to a dictionary, "
|
"__dict__ must be set to a dictionary, "
|
||||||
"not a '%.200s'", Py_TYPE(value)->tp_name);
|
"not a '%.200s'", Py_TYPE(value)->tp_name);
|
||||||
|
|
Loading…
Reference in New Issue