summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2012-04-15 22:16:30 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2012-04-15 22:16:30 (GMT)
commit0db176f8f6cfaf3277e6ef41d92b09a01b263f27 (patch)
tree9c881aaab525015223b7219c8fa12910e66354e9 /Objects
parent8a1d04c64372d4706572671a21ff9d3e4a6374ca (diff)
downloadcpython-0db176f8f6cfaf3277e6ef41d92b09a01b263f27.zip
cpython-0db176f8f6cfaf3277e6ef41d92b09a01b263f27.tar.gz
cpython-0db176f8f6cfaf3277e6ef41d92b09a01b263f27.tar.bz2
Issue #14386: Expose the dict_proxy internal type as types.MappingProxyType
Diffstat (limited to 'Objects')
-rw-r--r--Objects/descrobject.c170
1 files changed, 110 insertions, 60 deletions
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index ecf372a..b679c4bc 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -698,41 +698,44 @@ PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
}
-/* --- Readonly proxy for dictionaries (actually any mapping) --- */
+/* --- mappingproxy: read-only proxy for mappings --- */
/* This has no reason to be in this file except that adding new files is a
bit of a pain */
typedef struct {
PyObject_HEAD
- PyObject *dict;
-} proxyobject;
+ PyObject *mapping;
+} mappingproxyobject;
static Py_ssize_t
-proxy_len(proxyobject *pp)
+mappingproxy_len(mappingproxyobject *pp)
{
- return PyObject_Size(pp->dict);
+ return PyObject_Size(pp->mapping);
}
static PyObject *
-proxy_getitem(proxyobject *pp, PyObject *key)
+mappingproxy_getitem(mappingproxyobject *pp, PyObject *key)
{
- return PyObject_GetItem(pp->dict, key);
+ return PyObject_GetItem(pp->mapping, key);
}
-static PyMappingMethods proxy_as_mapping = {
- (lenfunc)proxy_len, /* mp_length */
- (binaryfunc)proxy_getitem, /* mp_subscript */
+static PyMappingMethods mappingproxy_as_mapping = {
+ (lenfunc)mappingproxy_len, /* mp_length */
+ (binaryfunc)mappingproxy_getitem, /* mp_subscript */
0, /* mp_ass_subscript */
};
static int
-proxy_contains(proxyobject *pp, PyObject *key)
+mappingproxy_contains(mappingproxyobject *pp, PyObject *key)
{
- return PyDict_Contains(pp->dict, key);
+ if (PyDict_CheckExact(pp->mapping))
+ return PyDict_Contains(pp->mapping, key);
+ else
+ return PySequence_Contains(pp->mapping, key);
}
-static PySequenceMethods proxy_as_sequence = {
+static PySequenceMethods mappingproxy_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
@@ -740,152 +743,199 @@ static PySequenceMethods proxy_as_sequence = {
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
- (objobjproc)proxy_contains, /* sq_contains */
+ (objobjproc)mappingproxy_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
static PyObject *
-proxy_get(proxyobject *pp, PyObject *args)
+mappingproxy_get(mappingproxyobject *pp, PyObject *args)
{
PyObject *key, *def = Py_None;
_Py_IDENTIFIER(get);
if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))
return NULL;
- return _PyObject_CallMethodId(pp->dict, &PyId_get, "(OO)", key, def);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_get, "(OO)", key, def);
}
static PyObject *
-proxy_keys(proxyobject *pp)
+mappingproxy_keys(mappingproxyobject *pp)
{
_Py_IDENTIFIER(keys);
- return _PyObject_CallMethodId(pp->dict, &PyId_keys, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_keys, NULL);
}
static PyObject *
-proxy_values(proxyobject *pp)
+mappingproxy_values(mappingproxyobject *pp)
{
_Py_IDENTIFIER(values);
- return _PyObject_CallMethodId(pp->dict, &PyId_values, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_values, NULL);
}
static PyObject *
-proxy_items(proxyobject *pp)
+mappingproxy_items(mappingproxyobject *pp)
{
_Py_IDENTIFIER(items);
- return _PyObject_CallMethodId(pp->dict, &PyId_items, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_items, NULL);
}
static PyObject *
-proxy_copy(proxyobject *pp)
+mappingproxy_copy(mappingproxyobject *pp)
{
_Py_IDENTIFIER(copy);
- return _PyObject_CallMethodId(pp->dict, &PyId_copy, NULL);
+ return _PyObject_CallMethodId(pp->mapping, &PyId_copy, NULL);
}
-static PyMethodDef proxy_methods[] = {
- {"get", (PyCFunction)proxy_get, METH_VARARGS,
+/* WARNING: mappingproxy methods must not give access
+ to the underlying mapping */
+
+static PyMethodDef mappingproxy_methods[] = {
+ {"get", (PyCFunction)mappingproxy_get, METH_VARARGS,
PyDoc_STR("D.get(k[,d]) -> D[k] if k in D, else d."
- " d defaults to None.")},
- {"keys", (PyCFunction)proxy_keys, METH_NOARGS,
+ " d defaults to None.")},
+ {"keys", (PyCFunction)mappingproxy_keys, METH_NOARGS,
PyDoc_STR("D.keys() -> list of D's keys")},
- {"values", (PyCFunction)proxy_values, METH_NOARGS,
+ {"values", (PyCFunction)mappingproxy_values, METH_NOARGS,
PyDoc_STR("D.values() -> list of D's values")},
- {"items", (PyCFunction)proxy_items, METH_NOARGS,
+ {"items", (PyCFunction)mappingproxy_items, METH_NOARGS,
PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
- {"copy", (PyCFunction)proxy_copy, METH_NOARGS,
+ {"copy", (PyCFunction)mappingproxy_copy, METH_NOARGS,
PyDoc_STR("D.copy() -> a shallow copy of D")},
{0}
};
static void
-proxy_dealloc(proxyobject *pp)
+mappingproxy_dealloc(mappingproxyobject *pp)
{
_PyObject_GC_UNTRACK(pp);
- Py_DECREF(pp->dict);
+ Py_DECREF(pp->mapping);
PyObject_GC_Del(pp);
}
static PyObject *
-proxy_getiter(proxyobject *pp)
+mappingproxy_getiter(mappingproxyobject *pp)
{
- return PyObject_GetIter(pp->dict);
+ return PyObject_GetIter(pp->mapping);
}
static PyObject *
-proxy_str(proxyobject *pp)
+mappingproxy_str(mappingproxyobject *pp)
{
- return PyObject_Str(pp->dict);
+ return PyObject_Str(pp->mapping);
}
static PyObject *
-proxy_repr(proxyobject *pp)
+mappingproxy_repr(mappingproxyobject *pp)
{
- return PyUnicode_FromFormat("dict_proxy(%R)", pp->dict);
+ return PyUnicode_FromFormat("mappingproxy(%R)", pp->mapping);
}
static int
-proxy_traverse(PyObject *self, visitproc visit, void *arg)
+mappingproxy_traverse(PyObject *self, visitproc visit, void *arg)
{
- proxyobject *pp = (proxyobject *)self;
- Py_VISIT(pp->dict);
+ mappingproxyobject *pp = (mappingproxyobject *)self;
+ Py_VISIT(pp->mapping);
return 0;
}
static PyObject *
-proxy_richcompare(proxyobject *v, PyObject *w, int op)
+mappingproxy_richcompare(mappingproxyobject *v, PyObject *w, int op)
+{
+ return PyObject_RichCompare(v->mapping, w, op);
+}
+
+static int
+mappingproxy_check_mapping(PyObject *mapping)
+{
+ if (!PyMapping_Check(mapping)
+ || PyList_Check(mapping)
+ || PyTuple_Check(mapping)) {
+ PyErr_Format(PyExc_TypeError,
+ "mappingproxy() argument must be a mapping, not %s",
+ Py_TYPE(mapping)->tp_name);
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject*
+mappingproxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
- return PyObject_RichCompare(v->dict, w, op);
+ static char *kwlist[] = {"mapping", NULL};
+ PyObject *mapping;
+ mappingproxyobject *mappingproxy;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:mappingproxy",
+ kwlist, &mapping))
+ return NULL;
+
+ if (mappingproxy_check_mapping(mapping) == -1)
+ return NULL;
+
+ mappingproxy = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
+ if (mappingproxy == NULL)
+ return NULL;
+ Py_INCREF(mapping);
+ mappingproxy->mapping = mapping;
+ _PyObject_GC_TRACK(mappingproxy);
+ return (PyObject *)mappingproxy;
}
PyTypeObject PyDictProxy_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_proxy", /* tp_name */
- sizeof(proxyobject), /* tp_basicsize */
+ "mappingproxy", /* tp_name */
+ sizeof(mappingproxyobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- (destructor)proxy_dealloc, /* tp_dealloc */
+ (destructor)mappingproxy_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
- (reprfunc)proxy_repr, /* tp_repr */
+ (reprfunc)mappingproxy_repr, /* tp_repr */
0, /* tp_as_number */
- &proxy_as_sequence, /* tp_as_sequence */
- &proxy_as_mapping, /* tp_as_mapping */
+ &mappingproxy_as_sequence, /* tp_as_sequence */
+ &mappingproxy_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
- (reprfunc)proxy_str, /* tp_str */
+ (reprfunc)mappingproxy_str, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
- proxy_traverse, /* tp_traverse */
+ mappingproxy_traverse, /* tp_traverse */
0, /* tp_clear */
- (richcmpfunc)proxy_richcompare, /* tp_richcompare */
+ (richcmpfunc)mappingproxy_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
- (getiterfunc)proxy_getiter, /* tp_iter */
+ (getiterfunc)mappingproxy_getiter, /* tp_iter */
0, /* tp_iternext */
- proxy_methods, /* tp_methods */
+ mappingproxy_methods, /* tp_methods */
0, /* tp_members */
0, /* 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 */
+ mappingproxy_new, /* tp_new */
};
PyObject *
-PyDictProxy_New(PyObject *dict)
+PyDictProxy_New(PyObject *mapping)
{
- proxyobject *pp;
+ mappingproxyobject *pp;
+
+ if (mappingproxy_check_mapping(mapping) == -1)
+ return NULL;
- pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type);
+ pp = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
if (pp != NULL) {
- Py_INCREF(dict);
- pp->dict = dict;
+ Py_INCREF(mapping);
+ pp->mapping = mapping;
_PyObject_GC_TRACK(pp);
}
return (PyObject *)pp;