diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2012-04-15 22:16:30 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2012-04-15 22:16:30 (GMT) |
commit | 0db176f8f6cfaf3277e6ef41d92b09a01b263f27 (patch) | |
tree | 9c881aaab525015223b7219c8fa12910e66354e9 /Objects | |
parent | 8a1d04c64372d4706572671a21ff9d3e4a6374ca (diff) | |
download | cpython-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.c | 170 |
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; |