| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | # Tests for _speedups.LocationStore and NetUtils._LocationStore | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | import typing | 
					
						
							|  |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | import warnings | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | from NetUtils import LocationStore, _LocationStore | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | State = typing.Dict[typing.Tuple[int, int], typing.Set[int]] | 
					
						
							|  |  |  | RawLocations = typing.Dict[int, typing.Dict[int, typing.Tuple[int, int, int]]] | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  | ci = bool(os.environ.get("CI"))  # always set in GitHub actions | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | sample_data: RawLocations = { | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |     1: { | 
					
						
							|  |  |  |         11: (21, 2, 7), | 
					
						
							|  |  |  |         12: (22, 2, 0), | 
					
						
							|  |  |  |         13: (13, 1, 0), | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     2: { | 
					
						
							|  |  |  |         23: (11, 1, 0), | 
					
						
							|  |  |  |         22: (12, 1, 0), | 
					
						
							|  |  |  |         21: (23, 2, 0), | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     4: { | 
					
						
							|  |  |  |         9: (99, 3, 0), | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     3: { | 
					
						
							|  |  |  |         9: (99, 4, 0), | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |     5: { | 
					
						
							|  |  |  |         9: (99, 5, 0), | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | empty_state: State = { | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |     (0, slot): set() for slot in sample_data | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | full_state: State = { | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |     (0, slot): set(locations) for (slot, locations) in sample_data.items() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | one_state: State = { | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |     (0, 1): {12} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Base: | 
					
						
							|  |  |  |     class TestLocationStore(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         """Test method calls on a loaded store.""" | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |         store: typing.Union[LocationStore, _LocationStore] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_len(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |             self.assertEqual(len(self.store), 5) | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(len(self.store[1]), 3) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_key_error(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             with self.assertRaises(KeyError): | 
					
						
							|  |  |  |                 _ = self.store[0] | 
					
						
							|  |  |  |             with self.assertRaises(KeyError): | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |                 _ = self.store[6] | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             locations = self.store[1]  # no Exception | 
					
						
							|  |  |  |             with self.assertRaises(KeyError): | 
					
						
							|  |  |  |                 _ = locations[7] | 
					
						
							|  |  |  |             _ = locations[11]  # no Exception | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_getitem(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(self.store[1][11], (21, 2, 7)) | 
					
						
							|  |  |  |             self.assertEqual(self.store[1][13], (13, 1, 0)) | 
					
						
							|  |  |  |             self.assertEqual(self.store[2][22], (12, 1, 0)) | 
					
						
							|  |  |  |             self.assertEqual(self.store[4][9], (99, 3, 0)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_get(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(self.store.get(1, None), self.store[1]) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get(0, None), None) | 
					
						
							|  |  |  |             self.assertEqual(self.store[1].get(11, (None, None, None)), self.store[1][11]) | 
					
						
							|  |  |  |             self.assertEqual(self.store[1].get(10, (None, None, None)), (None, None, None)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_iter(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |             self.assertEqual(sorted(self.store), [1, 2, 3, 4, 5]) | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(len(self.store), len(sample_data)) | 
					
						
							|  |  |  |             self.assertEqual(list(self.store[1]), [11, 12, 13]) | 
					
						
							|  |  |  |             self.assertEqual(len(self.store[1]), len(sample_data[1])) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_items(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(sorted(p for p, _ in self.store.items()), sorted(self.store)) | 
					
						
							|  |  |  |             self.assertEqual(sorted(p for p, _ in self.store[1].items()), sorted(self.store[1])) | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store.items())[0][0], 1) | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store.items())[0][1], self.store[1]) | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store[1].items())[0][0], 11) | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store[1].items())[0][1], self.store[1][11]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_find_item(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |             # empty player set | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(sorted(self.store.find_item(set(), 99)), []) | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |             # no such player, single | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store.find_item({6}, 99)), []) | 
					
						
							|  |  |  |             # no such player, set | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store.find_item({7, 8, 9}, 99)), []) | 
					
						
							|  |  |  |             # no such item | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(sorted(self.store.find_item({3}, 1)), []) | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |             # valid matches | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(sorted(self.store.find_item({3}, 99)), | 
					
						
							|  |  |  |                              [(4, 9, 99, 3, 0)]) | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store.find_item({3, 4}, 99)), | 
					
						
							|  |  |  |                              [(3, 9, 99, 4, 0), (4, 9, 99, 3, 0)]) | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |             self.assertEqual(sorted(self.store.find_item({2, 3, 4}, 99)), | 
					
						
							|  |  |  |                              [(3, 9, 99, 4, 0), (4, 9, 99, 3, 0)]) | 
					
						
							|  |  |  |             # test hash collision in set | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store.find_item({3, 5}, 99)), | 
					
						
							|  |  |  |                              [(4, 9, 99, 3, 0), (5, 9, 99, 5, 0)]) | 
					
						
							|  |  |  |             self.assertEqual(sorted(self.store.find_item(set(range(2048)), 13)), | 
					
						
							|  |  |  |                              [(1, 13, 13, 1, 0)]) | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         def test_get_for_player(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(self.store.get_for_player(3), {4: {9}}) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_for_player(1), {1: {13}, 2: {22, 23}}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-29 19:44:10 +02:00
										 |  |  |         def test_get_checked(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(self.store.get_checked(full_state, 0, 1), [11, 12, 13]) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_checked(one_state, 0, 1), [12]) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_checked(empty_state, 0, 1), []) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_checked(full_state, 0, 3), [9]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-29 19:44:10 +02:00
										 |  |  |         def test_get_missing(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(self.store.get_missing(full_state, 0, 1), []) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_missing(one_state, 0, 1), [11, 13]) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_missing(empty_state, 0, 1), [11, 12, 13]) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_missing(empty_state, 0, 3), [9]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-29 19:44:10 +02:00
										 |  |  |         def test_get_remaining(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |             self.assertEqual(self.store.get_remaining(full_state, 0, 1), []) | 
					
						
							| 
									
										
										
										
											2024-08-16 13:20:02 -07:00
										 |  |  |             self.assertEqual(self.store.get_remaining(one_state, 0, 1), [(1, 13), (2, 21)]) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_remaining(empty_state, 0, 1), [(1, 13), (2, 21), (2, 22)]) | 
					
						
							|  |  |  |             self.assertEqual(self.store.get_remaining(empty_state, 0, 3), [(4, 99)]) | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-29 19:44:10 +02:00
										 |  |  |         def test_location_set_intersection(self) -> None: | 
					
						
							|  |  |  |             locations = {10, 11, 12} | 
					
						
							|  |  |  |             locations.intersection_update(self.store[1]) | 
					
						
							|  |  |  |             self.assertEqual(locations, {11, 12}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |     class TestLocationStoreConstructor(unittest.TestCase): | 
					
						
							|  |  |  |         """Test constructors for a given store type.""" | 
					
						
							|  |  |  |         type: type | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_hole(self) -> None: | 
					
						
							|  |  |  |             with self.assertRaises(Exception): | 
					
						
							|  |  |  |                 self.type({ | 
					
						
							|  |  |  |                     1: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                     3: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_no_slot1(self) -> None: | 
					
						
							|  |  |  |             with self.assertRaises(Exception): | 
					
						
							|  |  |  |                 self.type({ | 
					
						
							|  |  |  |                     2: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                     3: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_slot0(self) -> None: | 
					
						
							|  |  |  |             with self.assertRaises(ValueError): | 
					
						
							|  |  |  |                 self.type({ | 
					
						
							|  |  |  |                     0: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                     1: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             with self.assertRaises(ValueError): | 
					
						
							|  |  |  |                 self.type({ | 
					
						
							|  |  |  |                     0: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                     2: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_no_players(self) -> None: | 
					
						
							|  |  |  |             with self.assertRaises(Exception): | 
					
						
							|  |  |  |                 _ = self.type({}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_no_locations(self) -> None: | 
					
						
							|  |  |  |             with warnings.catch_warnings(): | 
					
						
							|  |  |  |                 warnings.simplefilter("ignore") | 
					
						
							|  |  |  |                 store = self.type({ | 
					
						
							|  |  |  |                     1: {}, | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |                 self.assertEqual(len(store), 1) | 
					
						
							|  |  |  |                 self.assertEqual(len(store[1]), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_no_locations_for_1(self) -> None: | 
					
						
							|  |  |  |             store = self.type({ | 
					
						
							|  |  |  |                 1: {}, | 
					
						
							|  |  |  |                 2: {1: (1, 2, 3)}, | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             self.assertEqual(len(store), 2) | 
					
						
							|  |  |  |             self.assertEqual(len(store[1]), 0) | 
					
						
							|  |  |  |             self.assertEqual(len(store[2]), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_no_locations_for_last(self) -> None: | 
					
						
							|  |  |  |             store = self.type({ | 
					
						
							|  |  |  |                 1: {1: (1, 2, 3)}, | 
					
						
							|  |  |  |                 2: {}, | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             self.assertEqual(len(store), 2) | 
					
						
							|  |  |  |             self.assertEqual(len(store[1]), 1) | 
					
						
							|  |  |  |             self.assertEqual(len(store[2]), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestPurePythonLocationStore(Base.TestLocationStore): | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |     """Run base method tests for pure python implementation.""" | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |     def setUp(self) -> None: | 
					
						
							|  |  |  |         self.store = _LocationStore(sample_data) | 
					
						
							|  |  |  |         super().setUp() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | class TestPurePythonLocationStoreConstructor(Base.TestLocationStoreConstructor): | 
					
						
							|  |  |  |     """Run base constructor tests for the pure python implementation.""" | 
					
						
							|  |  |  |     def setUp(self) -> None: | 
					
						
							|  |  |  |         self.type = _LocationStore | 
					
						
							|  |  |  |         super().setUp() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  | @unittest.skipIf(LocationStore is _LocationStore and not ci, "_speedups not available") | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  | class TestSpeedupsLocationStore(Base.TestLocationStore): | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |     """Run base method tests for cython implementation.""" | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |     def setUp(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |         self.assertFalse(LocationStore is _LocationStore, "Failed to load _speedups") | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |         self.store = LocationStore(sample_data) | 
					
						
							|  |  |  |         super().setUp() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  | @unittest.skipIf(LocationStore is _LocationStore and not ci, "_speedups not available") | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  | class TestSpeedupsLocationStoreConstructor(Base.TestLocationStoreConstructor): | 
					
						
							|  |  |  |     """Run base constructor tests and tests the additional constraints for cython implementation.""" | 
					
						
							|  |  |  |     def setUp(self) -> None: | 
					
						
							| 
									
										
										
										
											2024-06-12 18:54:59 +02:00
										 |  |  |         self.assertFalse(LocationStore is _LocationStore, "Failed to load _speedups") | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |         self.type = LocationStore | 
					
						
							|  |  |  |         super().setUp() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_float_key(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |         with self.assertRaises(Exception): | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |             self.type({ | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |                 1: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                 1.1: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |                 3: {1: (1, 1, 1)} | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |     def test_string_key(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |         with self.assertRaises(Exception): | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |             self.type({ | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |                 "1": {1: (1, 1, 1)}, | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |     def test_high_player_number(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |         with self.assertRaises(Exception): | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |             self.type({ | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |                 1 << 32: {1: (1, 1, 1)}, | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |     def test_not_a_tuple(self) -> None: | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |         with self.assertRaises(Exception): | 
					
						
							| 
									
										
										
										
											2023-07-05 10:35:03 +02:00
										 |  |  |             self.type({ | 
					
						
							| 
									
										
										
										
											2023-07-04 19:12:43 +02:00
										 |  |  |                 1: {1: None}, | 
					
						
							|  |  |  |             }) |