summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@gmail.com>2020-03-07 19:03:09 (GMT)
committerGitHub <noreply@github.com>2020-03-07 19:03:09 (GMT)
commit4663f66f3554dd8e2ec130e40f6abb3c6a514775 (patch)
tree479bda23ce4895419248e76431066a81d9088c94
parent8f130536926a30237b5297780d61ef4232e88577 (diff)
downloadcpython-4663f66f3554dd8e2ec130e40f6abb3c6a514775.zip
cpython-4663f66f3554dd8e2ec130e40f6abb3c6a514775.tar.gz
cpython-4663f66f3554dd8e2ec130e40f6abb3c6a514775.tar.bz2
bpo-36144: Update MappingProxyType with PEP 584's operators (#18814)
We make `|=` raise TypeError, since it would be surprising if `C.__dict__ |= {'x': 0}` silently did nothing, while `C.__dict__.update({'x': 0})` is an error.
-rw-r--r--Doc/library/types.rst5
-rw-r--r--Lib/test/test_types.py19
-rw-r--r--Misc/NEWS.d/next/Library/2020-02-25-09-28-06.bpo-36144.Rbvvi7.rst2
-rw-r--r--Objects/descrobject.c26
4 files changed, 51 insertions, 1 deletions
diff --git a/Doc/library/types.rst b/Doc/library/types.rst
index 3529c2b..4cb91c1 100644
--- a/Doc/library/types.rst
+++ b/Doc/library/types.rst
@@ -282,6 +282,11 @@ Standard names are defined for the following types:
.. versionadded:: 3.3
+ .. versionchanged:: 3.9
+
+ Updated to support the new union (``|``) operator from :pep:`584`, which
+ simply delegates to the underlying mapping.
+
.. describe:: key in proxy
Return ``True`` if the underlying mapping has a key *key*, else
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index 7b45b7a..544c91b 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -622,8 +622,11 @@ class MappingProxyTests(unittest.TestCase):
self.assertEqual(attrs, {
'__contains__',
'__getitem__',
+ '__ior__',
'__iter__',
'__len__',
+ '__or__',
+ '__ror__',
'copy',
'get',
'items',
@@ -774,6 +777,22 @@ class MappingProxyTests(unittest.TestCase):
self.assertEqual(view['key1'], 70)
self.assertEqual(copy['key1'], 27)
+ def test_union(self):
+ mapping = {'a': 0, 'b': 1, 'c': 2}
+ view = self.mappingproxy(mapping)
+ with self.assertRaises(TypeError):
+ view | [('r', 2), ('d', 2)]
+ with self.assertRaises(TypeError):
+ [('r', 2), ('d', 2)] | view
+ with self.assertRaises(TypeError):
+ view |= [('r', 2), ('d', 2)]
+ other = {'c': 3, 'p': 0}
+ self.assertDictEqual(view | other, {'a': 0, 'b': 1, 'c': 3, 'p': 0})
+ self.assertDictEqual(other | view, {'c': 2, 'p': 0, 'a': 0, 'b': 1})
+ self.assertEqual(view, {'a': 0, 'b': 1, 'c': 2})
+ self.assertDictEqual(mapping, {'a': 0, 'b': 1, 'c': 2})
+ self.assertDictEqual(other, {'c': 3, 'p': 0})
+
class ClassCreationTests(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2020-02-25-09-28-06.bpo-36144.Rbvvi7.rst b/Misc/NEWS.d/next/Library/2020-02-25-09-28-06.bpo-36144.Rbvvi7.rst
new file mode 100644
index 0000000..da0ff9d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-02-25-09-28-06.bpo-36144.Rbvvi7.rst
@@ -0,0 +1,2 @@
+:class:`types.MappingProxyType` objects now support the merge (``|``) operator
+from :pep:`584`.
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index c96945b..4ebbb74 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -982,6 +982,30 @@ static PyMappingMethods mappingproxy_as_mapping = {
0, /* mp_ass_subscript */
};
+static PyObject *
+mappingproxy_or(PyObject *left, PyObject *right)
+{
+ if (PyObject_TypeCheck(left, &PyDictProxy_Type)) {
+ left = ((mappingproxyobject*)left)->mapping;
+ }
+ if (PyObject_TypeCheck(right, &PyDictProxy_Type)) {
+ right = ((mappingproxyobject*)right)->mapping;
+ }
+ return PyNumber_Or(left, right);
+}
+
+static PyObject *
+mappingproxy_ior(PyObject *self, PyObject *Py_UNUSED(other))
+{
+ return PyErr_Format(PyExc_TypeError,
+ "'|=' is not supported by %s; use '|' instead", Py_TYPE(self)->tp_name);
+}
+
+static PyNumberMethods mappingproxy_as_number = {
+ .nb_or = mappingproxy_or,
+ .nb_inplace_or = mappingproxy_ior,
+};
+
static int
mappingproxy_contains(mappingproxyobject *pp, PyObject *key)
{
@@ -1717,7 +1741,7 @@ PyTypeObject PyDictProxy_Type = {
0, /* tp_setattr */
0, /* tp_as_async */
(reprfunc)mappingproxy_repr, /* tp_repr */
- 0, /* tp_as_number */
+ &mappingproxy_as_number, /* tp_as_number */
&mappingproxy_as_sequence, /* tp_as_sequence */
&mappingproxy_as_mapping, /* tp_as_mapping */
0, /* tp_hash */