| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  | import unittest | 
					
						
							|  |  |  | from collections import OrderedDict, UserDict | 
					
						
							|  |  |  | from types import MappingProxyType | 
					
						
							| 
									
										
										
										
											2023-11-07 15:58:04 +02:00
										 |  |  | from test import support | 
					
						
							| 
									
										
										
										
											2024-04-10 17:32:57 +03:00
										 |  |  | from test.support import import_helper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _testcapi = import_helper.import_module("_testcapi") | 
					
						
							|  |  |  | _testlimitedcapi = import_helper.import_module("_testlimitedcapi") | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NULL = None | 
					
						
							| 
									
										
										
										
											2023-08-24 15:59:12 +02:00
										 |  |  | INVALID_UTF8 = b'\xff' | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | class DictSubclass(dict): | 
					
						
							|  |  |  |     def __getitem__(self, key): | 
					
						
							|  |  |  |         raise RuntimeError('do not get evil') | 
					
						
							|  |  |  |     def __setitem__(self, key, value): | 
					
						
							|  |  |  |         raise RuntimeError('do not set evil') | 
					
						
							|  |  |  |     def __delitem__(self, key): | 
					
						
							|  |  |  |         raise RuntimeError('do not del evil') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def gen(): | 
					
						
							|  |  |  |     yield 'a' | 
					
						
							|  |  |  |     yield 'b' | 
					
						
							|  |  |  |     yield 'c' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CAPITest(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_check(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         check = _testlimitedcapi.dict_check | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertTrue(check({1: 2})) | 
					
						
							|  |  |  |         self.assertTrue(check(OrderedDict({1: 2}))) | 
					
						
							|  |  |  |         self.assertFalse(check(UserDict({1: 2}))) | 
					
						
							|  |  |  |         self.assertFalse(check([1, 2])) | 
					
						
							|  |  |  |         self.assertFalse(check(object())) | 
					
						
							| 
									
										
										
										
											2023-11-07 15:58:04 +02:00
										 |  |  |         # CRASHES check(NULL) | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_checkexact(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         check = _testlimitedcapi.dict_checkexact | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertTrue(check({1: 2})) | 
					
						
							|  |  |  |         self.assertFalse(check(OrderedDict({1: 2}))) | 
					
						
							|  |  |  |         self.assertFalse(check(UserDict({1: 2}))) | 
					
						
							|  |  |  |         self.assertFalse(check([1, 2])) | 
					
						
							|  |  |  |         self.assertFalse(check(object())) | 
					
						
							| 
									
										
										
										
											2023-11-07 15:58:04 +02:00
										 |  |  |         # CRASHES check(NULL) | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_new(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         dict_new = _testlimitedcapi.dict_new | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = dict_new() | 
					
						
							|  |  |  |         self.assertEqual(dct, {}) | 
					
						
							|  |  |  |         self.assertIs(type(dct), dict) | 
					
						
							|  |  |  |         dct2 = dict_new() | 
					
						
							|  |  |  |         self.assertIsNot(dct2, dct) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dictproxy_new(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         dictproxy_new = _testlimitedcapi.dictproxy_new | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         for dct in {1: 2}, OrderedDict({1: 2}), UserDict({1: 2}): | 
					
						
							|  |  |  |             proxy = dictproxy_new(dct) | 
					
						
							|  |  |  |             self.assertIs(type(proxy), MappingProxyType) | 
					
						
							|  |  |  |             self.assertEqual(proxy, dct) | 
					
						
							|  |  |  |             with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                 proxy[1] = 3 | 
					
						
							|  |  |  |             self.assertEqual(proxy[1], 2) | 
					
						
							|  |  |  |             dct[1] = 4 | 
					
						
							|  |  |  |             self.assertEqual(proxy[1], 4) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(TypeError, dictproxy_new, []) | 
					
						
							|  |  |  |         self.assertRaises(TypeError, dictproxy_new, 42) | 
					
						
							|  |  |  |         # CRASHES dictproxy_new(NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_copy(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         copy = _testlimitedcapi.dict_copy | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         for dct in {1: 2}, OrderedDict({1: 2}): | 
					
						
							|  |  |  |             dct_copy = copy(dct) | 
					
						
							|  |  |  |             self.assertIs(type(dct_copy), dict) | 
					
						
							|  |  |  |             self.assertEqual(dct_copy, dct) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(SystemError, copy, UserDict()) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, copy, []) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, copy, 42) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, copy, NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_clear(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         clear = _testlimitedcapi.dict_clear | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {1: 2} | 
					
						
							|  |  |  |         clear(dct) | 
					
						
							|  |  |  |         self.assertEqual(dct, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # NOTE: It is not safe to call it with OrderedDict. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Has no effect for non-dicts. | 
					
						
							|  |  |  |         dct = UserDict({1: 2}) | 
					
						
							|  |  |  |         clear(dct) | 
					
						
							|  |  |  |         self.assertEqual(dct, {1: 2}) | 
					
						
							|  |  |  |         lst = [1, 2] | 
					
						
							|  |  |  |         clear(lst) | 
					
						
							|  |  |  |         self.assertEqual(lst, [1, 2]) | 
					
						
							|  |  |  |         clear(object()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CRASHES? clear(NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_size(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         size = _testlimitedcapi.dict_size | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertEqual(size({1: 2}), 1) | 
					
						
							|  |  |  |         self.assertEqual(size(OrderedDict({1: 2})), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(SystemError, size, UserDict()) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, size, []) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, size, 42) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, size, object()) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, size, NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_getitem(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         getitem = _testlimitedcapi.dict_getitem | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {'a': 1, '\U0001f40d': 2} | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct, 'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitem(dct, 'b'), KeyError) | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct, '\U0001f40d'), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass(dct) | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct2, 'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitem(dct2, 'b'), KeyError) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-07 15:58:04 +02:00
										 |  |  |         with support.catch_unraisable_exception() as cm: | 
					
						
							|  |  |  |             self.assertIs(getitem({}, []), KeyError)  # unhashable | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_type, TypeError) | 
					
						
							|  |  |  |             self.assertEqual(str(cm.unraisable.exc_value), | 
					
						
							|  |  |  |                              "unhashable type: 'list'") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertIs(getitem(42, 'a'), KeyError) | 
					
						
							|  |  |  |         self.assertIs(getitem([1], 0), KeyError) | 
					
						
							|  |  |  |         # CRASHES getitem({}, NULL) | 
					
						
							|  |  |  |         # CRASHES getitem(NULL, 'a') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_getitemstring(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         getitemstring = _testlimitedcapi.dict_getitemstring | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {'a': 1, '\U0001f40d': 2} | 
					
						
							|  |  |  |         self.assertEqual(getitemstring(dct, b'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitemstring(dct, b'b'), KeyError) | 
					
						
							|  |  |  |         self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass(dct) | 
					
						
							|  |  |  |         self.assertEqual(getitemstring(dct2, b'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitemstring(dct2, b'b'), KeyError) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-07 15:58:04 +02:00
										 |  |  |         with support.catch_unraisable_exception() as cm: | 
					
						
							|  |  |  |             self.assertIs(getitemstring({}, INVALID_UTF8), KeyError) | 
					
						
							|  |  |  |             self.assertEqual(cm.unraisable.exc_type, UnicodeDecodeError) | 
					
						
							|  |  |  |             self.assertRegex(str(cm.unraisable.exc_value), | 
					
						
							|  |  |  |                              "'utf-8' codec can't decode") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertIs(getitemstring(42, b'a'), KeyError) | 
					
						
							|  |  |  |         self.assertIs(getitemstring([], b'a'), KeyError) | 
					
						
							|  |  |  |         # CRASHES getitemstring({}, NULL) | 
					
						
							|  |  |  |         # CRASHES getitemstring(NULL, b'a') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_getitemref(self): | 
					
						
							|  |  |  |         getitem = _testcapi.dict_getitemref | 
					
						
							|  |  |  |         dct = {'a': 1, '\U0001f40d': 2} | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct, 'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitem(dct, 'b'), KeyError) | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct, '\U0001f40d'), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass(dct) | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct2, 'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitem(dct2, 'b'), KeyError) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(SystemError, getitem, 42, 'a') | 
					
						
							|  |  |  |         self.assertRaises(TypeError, getitem, {}, [])  # unhashable | 
					
						
							|  |  |  |         self.assertRaises(SystemError, getitem, [], 1) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, getitem, [], 'a') | 
					
						
							|  |  |  |         # CRASHES getitem({}, NULL) | 
					
						
							|  |  |  |         # CRASHES getitem(NULL, 'a') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_getitemstringref(self): | 
					
						
							|  |  |  |         getitemstring = _testcapi.dict_getitemstringref | 
					
						
							|  |  |  |         dct = {'a': 1, '\U0001f40d': 2} | 
					
						
							|  |  |  |         self.assertEqual(getitemstring(dct, b'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitemstring(dct, b'b'), KeyError) | 
					
						
							|  |  |  |         self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass(dct) | 
					
						
							|  |  |  |         self.assertEqual(getitemstring(dct2, b'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitemstring(dct2, b'b'), KeyError) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(SystemError, getitemstring, 42, b'a') | 
					
						
							| 
									
										
										
										
											2023-08-24 15:59:12 +02:00
										 |  |  |         self.assertRaises(UnicodeDecodeError, getitemstring, {}, INVALID_UTF8) | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertRaises(SystemError, getitemstring, [], b'a') | 
					
						
							|  |  |  |         # CRASHES getitemstring({}, NULL) | 
					
						
							|  |  |  |         # CRASHES getitemstring(NULL, b'a') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_getitemwitherror(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         getitem = _testlimitedcapi.dict_getitemwitherror | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {'a': 1, '\U0001f40d': 2} | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct, 'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitem(dct, 'b'), KeyError) | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct, '\U0001f40d'), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass(dct) | 
					
						
							|  |  |  |         self.assertEqual(getitem(dct2, 'a'), 1) | 
					
						
							|  |  |  |         self.assertIs(getitem(dct2, 'b'), KeyError) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(SystemError, getitem, 42, 'a') | 
					
						
							|  |  |  |         self.assertRaises(TypeError, getitem, {}, [])  # unhashable | 
					
						
							|  |  |  |         self.assertRaises(SystemError, getitem, [], 1) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, getitem, [], 'a') | 
					
						
							|  |  |  |         # CRASHES getitem({}, NULL) | 
					
						
							|  |  |  |         # CRASHES getitem(NULL, 'a') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_contains(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         contains = _testlimitedcapi.dict_contains | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {'a': 1, '\U0001f40d': 2} | 
					
						
							|  |  |  |         self.assertTrue(contains(dct, 'a')) | 
					
						
							|  |  |  |         self.assertFalse(contains(dct, 'b')) | 
					
						
							|  |  |  |         self.assertTrue(contains(dct, '\U0001f40d')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass(dct) | 
					
						
							|  |  |  |         self.assertTrue(contains(dct2, 'a')) | 
					
						
							|  |  |  |         self.assertFalse(contains(dct2, 'b')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(TypeError, contains, {}, [])  # unhashable | 
					
						
							|  |  |  |         # CRASHES contains({}, NULL) | 
					
						
							|  |  |  |         # CRASHES contains(UserDict(), 'a') | 
					
						
							|  |  |  |         # CRASHES contains(42, 'a') | 
					
						
							|  |  |  |         # CRASHES contains(NULL, 'a') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-24 15:59:12 +02:00
										 |  |  |     def test_dict_contains_string(self): | 
					
						
							|  |  |  |         contains_string = _testcapi.dict_containsstring | 
					
						
							|  |  |  |         dct = {'a': 1, '\U0001f40d': 2} | 
					
						
							|  |  |  |         self.assertTrue(contains_string(dct, b'a')) | 
					
						
							|  |  |  |         self.assertFalse(contains_string(dct, b'b')) | 
					
						
							|  |  |  |         self.assertTrue(contains_string(dct, '\U0001f40d'.encode())) | 
					
						
							|  |  |  |         self.assertRaises(UnicodeDecodeError, contains_string, dct, INVALID_UTF8) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass(dct) | 
					
						
							|  |  |  |         self.assertTrue(contains_string(dct2, b'a')) | 
					
						
							|  |  |  |         self.assertFalse(contains_string(dct2, b'b')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CRASHES contains({}, NULL) | 
					
						
							|  |  |  |         # CRASHES contains(NULL, b'a') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |     def test_dict_setitem(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         setitem = _testlimitedcapi.dict_setitem | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {} | 
					
						
							|  |  |  |         setitem(dct, 'a', 5) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5}) | 
					
						
							|  |  |  |         setitem(dct, '\U0001f40d', 8) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass() | 
					
						
							|  |  |  |         setitem(dct2, 'a', 5) | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'a': 5}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(TypeError, setitem, {}, [], 5)  # unhashable | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setitem, UserDict(), 'a', 5) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setitem, [1], 0, 5) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setitem, 42, 'a', 5) | 
					
						
							|  |  |  |         # CRASHES setitem({}, NULL, 5) | 
					
						
							|  |  |  |         # CRASHES setitem({}, 'a', NULL) | 
					
						
							|  |  |  |         # CRASHES setitem(NULL, 'a', 5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_setitemstring(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         setitemstring = _testlimitedcapi.dict_setitemstring | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {} | 
					
						
							|  |  |  |         setitemstring(dct, b'a', 5) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5}) | 
					
						
							|  |  |  |         setitemstring(dct, '\U0001f40d'.encode(), 8) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5, '\U0001f40d': 8}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass() | 
					
						
							|  |  |  |         setitemstring(dct2, b'a', 5) | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'a': 5}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-24 15:59:12 +02:00
										 |  |  |         self.assertRaises(UnicodeDecodeError, setitemstring, {}, INVALID_UTF8, 5) | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertRaises(SystemError, setitemstring, UserDict(), b'a', 5) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setitemstring, 42, b'a', 5) | 
					
						
							|  |  |  |         # CRASHES setitemstring({}, NULL, 5) | 
					
						
							|  |  |  |         # CRASHES setitemstring({}, b'a', NULL) | 
					
						
							|  |  |  |         # CRASHES setitemstring(NULL, b'a', 5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_delitem(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         delitem = _testlimitedcapi.dict_delitem | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {'a': 1, 'c': 2, '\U0001f40d': 3} | 
					
						
							|  |  |  |         delitem(dct, 'a') | 
					
						
							|  |  |  |         self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) | 
					
						
							|  |  |  |         self.assertRaises(KeyError, delitem, dct, 'b') | 
					
						
							|  |  |  |         delitem(dct, '\U0001f40d') | 
					
						
							|  |  |  |         self.assertEqual(dct, {'c': 2}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass({'a': 1, 'c': 2}) | 
					
						
							|  |  |  |         delitem(dct2, 'a') | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'c': 2}) | 
					
						
							|  |  |  |         self.assertRaises(KeyError, delitem, dct2, 'b') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(TypeError, delitem, {}, [])  # unhashable | 
					
						
							|  |  |  |         self.assertRaises(SystemError, delitem, UserDict({'a': 1}), 'a') | 
					
						
							|  |  |  |         self.assertRaises(SystemError, delitem, [1], 0) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, delitem, 42, 'a') | 
					
						
							|  |  |  |         # CRASHES delitem({}, NULL) | 
					
						
							|  |  |  |         # CRASHES delitem(NULL, 'a') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_delitemstring(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         delitemstring = _testlimitedcapi.dict_delitemstring | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         dct = {'a': 1, 'c': 2, '\U0001f40d': 3} | 
					
						
							|  |  |  |         delitemstring(dct, b'a') | 
					
						
							|  |  |  |         self.assertEqual(dct, {'c': 2, '\U0001f40d': 3}) | 
					
						
							|  |  |  |         self.assertRaises(KeyError, delitemstring, dct, b'b') | 
					
						
							|  |  |  |         delitemstring(dct, '\U0001f40d'.encode()) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'c': 2}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass({'a': 1, 'c': 2}) | 
					
						
							|  |  |  |         delitemstring(dct2, b'a') | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'c': 2}) | 
					
						
							|  |  |  |         self.assertRaises(KeyError, delitemstring, dct2, b'b') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-24 15:59:12 +02:00
										 |  |  |         self.assertRaises(UnicodeDecodeError, delitemstring, {}, INVALID_UTF8) | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertRaises(SystemError, delitemstring, UserDict({'a': 1}), b'a') | 
					
						
							|  |  |  |         self.assertRaises(SystemError, delitemstring, 42, b'a') | 
					
						
							|  |  |  |         # CRASHES delitemstring({}, NULL) | 
					
						
							|  |  |  |         # CRASHES delitemstring(NULL, b'a') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_setdefault(self): | 
					
						
							|  |  |  |         setdefault = _testcapi.dict_setdefault | 
					
						
							|  |  |  |         dct = {} | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct, 'a', 5), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5}) | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct, 'a', 8), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass() | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct2, 'a', 5), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'a': 5}) | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct2, 'a', 8), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'a': 5}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(TypeError, setdefault, {}, [], 5)  # unhashable | 
					
						
							| 
									
										
										
										
											2024-02-06 11:36:23 -05:00
										 |  |  |         self.assertRaises(SystemError, setdefault, UserDict(), 'a', 5) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setdefault, [1], 0, 5) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setdefault, 42, 'a', 5) | 
					
						
							|  |  |  |         # CRASHES setdefault({}, NULL, 5) | 
					
						
							|  |  |  |         # CRASHES setdefault({}, 'a', NULL) | 
					
						
							|  |  |  |         # CRASHES setdefault(NULL, 'a', 5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_setdefaultref(self): | 
					
						
							|  |  |  |         setdefault = _testcapi.dict_setdefaultref | 
					
						
							|  |  |  |         dct = {} | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct, 'a', 5), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5}) | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct, 'a', 8), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct, {'a': 5}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dct2 = DictSubclass() | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct2, 'a', 5), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'a': 5}) | 
					
						
							|  |  |  |         self.assertEqual(setdefault(dct2, 'a', 8), 5) | 
					
						
							|  |  |  |         self.assertEqual(dct2, {'a': 5}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(TypeError, setdefault, {}, [], 5)  # unhashable | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertRaises(SystemError, setdefault, UserDict(), 'a', 5) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setdefault, [1], 0, 5) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, setdefault, 42, 'a', 5) | 
					
						
							|  |  |  |         # CRASHES setdefault({}, NULL, 5) | 
					
						
							|  |  |  |         # CRASHES setdefault({}, 'a', NULL) | 
					
						
							|  |  |  |         # CRASHES setdefault(NULL, 'a', 5) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_mapping_keys_valuesitems(self): | 
					
						
							|  |  |  |         class BadMapping(dict): | 
					
						
							|  |  |  |             def keys(self): | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |             def values(self): | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |             def items(self): | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |         dict_obj = {'foo': 1, 'bar': 2, 'spam': 3} | 
					
						
							|  |  |  |         for mapping in [dict_obj, DictSubclass(dict_obj), BadMapping(dict_obj)]: | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |             self.assertListEqual(_testlimitedcapi.dict_keys(mapping), | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |                                  list(dict_obj.keys())) | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |             self.assertListEqual(_testlimitedcapi.dict_values(mapping), | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |                                  list(dict_obj.values())) | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |             self.assertListEqual(_testlimitedcapi.dict_items(mapping), | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |                                  list(dict_obj.items())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_keys_valuesitems_bad_arg(self): | 
					
						
							|  |  |  |         for mapping in UserDict(), [], object(): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |             self.assertRaises(SystemError, _testlimitedcapi.dict_keys, mapping) | 
					
						
							|  |  |  |             self.assertRaises(SystemError, _testlimitedcapi.dict_values, mapping) | 
					
						
							|  |  |  |             self.assertRaises(SystemError, _testlimitedcapi.dict_items, mapping) | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_next(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         dict_next = _testlimitedcapi.dict_next | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         self.assertIsNone(dict_next({}, 0)) | 
					
						
							|  |  |  |         dct = {'a': 1, 'b': 2, 'c': 3} | 
					
						
							|  |  |  |         pos = 0 | 
					
						
							|  |  |  |         pairs = [] | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             res = dict_next(dct, pos) | 
					
						
							|  |  |  |             if res is None: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             rc, pos, key, value = res | 
					
						
							|  |  |  |             self.assertEqual(rc, 1) | 
					
						
							|  |  |  |             pairs.append((key, value)) | 
					
						
							|  |  |  |         self.assertEqual(pairs, list(dct.items())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CRASHES dict_next(NULL, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_update(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         update = _testlimitedcapi.dict_update | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         for cls1 in dict, DictSubclass: | 
					
						
							|  |  |  |             for cls2 in dict, DictSubclass, UserDict: | 
					
						
							|  |  |  |                 dct = cls1({'a': 1, 'b': 2}) | 
					
						
							|  |  |  |                 update(dct, cls2({'b': 3, 'c': 4})) | 
					
						
							|  |  |  |                 self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(AttributeError, update, {}, []) | 
					
						
							|  |  |  |         self.assertRaises(AttributeError, update, {}, 42) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, update, UserDict(), {}) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, update, 42, {}) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, update, {}, NULL) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, update, NULL, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_merge(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         merge = _testlimitedcapi.dict_merge | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         for cls1 in dict, DictSubclass: | 
					
						
							|  |  |  |             for cls2 in dict, DictSubclass, UserDict: | 
					
						
							|  |  |  |                 dct = cls1({'a': 1, 'b': 2}) | 
					
						
							|  |  |  |                 merge(dct, cls2({'b': 3, 'c': 4}), 0) | 
					
						
							|  |  |  |                 self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4}) | 
					
						
							|  |  |  |                 dct = cls1({'a': 1, 'b': 2}) | 
					
						
							|  |  |  |                 merge(dct, cls2({'b': 3, 'c': 4}), 1) | 
					
						
							|  |  |  |                 self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(AttributeError, merge, {}, [], 0) | 
					
						
							|  |  |  |         self.assertRaises(AttributeError, merge, {}, 42, 0) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, merge, UserDict(), {}, 0) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, merge, 42, {}, 0) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, merge, {}, NULL, 0) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, merge, NULL, {}, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_mergefromseq2(self): | 
					
						
							| 
									
										
										
										
											2024-03-19 16:06:20 +01:00
										 |  |  |         mergefromseq2 = _testlimitedcapi.dict_mergefromseq2 | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  |         for cls1 in dict, DictSubclass: | 
					
						
							|  |  |  |             for cls2 in list, iter: | 
					
						
							|  |  |  |                 dct = cls1({'a': 1, 'b': 2}) | 
					
						
							|  |  |  |                 mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 0) | 
					
						
							|  |  |  |                 self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4}) | 
					
						
							|  |  |  |                 dct = cls1({'a': 1, 'b': 2}) | 
					
						
							|  |  |  |                 mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 1) | 
					
						
							|  |  |  |                 self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertRaises(ValueError, mergefromseq2, {}, [(1,)], 0) | 
					
						
							|  |  |  |         self.assertRaises(ValueError, mergefromseq2, {}, [(1, 2, 3)], 0) | 
					
						
							|  |  |  |         self.assertRaises(TypeError, mergefromseq2, {}, [1], 0) | 
					
						
							|  |  |  |         self.assertRaises(TypeError, mergefromseq2, {}, 42, 0) | 
					
						
							|  |  |  |         # CRASHES mergefromseq2(UserDict(), [], 0) | 
					
						
							|  |  |  |         # CRASHES mergefromseq2(42, [], 0) | 
					
						
							|  |  |  |         # CRASHES mergefromseq2({}, NULL, 0) | 
					
						
							|  |  |  |         # CRASHES mergefromseq2(NULL, {}, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-14 13:51:00 +01:00
										 |  |  |     def test_dict_pop(self): | 
					
						
							|  |  |  |         # Test PyDict_Pop() | 
					
						
							|  |  |  |         dict_pop = _testcapi.dict_pop | 
					
						
							|  |  |  |         dict_pop_null = _testcapi.dict_pop_null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key present, get removed value | 
					
						
							|  |  |  |         mydict = {"key": "value", "key2": "value2"} | 
					
						
							|  |  |  |         self.assertEqual(dict_pop(mydict, "key"), (1, "value")) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {"key2": "value2"}) | 
					
						
							|  |  |  |         self.assertEqual(dict_pop(mydict, "key2"), (1, "value2")) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key present, ignore removed value | 
					
						
							|  |  |  |         mydict = {"key": "value", "key2": "value2"} | 
					
						
							|  |  |  |         self.assertEqual(dict_pop_null(mydict, "key"), 1) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {"key2": "value2"}) | 
					
						
							|  |  |  |         self.assertEqual(dict_pop_null(mydict, "key2"), 1) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key missing, expect removed value; empty dict has a fast path | 
					
						
							|  |  |  |         self.assertEqual(dict_pop({}, "key"), (0, NULL)) | 
					
						
							|  |  |  |         self.assertEqual(dict_pop({"a": 1}, "key"), (0, NULL)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key missing, ignored removed value; empty dict has a fast path | 
					
						
							|  |  |  |         self.assertEqual(dict_pop_null({}, "key"), 0) | 
					
						
							|  |  |  |         self.assertEqual(dict_pop_null({"a": 1}, "key"), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # dict error | 
					
						
							|  |  |  |         not_dict = UserDict({1: 2}) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, dict_pop, not_dict, "key") | 
					
						
							|  |  |  |         self.assertRaises(SystemError, dict_pop_null, not_dict, "key") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key error; don't hash key if dict is empty | 
					
						
							|  |  |  |         not_hashable_key = ["list"] | 
					
						
							|  |  |  |         self.assertEqual(dict_pop({}, not_hashable_key), (0, NULL)) | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             dict_pop({'key': 1}, not_hashable_key) | 
					
						
							|  |  |  |         dict_pop({}, NULL)  # key is not checked if dict is empty | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CRASHES dict_pop(NULL, "key") | 
					
						
							|  |  |  |         # CRASHES dict_pop({"a": 1}, NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_popstring(self): | 
					
						
							|  |  |  |         # Test PyDict_PopString() | 
					
						
							|  |  |  |         dict_popstring = _testcapi.dict_popstring | 
					
						
							|  |  |  |         dict_popstring_null = _testcapi.dict_popstring_null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key present, get removed value | 
					
						
							|  |  |  |         mydict = {"key": "value", "key2": "value2"} | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring(mydict, "key"), (1, "value")) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {"key2": "value2"}) | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring(mydict, "key2"), (1, "value2")) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key present, ignore removed value | 
					
						
							|  |  |  |         mydict = {"key": "value", "key2": "value2"} | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring_null(mydict, "key"), 1) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {"key2": "value2"}) | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring_null(mydict, "key2"), 1) | 
					
						
							|  |  |  |         self.assertEqual(mydict, {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key missing; empty dict has a fast path | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring({}, "key"), (0, NULL)) | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring_null({}, "key"), 0) | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring({"a": 1}, "key"), (0, NULL)) | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring_null({"a": 1}, "key"), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # non-ASCII key | 
					
						
							|  |  |  |         non_ascii = '\U0001f40d' | 
					
						
							|  |  |  |         dct = {'\U0001f40d': 123} | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring(dct, '\U0001f40d'.encode()), (1, 123)) | 
					
						
							|  |  |  |         dct = {'\U0001f40d': 123} | 
					
						
							|  |  |  |         self.assertEqual(dict_popstring_null(dct, '\U0001f40d'.encode()), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # dict error | 
					
						
							|  |  |  |         not_dict = UserDict({1: 2}) | 
					
						
							|  |  |  |         self.assertRaises(SystemError, dict_popstring, not_dict, "key") | 
					
						
							|  |  |  |         self.assertRaises(SystemError, dict_popstring_null, not_dict, "key") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # key error | 
					
						
							|  |  |  |         self.assertRaises(UnicodeDecodeError, dict_popstring, {1: 2}, INVALID_UTF8) | 
					
						
							|  |  |  |         self.assertRaises(UnicodeDecodeError, dict_popstring_null, {1: 2}, INVALID_UTF8) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # CRASHES dict_popstring(NULL, "key") | 
					
						
							|  |  |  |         # CRASHES dict_popstring({}, NULL) | 
					
						
							|  |  |  |         # CRASHES dict_popstring({"a": 1}, NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-07 18:51:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     unittest.main() |