@@ -1180,6 +1180,28 @@ def test_instantiation(self):
11801180class MappingProxyTests (unittest .TestCase ):
11811181 mappingproxy = types .MappingProxyType
11821182
1183+ class MappingWithoutCopy (collections .abc .Mapping ):
1184+ def __init__ (self , mapping ):
1185+ self .mapping = mapping
1186+
1187+ def __getitem__ (self , key ):
1188+ return self .mapping [key ]
1189+
1190+ def __iter__ (self ):
1191+ return iter (self .mapping )
1192+
1193+ def __len__ (self ):
1194+ return len (self .mapping )
1195+
1196+ class RecordingOperand :
1197+ def __eq__ (self , other ):
1198+ self .other = other
1199+ return None
1200+
1201+ def __ror__ (self , other ):
1202+ self .other = other
1203+ return None
1204+
11831205 def test_constructor (self ):
11841206 class userdict (dict ):
11851207 pass
@@ -1381,6 +1403,70 @@ def test_union(self):
13811403 self .assertDictEqual (mapping , {'a' : 0 , 'b' : 1 , 'c' : 2 })
13821404 self .assertDictEqual (other , {'c' : 3 , 'p' : 0 })
13831405
1406+ def test_richcompare_does_not_expose_mapping (self ):
1407+ mapping = {}
1408+ view = self .mappingproxy (mapping )
1409+
1410+ class Sneaky :
1411+ def __eq__ (self , other ):
1412+ other ['x' ] = 42
1413+ return None
1414+
1415+ self .assertIsNone (view == Sneaky ())
1416+ self .assertEqual (mapping , {})
1417+
1418+ other = self .RecordingOperand ()
1419+ view = self .mappingproxy (self .MappingWithoutCopy (mapping ))
1420+ self .assertIsNone (view == other )
1421+ self .assertIs (type (other .other ), self .mappingproxy )
1422+
1423+ def test_union_does_not_expose_mapping (self ):
1424+ mapping = {}
1425+ view = self .mappingproxy (mapping )
1426+ mappingproxy = self .mappingproxy
1427+
1428+ class SneakyRor :
1429+ def __ror__ (self , other ):
1430+ other ['x' ] = 42
1431+ return None
1432+
1433+ class SneakyOr :
1434+ def __or__ (self , other ):
1435+ if type (other ) is mappingproxy :
1436+ return NotImplemented
1437+ other ['y' ] = 42
1438+ return None
1439+
1440+ self .assertIsNone (view | SneakyRor ())
1441+ self .assertEqual (mapping , {})
1442+ self .assertIsNone (SneakyOr () | view )
1443+ self .assertEqual (mapping , {})
1444+
1445+ other = self .RecordingOperand ()
1446+ view = self .mappingproxy (self .MappingWithoutCopy (mapping ))
1447+ self .assertIsNone (view | other )
1448+ self .assertIs (type (other .other ), self .mappingproxy )
1449+
1450+ def test_operator_dispatch_does_not_expose_type_dict (self ):
1451+ code = textwrap .dedent ("""
1452+ class SneakyEq:
1453+ def __eq__(self, other):
1454+ other['__mappingproxy_test_eq__'] = lambda self: None
1455+ return None
1456+
1457+ class SneakyRor:
1458+ def __ror__(self, other):
1459+ other['__mappingproxy_test_or__'] = lambda self: None
1460+ return None
1461+
1462+ vars(list) == SneakyEq()
1463+ vars(dict) | SneakyRor()
1464+
1465+ assert not hasattr(list, '__mappingproxy_test_eq__')
1466+ assert not hasattr(dict, '__mappingproxy_test_or__')
1467+ """ )
1468+ assert_python_ok ("-c" , code )
1469+
13841470 def test_hash (self ):
13851471 class HashableDict (dict ):
13861472 def __hash__ (self ):
0 commit comments