From 7afb2d25290d49480bcbd9003fb7a9c063257801 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 25 Jun 2022 10:20:40 +0300 Subject: [PATCH 1/2] gh-87995: Make MappingProxyType hashable --- Doc/library/types.rst | 6 ++++++ Doc/whatsnew/3.12.rst | 3 +++ Lib/test/test_types.py | 10 ++++++++++ .../2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst | 2 ++ Objects/descrobject.c | 8 +++++++- 5 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst diff --git a/Doc/library/types.rst b/Doc/library/types.rst index e0e77dfbfe7ed2..cce0ad960edf97 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -417,6 +417,12 @@ Standard names are defined for the following types: .. versionadded:: 3.9 + .. describe:: hash(proxy) + + Return a hash of the underlying mapping. + + .. versionadded:: 3.12 + Additional Utility Classes and Functions ---------------------------------------- diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 625790151f70cb..69a045ca5f87e6 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -79,6 +79,9 @@ New Features Other Language Changes ====================== +* :class:`types.MappingProxyType` instances are now hashable if the underlying + mapping is hashable. + (Contributed by Serhiy Storchaka in :gh:`87995`.) New Modules diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 8556ca35ca06c1..f00da0a758d46f 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1203,6 +1203,16 @@ def test_union(self): self.assertDictEqual(mapping, {'a': 0, 'b': 1, 'c': 2}) self.assertDictEqual(other, {'c': 3, 'p': 0}) + def test_hash(self): + class HashableDict(dict): + def __hash__(self): + return 3844817361 + view = self.mappingproxy({'a': 1, 'b': 2}) + self.assertRaises(TypeError, hash, view) + mapping = HashableDict({'a': 1, 'b': 2}) + view = self.mappingproxy(mapping) + self.assertEqual(hash(view), hash(mapping)) + class ClassCreationTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst new file mode 100644 index 00000000000000..4154ebce234958 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-25-10-19-43.gh-issue-87995.aMDHnp.rst @@ -0,0 +1,2 @@ +:class:`types.MappingProxyType` instances are now hashable if the underlying +mapping is hashable. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 8ef6a82d7c6d96..9434459596e423 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1184,6 +1184,12 @@ mappingproxy_str(mappingproxyobject *pp) return PyObject_Str(pp->mapping); } +static Py_hash_t +mappingproxy_hash(mappingproxyobject *pp) +{ + return PyObject_Hash(pp->mapping); +} + static PyObject * mappingproxy_repr(mappingproxyobject *pp) { @@ -1901,7 +1907,7 @@ PyTypeObject PyDictProxy_Type = { &mappingproxy_as_number, /* tp_as_number */ &mappingproxy_as_sequence, /* tp_as_sequence */ &mappingproxy_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ + (hashfunc)mappingproxy_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc)mappingproxy_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ From cedc9433992041062885b24cc608236befc52b23 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 28 Jun 2022 08:07:24 +0300 Subject: [PATCH 2/2] Polishing. --- Objects/descrobject.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 9434459596e423..82570e085143ed 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1178,18 +1178,18 @@ mappingproxy_getiter(mappingproxyobject *pp) return PyObject_GetIter(pp->mapping); } -static PyObject * -mappingproxy_str(mappingproxyobject *pp) -{ - return PyObject_Str(pp->mapping); -} - static Py_hash_t mappingproxy_hash(mappingproxyobject *pp) { return PyObject_Hash(pp->mapping); } +static PyObject * +mappingproxy_str(mappingproxyobject *pp) +{ + return PyObject_Str(pp->mapping); +} + static PyObject * mappingproxy_repr(mappingproxyobject *pp) {