@@ -41,7 +41,8 @@ def clear_typing_caches():
4141class TypesTests (unittest .TestCase ):
4242
4343 def test_names (self ):
44- c_only_names = {'CapsuleType' , 'LazyImportType' }
44+ c_only_names = {'CapsuleType' , 'LazyImportType' ,
45+ 'lookup_special_method' }
4546 ignored = {'new_class' , 'resolve_bases' , 'prepare_class' ,
4647 'get_original_bases' , 'DynamicClassAttribute' , 'coroutine' }
4748
@@ -59,7 +60,7 @@ def test_names(self):
5960 'MemberDescriptorType' , 'MethodDescriptorType' , 'MethodType' ,
6061 'MethodWrapperType' , 'ModuleType' , 'NoneType' ,
6162 'NotImplementedType' , 'SimpleNamespace' , 'TracebackType' ,
62- 'UnionType' , 'WrapperDescriptorType' ,
63+ 'UnionType' , 'WrapperDescriptorType' , 'lookup_special_method' ,
6364 }
6465 self .assertEqual (all_names , set (c_types .__all__ ))
6566 self .assertEqual (all_names - c_only_names , set (py_types .__all__ ))
@@ -726,6 +727,46 @@ def test_frame_locals_proxy_type(self):
726727 self .assertIsNotNone (frame )
727728 self .assertIsInstance (frame .f_locals , types .FrameLocalsProxyType )
728729
730+ def test_lookup_special_method (self ):
731+ class CM1 :
732+ def __enter__ (self ):
733+ return "__enter__ from class __dict__"
734+
735+ class CM2 :
736+ def __init__ (self ):
737+ def __enter__ (self ):
738+ return "__enter__ from instance __dict__"
739+ self .__enter__ = __enter__
740+
741+ class CM3 :
742+ __slots__ = ("__enter__" ,)
743+ def __init__ (self ):
744+ def __enter__ (self ):
745+ return "__enter__ from __slots__"
746+ self .__enter__ = __enter__
747+ cm1 = CM1 ()
748+ meth = types .lookup_special_method (cm1 , "__enter__" )
749+ self .assertIsNotNone (meth )
750+ self .assertEqual (meth (cm1 ), "__enter__ from class __dict__" )
751+
752+ meth = types .lookup_special_method (cm1 , "__missing__" )
753+ self .assertIsNone (meth )
754+
755+ with self .assertRaises (TypeError ):
756+ types .lookup_special_method (cm1 , 123 )
757+
758+ cm2 = CM2 ()
759+ meth = types .lookup_special_method (cm2 , "__enter__" )
760+ self .assertIsNone (meth )
761+
762+ cm3 = CM3 ()
763+ meth = types .lookup_special_method (cm3 , "__enter__" )
764+ self .assertIsNotNone (meth )
765+ self .assertEqual (meth (cm3 ), "__enter__ from __slots__" )
766+
767+ meth = types .lookup_special_method ([], "__len__" )
768+ self .assertIsNotNone (meth )
769+ self .assertEqual (meth ([]), 0 )
729770
730771class UnionTests (unittest .TestCase ):
731772
0 commit comments