]> granicus.if.org Git - python/commitdiff
add generic implementation of a __dict__ descriptor for C types
authorBenjamin Peterson <benjamin@python.org>
Mon, 20 Feb 2012 00:59:10 +0000 (19:59 -0500)
committerBenjamin Peterson <benjamin@python.org>
Mon, 20 Feb 2012 00:59:10 +0000 (19:59 -0500)
Doc/c-api/object.rst
Doc/c-api/type.rst
Include/object.h
Misc/NEWS
Objects/object.c
Objects/typeobject.c

index 88ba5ac0c4efcb8491daa41fc210d6e3c9f30c90..43768f3959ee784968b03330f385761ec7326bab 100644 (file)
@@ -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*,
index b3386eaa8b524a9ed9bfe27b23f2819764277908..f8e01c068717bc99ccabbc95fcf740c4a0366f82 100644 (file)
@@ -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
index 6907a4464c29474ae9683c1100a0612f5321c1ae..844ff9f14a871bd431d0b6292c3c48bef06dea75 100644 (file)
@@ -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 *);
index 5c24b99c8c18b344ae7b2e172ab7fbc7fd81542d..fbeb1770ffec241a3e1a86818c4d6b52f2fa676e 100644 (file)
--- 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.
index 86f5e1b7a4b4353c3509964c6a2fa58f1348882c..81348258a4a091d0d2c3761e79e0d641584cfbc4 100644 (file)
@@ -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 */
index 495cc6dee20d42d4a862849c1294a15a1c3411e7..a5abcce4a0872264bfd5346354c15661fc24c785 100644 (file)
@@ -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);