diff -r 7c52a59f1409 Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst Thu Mar 22 07:42:31 2012 +0100 +++ b/Doc/library/stdtypes.rst Thu Mar 22 13:35:09 2012 +0100 @@ -2257,13 +2257,13 @@ pairs within braces, for example: ``{'ja .. method:: items() - Return a new view of the dictionary's items (``(key, value)`` pairs). See - below for documentation of view objects. + Return a new view of the dictionary's items (``(key, value)`` pairs). + See the :ref:`documentation of view objects `. .. method:: keys() - Return a new view of the dictionary's keys. See below for documentation of - view objects. + Return a new view of the dictionary's keys. See the :ref:`documentation + of view objects `. .. method:: pop(key[, default]) @@ -2297,8 +2297,8 @@ pairs within braces, for example: ``{'ja .. method:: values() - Return a new view of the dictionary's values. See below for documentation of - view objects. + Return a new view of the dictionary's values. See the + :ref:`documentation of view objects `. .. _dict-views: @@ -2379,6 +2379,64 @@ An example of dictionary view usage:: {'juice', 'sausage', 'bacon', 'spam'} +Immutable Mapping Types --- :class:`dictproxy` +============================================== + +An immutable mapping object maps :term:`hashable` values to arbitrary objects. + + +.. class:: dictproxy(dict) + + Return a new dictionary proxy initialized from a dictionary. A dictproxy + stores a reference to the dictionary: if the dictionary is modified, the + dictproxy is also modified. + + .. versionadded:: 3.3 + + .. describe:: key in d + + Return ``True`` if *d* has a key *key*, else ``False``. + + .. describe:: d[key] + + Return the item of *d* with key *key*. Raises a :exc:`KeyError` if *key* is + not in the map. + + .. describe:: iter(d) + + Return an iterator over the keys of the dictionary. This is a shortcut + for ``iter(d.keys())``. + + .. describe:: len(d) + + Return the number of items in the dictionary *d*. + + .. method:: copy() + + Return a shallow copy of the dictionary as a :class:`dict`. + + .. method:: get(key[, default]) + + Return the value for *key* if *key* is in the dictionary, else *default*. + If *default* is not given, it defaults to ``None``, so that this method + never raises a :exc:`KeyError`. + + .. method:: items() + + Return a new view of the dictionary's items (``(key, value)`` pairs). See + the :ref:`documentation of view objects `. + + .. method:: keys() + + Return a new view of the dictionary's keys. See the :ref:`documentation of + view objects `. + + .. method:: values() + + Return a new view of the dictionary's values. See the :ref:`documentation of + view objects `. + + .. _typememoryview: memoryview type diff -r 7c52a59f1409 Include/Python.h --- a/Include/Python.h Thu Mar 22 07:42:31 2012 +0100 +++ b/Include/Python.h Thu Mar 22 13:35:09 2012 +0100 @@ -84,6 +84,7 @@ #include "tupleobject.h" #include "listobject.h" #include "dictobject.h" +#include "dictproxyobject.h" #include "enumobject.h" #include "setobject.h" #include "methodobject.h" diff -r 7c52a59f1409 Include/descrobject.h --- a/Include/descrobject.h Thu Mar 22 07:42:31 2012 +0100 +++ b/Include/descrobject.h Thu Mar 22 13:35:09 2012 +0100 @@ -77,7 +77,6 @@ PyAPI_DATA(PyTypeObject) PyGetSetDescr_T PyAPI_DATA(PyTypeObject) PyMemberDescr_Type; PyAPI_DATA(PyTypeObject) PyMethodDescr_Type; PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type; -PyAPI_DATA(PyTypeObject) PyDictProxy_Type; PyAPI_DATA(PyTypeObject) _PyMethodWrapper_Type; PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *); @@ -93,7 +92,6 @@ PyAPI_FUNC(PyObject *) PyDescr_NewWrappe #define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL) #endif -PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); diff -r 7c52a59f1409 Include/dictproxyobject.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Include/dictproxyobject.h Thu Mar 22 13:35:09 2012 +0100 @@ -0,0 +1,14 @@ +#ifndef Py_DICTPROXYOBJECT_H +#define Py_DICTPROXYOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* dictproxy type */ +PyAPI_DATA(PyTypeObject) PyDictProxy_Type; +PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_DICTPROXYOBJECT_H */ diff -r 7c52a59f1409 Lib/test/test_descr.py --- a/Lib/test/test_descr.py Thu Mar 22 07:42:31 2012 +0100 +++ b/Lib/test/test_descr.py Thu Mar 22 13:35:09 2012 +0100 @@ -4574,11 +4574,11 @@ class DictProxyTests(unittest.TestCase): self.assertEqual(type(C.__dict__), type(B.__dict__)) def test_repr(self): - # Testing dict_proxy.__repr__. + # Testing dictproxy.__repr__. # We can't blindly compare with the repr of another dict as ordering # of keys and values is arbitrary and may differ. r = repr(self.C.__dict__) - self.assertTrue(r.startswith('dict_proxy('), r) + self.assertTrue(r.startswith('dictproxy('), r) self.assertTrue(r.endswith(')'), r) for k, v in self.C.__dict__.items(): self.assertIn('{!r}: {!r}'.format(k, v), r) diff -r 7c52a59f1409 Lib/test/test_dictproxy.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/test/test_dictproxy.py Thu Mar 22 13:35:09 2012 +0100 @@ -0,0 +1,141 @@ +from test import support +import unittest +import collections + +class DictProxyTests(unittest.TestCase): + def test_constructor(self): + class userdict(dict): + pass + + d = {'x': 1, 'y': 2} + self.assertEqual(dictproxy(d), d) + d = userdict(x=1, y=2) + self.assertEqual(dictproxy(d), d) + self.assertRaises(TypeError, dictproxy, 10) + self.assertRaises(TypeError, dictproxy, ("a", "tuple")) + self.assertRaises(TypeError, dictproxy, ["a", "list"]) + self.assertRaises(TypeError, dictproxy, collections.ChainMap({})) + + def test_methods(self): + attrs = set(dir(dictproxy({}))) - set(dir(object())) + self.assertEqual(attrs, { + '__contains__', + '__getitem__', + '__iter__', + '__len__', + 'copy', + 'get', + 'items', + 'keys', + 'values', + }) + + def test_get(self): + proxy = dictproxy({'a': 'A', 'b': 'B'}) + self.assertEqual(proxy['a'], 'A') + self.assertEqual(proxy['b'], 'B') + self.assertRaises(KeyError, proxy.__getitem__, 'xxx') + self.assertEqual(proxy.get('a'), 'A') + self.assertIsNone(proxy.get('xxx')) + self.assertEqual(proxy.get('xxx', 42), 42) + + def test_missing(self): + class dictmissing(dict): + def __missing__(self, key): + return "missing=%s" % key + + proxy = dictproxy(dictmissing(x=1)) + self.assertEqual(proxy['x'], 1) + self.assertEqual(proxy['y'], 'missing=y') + self.assertEqual(proxy.get('x'), 1) + self.assertEqual(proxy.get('y'), None) + self.assertEqual(proxy.get('y', 42), 42) + self.assertTrue('x' in proxy) + self.assertFalse('y' in proxy) + + def test_customdict(self): + class customdict(dict): + def __contains__(self, key): + if key == 'magic': + return True + else: + return dict.__contains__(self, key) + + def __iter__(self): + return iter(('iter',)) + + def __len__(self): + return 500 + + def copy(self): + return 'copy' + + def keys(self): + return 'keys' + + def items(self): + return 'items' + + def values(self): + return 'values' + + def __getitem__(self, key): + return "getitem=%s" % dict.__getitem__(self, key) + + def get(self, key, default=None): + return "get=%s" % dict.get(self, key, default) + + custom = customdict({'key': 'value'}) + proxy = dictproxy(custom) + self.assertTrue('key' in proxy) + self.assertTrue('magic' in proxy) + self.assertFalse('xxx' in proxy) + self.assertEqual(proxy['key'], 'getitem=value') + self.assertEqual(tuple(proxy), ('iter',)) + self.assertEqual(len(proxy), 500) + self.assertEqual(proxy.copy(), 'copy') + self.assertEqual(proxy.get('key'), 'get=value') + self.assertEqual(proxy.items(), 'items') + self.assertEqual(proxy.keys(), 'keys') + self.assertEqual(proxy.values(), 'values') + + def test_contains(self): + proxy = dictproxy(dict.fromkeys('abc')) + self.assertTrue('a' in proxy) + self.assertTrue('b' in proxy) + self.assertTrue('c' in proxy) + self.assertFalse('xxx' in proxy) + + def test_len(self): + for expected in range(6): + data = dict.fromkeys('abcde'[:expected]) + self.assertEqual(len(data), expected) + proxy = dictproxy(data) + self.assertEqual(len(proxy), expected) + + def test_iterators(self): + keys = ('x', 'y') + values = (1, 2) + items = tuple(zip(keys, values)) + proxy = dictproxy(dict(items)) + self.assertEqual(set(proxy), set(keys)) + self.assertEqual(set(proxy.keys()), set(keys)) + self.assertEqual(set(proxy.values()), set(values)) + self.assertEqual(set(proxy.items()), set(items)) + + def test_copy(self): + original = {'key1': 27, 'key2': 51, 'key3': 93} + proxy = dictproxy(original) + copy = proxy.copy() + self.assertEqual(type(copy), dict) + self.assertEqual(copy, original) + original['key1'] = 70 + self.assertEqual(proxy['key1'], 70) + self.assertEqual(copy['key1'], 27) + + +def test_main(): + support.run_unittest(DictProxyTests) + +if __name__ == "__main__": + test_main() diff -r 7c52a59f1409 Makefile.pre.in --- a/Makefile.pre.in Thu Mar 22 07:42:31 2012 +0100 +++ b/Makefile.pre.in Thu Mar 22 13:35:09 2012 +0100 @@ -389,6 +389,7 @@ OBJECT_OBJS= \ Objects/listobject.o \ Objects/longobject.o \ Objects/dictobject.o \ + Objects/dictproxyobject.o \ Objects/memoryobject.o \ Objects/methodobject.o \ Objects/moduleobject.o \ @@ -725,6 +726,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/complexobject.h \ $(srcdir)/Include/descrobject.h \ $(srcdir)/Include/dictobject.h \ + $(srcdir)/Include/dictproxyobject.h \ $(srcdir)/Include/dtoa.h \ $(srcdir)/Include/dynamic_annotations.h \ $(srcdir)/Include/enumobject.h \ diff -r 7c52a59f1409 Objects/descrobject.c --- a/Objects/descrobject.c Thu Mar 22 07:42:31 2012 +0100 +++ b/Objects/descrobject.c Thu Mar 22 13:35:09 2012 +0100 @@ -698,200 +698,6 @@ PyDescr_NewWrapper(PyTypeObject *type, s } -/* --- Readonly proxy for dictionaries (actually any mapping) --- */ - -/* 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; - -static Py_ssize_t -proxy_len(proxyobject *pp) -{ - return PyObject_Size(pp->dict); -} - -static PyObject * -proxy_getitem(proxyobject *pp, PyObject *key) -{ - return PyObject_GetItem(pp->dict, key); -} - -static PyMappingMethods proxy_as_mapping = { - (lenfunc)proxy_len, /* mp_length */ - (binaryfunc)proxy_getitem, /* mp_subscript */ - 0, /* mp_ass_subscript */ -}; - -static int -proxy_contains(proxyobject *pp, PyObject *key) -{ - return PyDict_Contains(pp->dict, key); -} - -static PySequenceMethods proxy_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)proxy_contains, /* sq_contains */ - 0, /* sq_inplace_concat */ - 0, /* sq_inplace_repeat */ -}; - -static PyObject * -proxy_get(proxyobject *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); -} - -static PyObject * -proxy_keys(proxyobject *pp) -{ - _Py_IDENTIFIER(keys); - return _PyObject_CallMethodId(pp->dict, &PyId_keys, NULL); -} - -static PyObject * -proxy_values(proxyobject *pp) -{ - _Py_IDENTIFIER(values); - return _PyObject_CallMethodId(pp->dict, &PyId_values, NULL); -} - -static PyObject * -proxy_items(proxyobject *pp) -{ - _Py_IDENTIFIER(items); - return _PyObject_CallMethodId(pp->dict, &PyId_items, NULL); -} - -static PyObject * -proxy_copy(proxyobject *pp) -{ - _Py_IDENTIFIER(copy); - return _PyObject_CallMethodId(pp->dict, &PyId_copy, NULL); -} - -static PyMethodDef proxy_methods[] = { - {"get", (PyCFunction)proxy_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, - PyDoc_STR("D.keys() -> list of D's keys")}, - {"values", (PyCFunction)proxy_values, METH_NOARGS, - PyDoc_STR("D.values() -> list of D's values")}, - {"items", (PyCFunction)proxy_items, METH_NOARGS, - PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")}, - {"copy", (PyCFunction)proxy_copy, METH_NOARGS, - PyDoc_STR("D.copy() -> a shallow copy of D")}, - {0} -}; - -static void -proxy_dealloc(proxyobject *pp) -{ - _PyObject_GC_UNTRACK(pp); - Py_DECREF(pp->dict); - PyObject_GC_Del(pp); -} - -static PyObject * -proxy_getiter(proxyobject *pp) -{ - return PyObject_GetIter(pp->dict); -} - -static PyObject * -proxy_str(proxyobject *pp) -{ - return PyObject_Str(pp->dict); -} - -static PyObject * -proxy_repr(proxyobject *pp) -{ - return PyUnicode_FromFormat("dict_proxy(%R)", pp->dict); -} - -static int -proxy_traverse(PyObject *self, visitproc visit, void *arg) -{ - proxyobject *pp = (proxyobject *)self; - Py_VISIT(pp->dict); - return 0; -} - -static PyObject * -proxy_richcompare(proxyobject *v, PyObject *w, int op) -{ - return PyObject_RichCompare(v->dict, w, op); -} - -PyTypeObject PyDictProxy_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "dict_proxy", /* tp_name */ - sizeof(proxyobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)proxy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - (reprfunc)proxy_repr, /* tp_repr */ - 0, /* tp_as_number */ - &proxy_as_sequence, /* tp_as_sequence */ - &proxy_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)proxy_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 */ - 0, /* tp_clear */ - (richcmpfunc)proxy_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)proxy_getiter, /* tp_iter */ - 0, /* tp_iternext */ - proxy_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ -}; - -PyObject * -PyDictProxy_New(PyObject *dict) -{ - proxyobject *pp; - - pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type); - if (pp != NULL) { - Py_INCREF(dict); - pp->dict = dict; - _PyObject_GC_TRACK(pp); - } - return (PyObject *)pp; -} - - /* --- Wrapper object for "slot" methods --- */ /* This has no reason to be in this file except that adding new files is a diff -r 7c52a59f1409 Objects/dictproxyobject.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Objects/dictproxyobject.c Thu Mar 22 13:35:09 2012 +0100 @@ -0,0 +1,237 @@ +/* --- Readonly proxy for dictionaries (actually any mapping) --- */ + +#include "Python.h" + +typedef struct { + PyObject_HEAD + PyObject *dict; +} proxyobject; + +static Py_ssize_t +proxy_len(proxyobject *pp) +{ + return PyObject_Size(pp->dict); +} + +static PyObject * +proxy_getitem(proxyobject *pp, PyObject *key) +{ + return PyObject_GetItem(pp->dict, key); +} + +static PyMappingMethods proxy_as_mapping = { + (lenfunc)proxy_len, /* mp_length */ + (binaryfunc)proxy_getitem, /* mp_subscript */ + 0, /* mp_ass_subscript */ +}; + +static int +proxy_contains(proxyobject *pp, PyObject *key) +{ + if (PyDict_CheckExact(pp->dict)) + return PyDict_Contains(pp->dict, key); + else + return PySequence_Contains(pp->dict, key); +} + +static PySequenceMethods proxy_as_sequence = { + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)proxy_contains, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyObject * +proxy_get(proxyobject *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); +} + +static PyObject * +proxy_keys(proxyobject *pp) +{ + _Py_IDENTIFIER(keys); + return _PyObject_CallMethodId(pp->dict, &PyId_keys, NULL); +} + +static PyObject * +proxy_values(proxyobject *pp) +{ + _Py_IDENTIFIER(values); + return _PyObject_CallMethodId(pp->dict, &PyId_values, NULL); +} + +static PyObject * +proxy_items(proxyobject *pp) +{ + _Py_IDENTIFIER(items); + return _PyObject_CallMethodId(pp->dict, &PyId_items, NULL); +} + +static PyObject * +proxy_copy(proxyobject *pp) +{ + _Py_IDENTIFIER(copy); + return _PyObject_CallMethodId(pp->dict, &PyId_copy, NULL); +} + +static PyMethodDef proxy_methods[] = { + {"get", (PyCFunction)proxy_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, + PyDoc_STR("D.keys() -> list of D's keys")}, + {"values", (PyCFunction)proxy_values, METH_NOARGS, + PyDoc_STR("D.values() -> list of D's values")}, + {"items", (PyCFunction)proxy_items, METH_NOARGS, + PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")}, + {"copy", (PyCFunction)proxy_copy, METH_NOARGS, + PyDoc_STR("D.copy() -> a shallow copy of D")}, + {0} +}; + +static void +proxy_dealloc(proxyobject *pp) +{ + _PyObject_GC_UNTRACK(pp); + Py_DECREF(pp->dict); + PyObject_GC_Del(pp); +} + +static PyObject * +proxy_getiter(proxyobject *pp) +{ + return PyObject_GetIter(pp->dict); +} + +static PyObject * +proxy_str(proxyobject *pp) +{ + return PyObject_Str(pp->dict); +} + +static PyObject * +proxy_repr(proxyobject *pp) +{ + return PyUnicode_FromFormat("dictproxy(%R)", pp->dict); +} + +static int +proxy_traverse(PyObject *self, visitproc visit, void *arg) +{ + proxyobject *pp = (proxyobject *)self; + Py_VISIT(pp->dict); + return 0; +} + +static PyObject * +proxy_richcompare(proxyobject *v, PyObject *w, int op) +{ + return PyObject_RichCompare(v->dict, w, op); +} + +static int +proxy_check_dict(PyObject *dict) +{ + if (!PyDict_Check(dict)) { + PyErr_Format(PyExc_TypeError, + "dictproxy() argument must be a dict, not %s", + Py_TYPE(dict)->tp_name); + return -1; + } + return 0; +} + +static PyObject* +proxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"dict", 0}; + PyObject *dict; + proxyobject *proxy; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:dictproxy", + kwlist, &dict)) + return NULL; + + if (proxy_check_dict(dict) == -1) + return NULL; + + proxy = PyObject_GC_New(proxyobject, &PyDictProxy_Type); + if (proxy == NULL) + return NULL; + Py_INCREF(dict); + proxy->dict = dict; + _PyObject_GC_TRACK(proxy); + return (PyObject *)proxy; +} + +PyTypeObject PyDictProxy_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "dictproxy", /* tp_name */ + sizeof(proxyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)proxy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)proxy_repr, /* tp_repr */ + 0, /* tp_as_number */ + &proxy_as_sequence, /* tp_as_sequence */ + &proxy_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)proxy_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 */ + 0, /* tp_clear */ + (richcmpfunc)proxy_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)proxy_getiter, /* tp_iter */ + 0, /* tp_iternext */ + proxy_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 */ + proxy_new, /* tp_new */ +}; + +PyObject * +PyDictProxy_New(PyObject *dict) +{ + proxyobject *pp; + + if (proxy_check_dict(dict) == -1) + return NULL; + + pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type); + if (pp != NULL) { + Py_INCREF(dict); + pp->dict = dict; + _PyObject_GC_TRACK(pp); + } + return (PyObject *)pp; +} + diff -r 7c52a59f1409 PCbuild/pythoncore.vcproj --- a/PCbuild/pythoncore.vcproj Thu Mar 22 07:42:31 2012 +0100 +++ b/PCbuild/pythoncore.vcproj Thu Mar 22 13:35:09 2012 +0100 @@ -707,6 +707,10 @@ > + + @@ -1499,6 +1503,10 @@ > + + diff -r 7c52a59f1409 Python/bltinmodule.c --- a/Python/bltinmodule.c Thu Mar 22 07:42:31 2012 +0100 +++ b/Python/bltinmodule.c Thu Mar 22 13:35:09 2012 +0100 @@ -2393,6 +2393,7 @@ _PyBuiltin_Init(void) SETBUILTIN("classmethod", &PyClassMethod_Type); SETBUILTIN("complex", &PyComplex_Type); SETBUILTIN("dict", &PyDict_Type); + SETBUILTIN("dictproxy", &PyDictProxy_Type); SETBUILTIN("enumerate", &PyEnum_Type); SETBUILTIN("filter", &PyFilter_Type); SETBUILTIN("float", &PyFloat_Type);