summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2012-02-20 00:59:10 (GMT)
committerBenjamin Peterson <benjamin@python.org>2012-02-20 00:59:10 (GMT)
commit8eb1269c346fa860acce9459c0bed065ffccd3ce (patch)
tree186cdf221973397a4968a4c16d78d3298ff2011b
parent4a57846efe1419843a5e1a35a9f098bab6b066c9 (diff)
downloadcpython-8eb1269c346fa860acce9459c0bed065ffccd3ce.zip
cpython-8eb1269c346fa860acce9459c0bed065ffccd3ce.tar.gz
cpython-8eb1269c346fa860acce9459c0bed065ffccd3ce.tar.bz2
add generic implementation of a __dict__ descriptor for C types
-rw-r--r--Doc/c-api/object.rst12
-rw-r--r--Doc/c-api/type.rst1
-rw-r--r--Include/object.h2
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/object.c42
-rw-r--r--Objects/typeobject.c22
6 files changed, 64 insertions, 19 deletions
diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst
index 88ba5ac..43768f3 100644
--- a/Doc/c-api/object.rst
+++ b/Doc/c-api/object.rst
@@ -101,6 +101,18 @@ Object Protocol
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)
Compare the values of *o1* and *o2* using the operation specified by *opid*,
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index b3386ea..f8e01c0 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -77,7 +77,6 @@ Type Objects
XXX: Document.
-
.. c:function:: int PyType_Ready(PyTypeObject *type)
Finalize a type object. This should be called on all type objects to finish
diff --git a/Include/object.h b/Include/object.h
index 6907a44..844ff9f 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -516,6 +516,8 @@ PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *);
PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
PyAPI_FUNC(int) PyObject_GenericSetAttr(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_HashNotImplemented(PyObject *);
PyAPI_FUNC(int) PyObject_IsTrue(PyObject *);
diff --git a/Misc/NEWS b/Misc/NEWS
index 5c24b99..fbeb177 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2253,6 +2253,10 @@ Tests
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:
PyDateTime_DELTA_GET_DAYS, PyDateTime_DELTA_GET_SECONDS,
PyDateTime_DELTA_GET_MICROSECONDS.
diff --git a/Objects/object.c b/Objects/object.c
index 86f5e1b..8134825 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1210,6 +1210,48 @@ PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value)
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.
Return -1 if an error occurred */
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 495cc6d..a5abcce 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1759,8 +1759,6 @@ raise_dict_descr_error(PyObject *obj)
static PyObject *
subtype_dict(PyObject *obj, void *context)
{
- PyObject **dictptr;
- PyObject *dict;
PyTypeObject *base;
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)));
}
-
- 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;
+ return PyObject_GenericGetDict(obj, context);
}
static int
subtype_setdict(PyObject *obj, PyObject *value, void *context)
{
- PyObject **dictptr;
- PyObject *dict;
+ PyObject *dict, **dictptr;
PyTypeObject *base;
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);
}
-
+ /* Almost like PyObject_GenericSetDict, but allow __dict__ to be deleted. */
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
PyErr_SetString(PyExc_AttributeError,
"This object has no __dict__");
return -1;
}
- if (value != NULL && !PyDict_Check(value)) {
+ if (!PyDict_Check(value)) {
PyErr_Format(PyExc_TypeError,
"__dict__ must be set to a dictionary, "
"not a '%.200s'", Py_TYPE(value)->tp_name);