@@ -2401,14 +2401,18 @@ def _(cls, arg):
24012401 self .assertEqual (A .t (0.0 ).arg , "base" )
24022402
24032403 def test_abstractmethod_register (self ):
2404- class Abstract (abc .ABCMeta ):
2404+ class Abstract (metaclass = abc .ABCMeta ):
24052405
24062406 @functools .singledispatchmethod
24072407 @abc .abstractmethod
24082408 def add (self , x , y ):
24092409 pass
24102410
24112411 self .assertTrue (Abstract .add .__isabstractmethod__ )
2412+ self .assertTrue (Abstract .__dict__ ['add' ].__isabstractmethod__ )
2413+
2414+ with self .assertRaises (TypeError ):
2415+ Abstract ()
24122416
24132417 def test_type_ann_register (self ):
24142418 class A :
@@ -2469,6 +2473,137 @@ def _(cls, arg: str):
24692473 self .assertEqual (A .t ('' ).arg , "str" )
24702474 self .assertEqual (A .t (0.0 ).arg , "base" )
24712475
2476+ def test_method_wrapping_attributes (self ):
2477+ class A :
2478+ @functools .singledispatchmethod
2479+ def func (self , arg : int ) -> str :
2480+ """My function docstring"""
2481+ return str (arg )
2482+ @functools .singledispatchmethod
2483+ @classmethod
2484+ def cls_func (cls , arg : int ) -> str :
2485+ """My function docstring"""
2486+ return str (arg )
2487+ @functools .singledispatchmethod
2488+ @staticmethod
2489+ def static_func (arg : int ) -> str :
2490+ """My function docstring"""
2491+ return str (arg )
2492+
2493+ for meth in (
2494+ A .func ,
2495+ A ().func ,
2496+ A .cls_func ,
2497+ A ().cls_func ,
2498+ A .static_func ,
2499+ A ().static_func
2500+ ):
2501+ with self .subTest (meth = meth ):
2502+ self .assertEqual (meth .__doc__ , 'My function docstring' )
2503+ self .assertEqual (meth .__annotations__ ['arg' ], int )
2504+
2505+ self .assertEqual (A .func .__name__ , 'func' )
2506+ self .assertEqual (A ().func .__name__ , 'func' )
2507+ self .assertEqual (A .cls_func .__name__ , 'cls_func' )
2508+ self .assertEqual (A ().cls_func .__name__ , 'cls_func' )
2509+ self .assertEqual (A .static_func .__name__ , 'static_func' )
2510+ self .assertEqual (A ().static_func .__name__ , 'static_func' )
2511+
2512+ def test_double_wrapped_methods (self ):
2513+ def classmethod_friendly_decorator (func ):
2514+ wrapped = func .__func__
2515+ @classmethod
2516+ @functools .wraps (wrapped )
2517+ def wrapper (* args , ** kwargs ):
2518+ return wrapped (* args , ** kwargs )
2519+ return wrapper
2520+
2521+ class WithoutSingleDispatch :
2522+ @classmethod
2523+ @contextlib .contextmanager
2524+ def cls_context_manager (cls , arg : int ) -> str :
2525+ try :
2526+ yield str (arg )
2527+ finally :
2528+ return 'Done'
2529+
2530+ @classmethod_friendly_decorator
2531+ @classmethod
2532+ def decorated_classmethod (cls , arg : int ) -> str :
2533+ return str (arg )
2534+
2535+ try :
2536+ with WithoutSingleDispatch .cls_context_manager (3 ) as foo :
2537+ assert foo == '3' , (
2538+ "Classmethod contextmanager called from class not working"
2539+ )
2540+ with WithoutSingleDispatch ().cls_context_manager (3 ) as bar :
2541+ assert bar == '3' , (
2542+ "Classmethod contextmanager called from instance not working"
2543+ )
2544+ assert WithoutSingleDispatch .decorated_classmethod (666 ) == '666' , (
2545+ "Wrapped classmethod called from class not working"
2546+ )
2547+ assert WithoutSingleDispatch ().decorated_classmethod (666 ) == '666' , (
2548+ "Wrapped classmethod called from instance not working"
2549+ )
2550+ except AssertionError as e :
2551+ self .fail (f"There's a bug in this test: '{ e } '" )
2552+
2553+ class A :
2554+ @functools .singledispatchmethod
2555+ @classmethod
2556+ @contextlib .contextmanager
2557+ def cls_context_manager (cls , arg : int ) -> str :
2558+ """My function docstring"""
2559+ try :
2560+ yield str (arg )
2561+ finally :
2562+ return 'Done'
2563+
2564+ @functools .singledispatchmethod
2565+ @classmethod_friendly_decorator
2566+ @classmethod
2567+ def decorated_classmethod (cls , arg : int ) -> str :
2568+ """My function docstring"""
2569+ return str (arg )
2570+
2571+ with WithoutSingleDispatch .cls_context_manager (5 ) as foo :
2572+ without_single_dispatch_foo = foo
2573+
2574+ with A .cls_context_manager (5 ) as foo :
2575+ single_dispatch_foo = foo
2576+
2577+ self .assertEqual (without_single_dispatch_foo , single_dispatch_foo )
2578+ self .assertEqual (single_dispatch_foo , '5' )
2579+
2580+ for method_name in ('cls_context_manager' , 'decorated_classmethod' ):
2581+ with self .subTest (method = method_name ):
2582+ self .assertEqual (
2583+ getattr (A , method_name ).__name__ ,
2584+ getattr (WithoutSingleDispatch , method_name ).__name__
2585+ )
2586+
2587+ self .assertEqual (
2588+ getattr (A (), method_name ).__name__ ,
2589+ getattr (WithoutSingleDispatch (), method_name ).__name__
2590+ )
2591+
2592+ for meth in (
2593+ A .cls_context_manager ,
2594+ A ().cls_context_manager ,
2595+ A .decorated_classmethod ,
2596+ A ().decorated_classmethod
2597+ ):
2598+ with self .subTest (meth = meth ):
2599+ self .assertEqual (meth .__doc__ , 'My function docstring' )
2600+ self .assertEqual (meth .__annotations__ ['arg' ], int )
2601+
2602+ self .assertEqual (A .cls_context_manager .__name__ , 'cls_context_manager' )
2603+ self .assertEqual (A ().cls_context_manager .__name__ , 'cls_context_manager' )
2604+ self .assertEqual (A .decorated_classmethod .__name__ , 'decorated_classmethod' )
2605+ self .assertEqual (A ().decorated_classmethod .__name__ , 'decorated_classmethod' )
2606+
24722607 def test_invalid_registrations (self ):
24732608 msg_prefix = "Invalid first argument to `register()`: "
24742609 msg_suffix = (
0 commit comments