| 
									
										
										
										
											2023-08-10 13:34:00 +01:00
										 |  |  | import copy | 
					
						
							|  |  |  | import pickle | 
					
						
							| 
									
										
										
										
											2023-06-22 15:02:38 -07:00
										 |  |  | import dis | 
					
						
							|  |  |  | import threading | 
					
						
							|  |  |  | import types | 
					
						
							| 
									
										
										
										
											2020-11-05 09:23:15 +00:00
										 |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2024-02-29 18:53:32 -08:00
										 |  |  | from test.support import threading_helper, check_impl_detail, requires_specialization | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  | from test.support.import_helper import import_module | 
					
						
							| 
									
										
										
										
											2023-09-22 23:51:58 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Skip this module on other interpreters, it is cpython specific: | 
					
						
							|  |  |  | if check_impl_detail(cpython=False): | 
					
						
							|  |  |  |     raise unittest.SkipTest('implementation detail specific to cpython') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 15:11:36 +02:00
										 |  |  | _testinternalcapi = import_module("_testinternalcapi") | 
					
						
							| 
									
										
										
										
											2020-11-05 09:23:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-18 10:10:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-25 09:40:27 -07:00
										 |  |  | def disabling_optimizer(func): | 
					
						
							|  |  |  |     def wrapper(*args, **kwargs): | 
					
						
							| 
									
										
										
										
											2024-04-30 18:26:34 -07:00
										 |  |  |         if not hasattr(_testinternalcapi, "get_optimizer"): | 
					
						
							|  |  |  |             return func(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											2023-08-25 09:40:27 -07:00
										 |  |  |         old_opt = _testinternalcapi.get_optimizer() | 
					
						
							|  |  |  |         _testinternalcapi.set_optimizer(None) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return func(*args, **kwargs) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             _testinternalcapi.set_optimizer(old_opt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return wrapper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 11:45:51 -06:00
										 |  |  | class TestLoadSuperAttrCache(unittest.TestCase): | 
					
						
							|  |  |  |     def test_descriptor_not_double_executed_on_spec_fail(self): | 
					
						
							|  |  |  |         calls = [] | 
					
						
							|  |  |  |         class Descriptor: | 
					
						
							|  |  |  |             def __get__(self, instance, owner): | 
					
						
							|  |  |  |                 calls.append((instance, owner)) | 
					
						
							|  |  |  |                 return lambda: 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             d = Descriptor() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class D(C): | 
					
						
							|  |  |  |             def f(self): | 
					
						
							|  |  |  |                 return super().d() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         d = D() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(d.f(), 1)  # warmup | 
					
						
							|  |  |  |         calls.clear() | 
					
						
							|  |  |  |         self.assertEqual(d.f(), 1)  # try to specialize | 
					
						
							|  |  |  |         self.assertEqual(calls, [(d, D)]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 09:23:15 +00:00
										 |  |  | class TestLoadAttrCache(unittest.TestCase): | 
					
						
							|  |  |  |     def test_descriptor_added_after_optimization(self): | 
					
						
							|  |  |  |         class Descriptor: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class C: | 
					
						
							|  |  |  |             def __init__(self): | 
					
						
							|  |  |  |                 self.x = 1 | 
					
						
							|  |  |  |             x = Descriptor() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(o): | 
					
						
							|  |  |  |             return o.x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         o = C() | 
					
						
							|  |  |  |         for i in range(1025): | 
					
						
							|  |  |  |             assert f(o) == 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Descriptor.__get__ = lambda self, instance, value: 2 | 
					
						
							|  |  |  |         Descriptor.__set__ = lambda *args: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertEqual(f(o), 2) | 
					
						
							| 
									
										
										
										
											2022-07-18 10:10:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_descriptor_added_after_optimization(self): | 
					
						
							|  |  |  |         class Descriptor: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             attribute = Descriptor() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             attribute = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __get__(self, instance, owner): | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __set__(self, instance, value): | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Descriptor.__get__ = __get__ | 
					
						
							|  |  |  |         Descriptor.__set__ = __set__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_descriptor_shadows_class_attribute(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             attribute = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_set_descriptor_after_optimization(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             attribute = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @property | 
					
						
							|  |  |  |         def attribute(self): | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Metaclass.attribute = attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_del_descriptor_after_optimization(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             attribute = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         del Metaclass.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_type_descriptor_shadows_attribute_method(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             mro = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.mro | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertIsNone(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_type_descriptor_shadows_attribute_member(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             __base__ = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.__base__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertIs(f(), object) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_type_descriptor_shadows_attribute_getset(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             __name__ = "Spam" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.__name__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertEqual(f(), "Class") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_getattribute(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             def __getattribute__(self, name): | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             attribute = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_swap(self): | 
					
						
							|  |  |  |         class OldMetaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class NewMetaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=OldMetaclass): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Class.__class__ = NewMetaclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 03:50:34 -08:00
										 |  |  |     def test_load_shadowing_slot_should_raise_type_error(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             __slots__ = ("slot",) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Sneaky: | 
					
						
							|  |  |  |             __slots__ = ("shadowed",) | 
					
						
							|  |  |  |             shadowing = Class.slot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(o): | 
					
						
							|  |  |  |             o.shadowing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         o = Sneaky() | 
					
						
							|  |  |  |         o.shadowed = 42 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                 f(o) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_store_shadowing_slot_should_raise_type_error(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             __slots__ = ("slot",) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Sneaky: | 
					
						
							|  |  |  |             __slots__ = ("shadowed",) | 
					
						
							|  |  |  |             shadowing = Class.slot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(o): | 
					
						
							|  |  |  |             o.shadowing = 42 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         o = Sneaky() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                 f(o) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_borrowed_slot_should_not_crash(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             __slots__ = ("slot",) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Sneaky: | 
					
						
							|  |  |  |             borrowed = Class.slot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(o): | 
					
						
							|  |  |  |             o.borrowed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         o = Sneaky() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                 f(o) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_store_borrowed_slot_should_not_crash(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             __slots__ = ("slot",) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Sneaky: | 
					
						
							|  |  |  |             borrowed = Class.slot | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(o): | 
					
						
							|  |  |  |             o.borrowed = 42 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         o = Sneaky() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             with self.assertRaises(TypeError): | 
					
						
							|  |  |  |                 f(o) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-18 10:10:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TestLoadMethodCache(unittest.TestCase): | 
					
						
							|  |  |  |     def test_descriptor_added_after_optimization(self): | 
					
						
							|  |  |  |         class Descriptor: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             attribute = Descriptor() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __get__(self, instance, owner): | 
					
						
							|  |  |  |             return lambda: False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __set__(self, instance, value): | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def attribute(): | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         instance = Class() | 
					
						
							|  |  |  |         instance.attribute = attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return instance.attribute() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Descriptor.__get__ = __get__ | 
					
						
							|  |  |  |         Descriptor.__set__ = __set__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_descriptor_added_after_optimization(self): | 
					
						
							|  |  |  |         class Descriptor: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             attribute = Descriptor() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             def attribute(): | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __get__(self, instance, owner): | 
					
						
							|  |  |  |             return lambda: False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __set__(self, instance, value): | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Descriptor.__get__ = __get__ | 
					
						
							|  |  |  |         Descriptor.__set__ = __set__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_descriptor_shadows_class_attribute(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return lambda: True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             def attribute(): | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_set_descriptor_after_optimization(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             def attribute(): | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @property | 
					
						
							|  |  |  |         def attribute(self): | 
					
						
							|  |  |  |             return lambda: False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Metaclass.attribute = attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_del_descriptor_after_optimization(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return lambda: True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             def attribute(): | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         del Metaclass.attribute | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_type_descriptor_shadows_attribute_method(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             def mro(): | 
					
						
							|  |  |  |                 return ["Spam", "eggs"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.mro() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertEqual(f(), ["Spam", "eggs"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_type_descriptor_shadows_attribute_member(self): | 
					
						
							|  |  |  |         class Class: | 
					
						
							|  |  |  |             def __base__(): | 
					
						
							|  |  |  |                 return "Spam" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.__base__() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertNotEqual(f(), "Spam") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_getattribute(self): | 
					
						
							|  |  |  |         class Metaclass(type): | 
					
						
							|  |  |  |             def __getattribute__(self, name): | 
					
						
							|  |  |  |                 return lambda: True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=Metaclass): | 
					
						
							|  |  |  |             def attribute(): | 
					
						
							|  |  |  |                 return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_metaclass_swap(self): | 
					
						
							|  |  |  |         class OldMetaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return lambda: True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class NewMetaclass(type): | 
					
						
							|  |  |  |             @property | 
					
						
							|  |  |  |             def attribute(self): | 
					
						
							|  |  |  |                 return lambda: False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class Class(metaclass=OldMetaclass): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             return Class.attribute() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertTrue(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Class.__class__ = NewMetaclass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             self.assertFalse(f()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-16 11:01:15 -07:00
										 |  |  | class TestCallCache(unittest.TestCase): | 
					
						
							|  |  |  |     def test_too_many_defaults_0(self): | 
					
						
							|  |  |  |         def f(): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         f.__defaults__ = (None,) | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             f() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_too_many_defaults_1(self): | 
					
						
							|  |  |  |         def f(x): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         f.__defaults__ = (None, None) | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             f(None) | 
					
						
							|  |  |  |             f() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_too_many_defaults_2(self): | 
					
						
							|  |  |  |         def f(x, y): | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         f.__defaults__ = (None, None, None) | 
					
						
							|  |  |  |         for _ in range(1025): | 
					
						
							|  |  |  |             f(None, None) | 
					
						
							|  |  |  |             f(None) | 
					
						
							|  |  |  |             f() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-28 13:04:59 -07:00
										 |  |  | @threading_helper.requires_working_threading() | 
					
						
							| 
									
										
										
										
											2024-02-29 18:53:32 -08:00
										 |  |  | @requires_specialization | 
					
						
							| 
									
										
										
										
											2023-06-22 15:02:38 -07:00
										 |  |  | class TestRacesDoNotCrash(unittest.TestCase): | 
					
						
							|  |  |  |     # Careful with these. Bigger numbers have a higher chance of catching bugs, | 
					
						
							|  |  |  |     # but you can also burn through a *ton* of type/dict/function versions: | 
					
						
							|  |  |  |     ITEMS = 1000 | 
					
						
							|  |  |  |     LOOPS = 4 | 
					
						
							|  |  |  |     WARMUPS = 2 | 
					
						
							|  |  |  |     WRITERS = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def assert_specialized(self, f, opname): | 
					
						
							|  |  |  |         instructions = dis.get_instructions(f, adaptive=True) | 
					
						
							|  |  |  |         opnames = {instruction.opname for instruction in instructions} | 
					
						
							|  |  |  |         self.assertIn(opname, opnames) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-25 09:40:27 -07:00
										 |  |  |     @disabling_optimizer | 
					
						
							| 
									
										
										
										
											2023-06-22 15:02:38 -07:00
										 |  |  |     def assert_races_do_not_crash( | 
					
						
							|  |  |  |         self, opname, get_items, read, write, *, check_items=False | 
					
						
							|  |  |  |     ): | 
					
						
							|  |  |  |         # This might need a few dozen loops in some cases: | 
					
						
							|  |  |  |         for _ in range(self.LOOPS): | 
					
						
							|  |  |  |             items = get_items() | 
					
						
							|  |  |  |             # Reset: | 
					
						
							|  |  |  |             if check_items: | 
					
						
							|  |  |  |                 for item in items: | 
					
						
							|  |  |  |                     item.__code__ = item.__code__.replace() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 read.__code__ = read.__code__.replace() | 
					
						
							|  |  |  |             # Specialize: | 
					
						
							|  |  |  |             for _ in range(self.WARMUPS): | 
					
						
							|  |  |  |                 read(items) | 
					
						
							|  |  |  |             if check_items: | 
					
						
							|  |  |  |                 for item in items: | 
					
						
							|  |  |  |                     self.assert_specialized(item, opname) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.assert_specialized(read, opname) | 
					
						
							|  |  |  |             # Create writers: | 
					
						
							|  |  |  |             writers = [] | 
					
						
							|  |  |  |             for _ in range(self.WRITERS): | 
					
						
							|  |  |  |                 writer = threading.Thread(target=write, args=[items]) | 
					
						
							|  |  |  |                 writers.append(writer) | 
					
						
							|  |  |  |             # Run: | 
					
						
							|  |  |  |             for writer in writers: | 
					
						
							|  |  |  |                 writer.start() | 
					
						
							|  |  |  |             read(items)  # BOOM! | 
					
						
							|  |  |  |             for writer in writers: | 
					
						
							|  |  |  |                 writer.join() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_binary_subscr_getitem(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 __getitem__ = lambda self, item: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item[None] | 
					
						
							|  |  |  |                 except TypeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     del item.__getitem__ | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 type(item).__getitem__ = lambda self, item: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "BINARY_SUBSCR_GETITEM" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_binary_subscr_list_int(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = [None] | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item[0] | 
					
						
							|  |  |  |                 except IndexError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.clear() | 
					
						
							|  |  |  |                 item.append(None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "BINARY_SUBSCR_LIST_INT" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_for_iter_gen(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             def g(): | 
					
						
							|  |  |  |                 yield | 
					
						
							|  |  |  |                 yield | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = g() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     for _ in item: | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     for _ in item: | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "FOR_ITER_GEN" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_for_iter_list(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = [None] | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 for item in item: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.clear() | 
					
						
							|  |  |  |                 item.append(None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "FOR_ITER_LIST" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_class(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 a = object() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item.a | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     del item.a | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 item.a = object() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_CLASS" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_getattribute_overridden(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 __getattribute__ = lambda self, name: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item.a | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     del item.__getattribute__ | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 type(item).__getattribute__ = lambda self, name: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_instance_value(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 item.a = None | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.__dict__[None] = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_INSTANCE_VALUE" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_method_lazy_dict(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C(Exception): | 
					
						
							|  |  |  |                 m = lambda self: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item.m() | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     del item.m | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 type(item).m = lambda self: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_METHOD_LAZY_DICT" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_method_no_dict(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 __slots__ = () | 
					
						
							|  |  |  |                 m = lambda self: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item.m() | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     del item.m | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 type(item).m = lambda self: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_METHOD_NO_DICT" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_method_with_values(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 m = lambda self: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item.m() | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     del item.m | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 type(item).m = lambda self: None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_METHOD_WITH_VALUES" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_module(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = types.ModuleType("<item>") | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item.__name__ | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 d = item.__dict__.copy() | 
					
						
							|  |  |  |                 item.__dict__.clear() | 
					
						
							|  |  |  |                 item.__dict__.update(d) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_MODULE" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_property(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 a = property(lambda self: None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item.a | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     del type(item).a | 
					
						
							|  |  |  |                 except AttributeError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 type(item).a = property(lambda self: None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_PROPERTY" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_attr_with_hint(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 item.a = None | 
					
						
							| 
									
										
										
										
											2023-08-09 12:14:50 -07:00
										 |  |  |                 # Resize into a combined unicode dict: | 
					
						
							|  |  |  |                 for i in range(29): | 
					
						
							|  |  |  |                     setattr(item, f"_{i}", None) | 
					
						
							| 
									
										
										
										
											2023-06-22 15:02:38 -07:00
										 |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.__dict__[None] = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_ATTR_WITH_HINT" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_load_global_module(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = eval("lambda: x", {"x": None}) | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.__globals__[None] = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "LOAD_GLOBAL_MODULE" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash( | 
					
						
							|  |  |  |             opname, get_items, read, write, check_items=True | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_store_attr_instance_value(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.a = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.__dict__[None] = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "STORE_ATTR_INSTANCE_VALUE" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_store_attr_with_hint(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             class C: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = C() | 
					
						
							| 
									
										
										
										
											2023-08-09 12:14:50 -07:00
										 |  |  |                 # Resize into a combined unicode dict: | 
					
						
							|  |  |  |                 for i in range(29): | 
					
						
							|  |  |  |                     setattr(item, f"_{i}", None) | 
					
						
							| 
									
										
										
										
											2023-06-22 15:02:38 -07:00
										 |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.a = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.__dict__[None] = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "STORE_ATTR_WITH_HINT" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_store_subscr_list_int(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = [None] | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     item[0] = None | 
					
						
							|  |  |  |                 except IndexError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.clear() | 
					
						
							|  |  |  |                 item.append(None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "STORE_SUBSCR_LIST_INT" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_unpack_sequence_list(self): | 
					
						
							|  |  |  |         def get_items(): | 
					
						
							|  |  |  |             items = [] | 
					
						
							|  |  |  |             for _ in range(self.ITEMS): | 
					
						
							|  |  |  |                 item = [None] | 
					
						
							|  |  |  |                 items.append(item) | 
					
						
							|  |  |  |             return items | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def read(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     [_] = item | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def write(items): | 
					
						
							|  |  |  |             for item in items: | 
					
						
							|  |  |  |                 item.clear() | 
					
						
							|  |  |  |                 item.append(None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         opname = "UNPACK_SEQUENCE_LIST" | 
					
						
							|  |  |  |         self.assert_races_do_not_crash(opname, get_items, read, write) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-10 13:34:00 +01:00
										 |  |  | class C: | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-29 18:53:32 -08:00
										 |  |  | @requires_specialization | 
					
						
							| 
									
										
										
										
											2023-08-10 13:34:00 +01:00
										 |  |  | class TestInstanceDict(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a, c.b, c.c = 0,0,0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_values_on_instance(self): | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a = 1 | 
					
						
							|  |  |  |         C().b = 2 | 
					
						
							|  |  |  |         c.c = 3 | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c), | 
					
						
							|  |  |  |             (1, '<NULL>', 3) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_materialization(self): | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a = 1 | 
					
						
							|  |  |  |         c.b = 2 | 
					
						
							|  |  |  |         c.__dict__ | 
					
						
							| 
									
										
										
										
											2024-04-02 11:59:21 +01:00
										 |  |  |         self.assertEqual(c.__dict__, {"a":1, "b": 2}) | 
					
						
							| 
									
										
										
										
											2023-08-10 13:34:00 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_dematerialization(self): | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a = 1 | 
					
						
							|  |  |  |         c.b = 2 | 
					
						
							|  |  |  |         c.__dict__ | 
					
						
							|  |  |  |         for _ in range(100): | 
					
						
							|  |  |  |             c.a | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c), | 
					
						
							|  |  |  |             (1, 2, '<NULL>') | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_dematerialization_multiple_refs(self): | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a = 1 | 
					
						
							|  |  |  |         c.b = 2 | 
					
						
							|  |  |  |         d = c.__dict__ | 
					
						
							|  |  |  |         for _ in range(100): | 
					
						
							|  |  |  |             c.a | 
					
						
							|  |  |  |         self.assertIs(c.__dict__, d) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_dematerialization_copy(self): | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a = 1 | 
					
						
							|  |  |  |         c.b = 2 | 
					
						
							|  |  |  |         c2 = copy.copy(c) | 
					
						
							|  |  |  |         for _ in range(100): | 
					
						
							|  |  |  |             c.a | 
					
						
							|  |  |  |             c2.a | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c), | 
					
						
							|  |  |  |             (1, 2, '<NULL>') | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c2), | 
					
						
							|  |  |  |             (1, 2, '<NULL>') | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         c3 = copy.deepcopy(c) | 
					
						
							|  |  |  |         for _ in range(100): | 
					
						
							|  |  |  |             c.a | 
					
						
							|  |  |  |             c3.a | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c), | 
					
						
							|  |  |  |             (1, 2, '<NULL>') | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         #NOTE -- c3.__dict__ does not de-materialize | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_dematerialization_pickle(self): | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a = 1 | 
					
						
							|  |  |  |         c.b = 2 | 
					
						
							|  |  |  |         c2 = pickle.loads(pickle.dumps(c)) | 
					
						
							|  |  |  |         for _ in range(100): | 
					
						
							|  |  |  |             c.a | 
					
						
							|  |  |  |             c2.a | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c), | 
					
						
							|  |  |  |             (1, 2, '<NULL>') | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c2), | 
					
						
							|  |  |  |             (1, 2, '<NULL>') | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_dict_dematerialization_subclass(self): | 
					
						
							|  |  |  |         class D(dict): pass | 
					
						
							|  |  |  |         c = C() | 
					
						
							|  |  |  |         c.a = 1 | 
					
						
							|  |  |  |         c.b = 2 | 
					
						
							|  |  |  |         c.__dict__ = D(c.__dict__) | 
					
						
							|  |  |  |         for _ in range(100): | 
					
						
							|  |  |  |             c.a | 
					
						
							|  |  |  |         self.assertIs( | 
					
						
							|  |  |  |             _testinternalcapi.get_object_dict_values(c), | 
					
						
							|  |  |  |             None | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         self.assertEqual( | 
					
						
							|  |  |  |             c.__dict__, | 
					
						
							|  |  |  |             {'a':1, 'b':2} | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 15:02:38 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-18 10:10:22 -07:00
										 |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     unittest.main() |