@@ -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,141 @@ 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+ class WithSingleDispatch :
2536+ @functools .singledispatchmethod
2537+ @classmethod
2538+ @contextlib .contextmanager
2539+ def cls_context_manager (cls , arg : int ) -> str :
2540+ """My function docstring"""
2541+ try :
2542+ yield str (arg )
2543+ finally :
2544+ return 'Done'
2545+
2546+ @functools .singledispatchmethod
2547+ @classmethod_friendly_decorator
2548+ @classmethod
2549+ def decorated_classmethod (cls , arg : int ) -> str :
2550+ """My function docstring"""
2551+ return str (arg )
2552+
2553+ # These are sanity checks
2554+ # to test the test itself is working as expected
2555+ with WithoutSingleDispatch .cls_context_manager (5 ) as foo :
2556+ without_single_dispatch_foo = foo
2557+
2558+ with WithSingleDispatch .cls_context_manager (5 ) as foo :
2559+ single_dispatch_foo = foo
2560+
2561+ self .assertEqual (without_single_dispatch_foo , single_dispatch_foo )
2562+ self .assertEqual (single_dispatch_foo , '5' )
2563+
2564+ self .assertEqual (
2565+ WithoutSingleDispatch .decorated_classmethod (5 ),
2566+ WithSingleDispatch .decorated_classmethod (5 )
2567+ )
2568+
2569+ self .assertEqual (WithSingleDispatch .decorated_classmethod (5 ), '5' )
2570+
2571+ # Behavioural checks now follow
2572+ for method_name in ('cls_context_manager' , 'decorated_classmethod' ):
2573+ with self .subTest (method = method_name ):
2574+ self .assertEqual (
2575+ getattr (WithSingleDispatch , method_name ).__name__ ,
2576+ getattr (WithoutSingleDispatch , method_name ).__name__
2577+ )
2578+
2579+ self .assertEqual (
2580+ getattr (WithSingleDispatch (), method_name ).__name__ ,
2581+ getattr (WithoutSingleDispatch (), method_name ).__name__
2582+ )
2583+
2584+ for meth in (
2585+ WithSingleDispatch .cls_context_manager ,
2586+ WithSingleDispatch ().cls_context_manager ,
2587+ WithSingleDispatch .decorated_classmethod ,
2588+ WithSingleDispatch ().decorated_classmethod
2589+ ):
2590+ with self .subTest (meth = meth ):
2591+ self .assertEqual (meth .__doc__ , 'My function docstring' )
2592+ self .assertEqual (meth .__annotations__ ['arg' ], int )
2593+
2594+ self .assertEqual (
2595+ WithSingleDispatch .cls_context_manager .__name__ ,
2596+ 'cls_context_manager'
2597+ )
2598+ self .assertEqual (
2599+ WithSingleDispatch ().cls_context_manager .__name__ ,
2600+ 'cls_context_manager'
2601+ )
2602+ self .assertEqual (
2603+ WithSingleDispatch .decorated_classmethod .__name__ ,
2604+ 'decorated_classmethod'
2605+ )
2606+ self .assertEqual (
2607+ WithSingleDispatch ().decorated_classmethod .__name__ ,
2608+ 'decorated_classmethod'
2609+ )
2610+
24722611 def test_invalid_registrations (self ):
24732612 msg_prefix = "Invalid first argument to `register()`: "
24742613 msg_suffix = (
0 commit comments