@@ -2519,6 +2519,105 @@ def static_func(arg: int) -> str:
2519
2519
self .assertEqual (A .static_func .__name__ , 'static_func' )
2520
2520
self .assertEqual (A ().static_func .__name__ , 'static_func' )
2521
2521
2522
+ def test_double_wrapped_methods (self ):
2523
+ def classmethod_friendly_decorator (func ):
2524
+ wrapped = func .__func__
2525
+ @classmethod
2526
+ @functools .wraps (wrapped )
2527
+ def wrapper (* args , ** kwargs ):
2528
+ return wrapped (* args , ** kwargs )
2529
+ return wrapper
2530
+
2531
+ class WithoutSingleDispatch :
2532
+ @classmethod
2533
+ @contextlib .contextmanager
2534
+ def cls_context_manager (cls , arg : int ) -> str :
2535
+ try :
2536
+ yield str (arg )
2537
+ finally :
2538
+ return 'Done'
2539
+
2540
+ @classmethod_friendly_decorator
2541
+ @classmethod
2542
+ def decorated_classmethod (cls , arg : int ) -> str :
2543
+ return str (arg )
2544
+
2545
+ class WithSingleDispatch :
2546
+ @functools .singledispatchmethod
2547
+ @classmethod
2548
+ @contextlib .contextmanager
2549
+ def cls_context_manager (cls , arg : int ) -> str :
2550
+ """My function docstring"""
2551
+ try :
2552
+ yield str (arg )
2553
+ finally :
2554
+ return 'Done'
2555
+
2556
+ @functools .singledispatchmethod
2557
+ @classmethod_friendly_decorator
2558
+ @classmethod
2559
+ def decorated_classmethod (cls , arg : int ) -> str :
2560
+ """My function docstring"""
2561
+ return str (arg )
2562
+
2563
+ # These are sanity checks
2564
+ # to test the test itself is working as expected
2565
+ with WithoutSingleDispatch .cls_context_manager (5 ) as foo :
2566
+ without_single_dispatch_foo = foo
2567
+
2568
+ with WithSingleDispatch .cls_context_manager (5 ) as foo :
2569
+ single_dispatch_foo = foo
2570
+
2571
+ self .assertEqual (without_single_dispatch_foo , single_dispatch_foo )
2572
+ self .assertEqual (single_dispatch_foo , '5' )
2573
+
2574
+ self .assertEqual (
2575
+ WithoutSingleDispatch .decorated_classmethod (5 ),
2576
+ WithSingleDispatch .decorated_classmethod (5 )
2577
+ )
2578
+
2579
+ self .assertEqual (WithSingleDispatch .decorated_classmethod (5 ), '5' )
2580
+
2581
+ # Behavioural checks now follow
2582
+ for method_name in ('cls_context_manager' , 'decorated_classmethod' ):
2583
+ with self .subTest (method = method_name ):
2584
+ self .assertEqual (
2585
+ getattr (WithSingleDispatch , method_name ).__name__ ,
2586
+ getattr (WithoutSingleDispatch , method_name ).__name__
2587
+ )
2588
+
2589
+ self .assertEqual (
2590
+ getattr (WithSingleDispatch (), method_name ).__name__ ,
2591
+ getattr (WithoutSingleDispatch (), method_name ).__name__
2592
+ )
2593
+
2594
+ for meth in (
2595
+ WithSingleDispatch .cls_context_manager ,
2596
+ WithSingleDispatch ().cls_context_manager ,
2597
+ WithSingleDispatch .decorated_classmethod ,
2598
+ WithSingleDispatch ().decorated_classmethod
2599
+ ):
2600
+ with self .subTest (meth = meth ):
2601
+ self .assertEqual (meth .__doc__ , 'My function docstring' )
2602
+ self .assertEqual (meth .__annotations__ ['arg' ], int )
2603
+
2604
+ self .assertEqual (
2605
+ WithSingleDispatch .cls_context_manager .__name__ ,
2606
+ 'cls_context_manager'
2607
+ )
2608
+ self .assertEqual (
2609
+ WithSingleDispatch ().cls_context_manager .__name__ ,
2610
+ 'cls_context_manager'
2611
+ )
2612
+ self .assertEqual (
2613
+ WithSingleDispatch .decorated_classmethod .__name__ ,
2614
+ 'decorated_classmethod'
2615
+ )
2616
+ self .assertEqual (
2617
+ WithSingleDispatch ().decorated_classmethod .__name__ ,
2618
+ 'decorated_classmethod'
2619
+ )
2620
+
2522
2621
def test_invalid_registrations (self ):
2523
2622
msg_prefix = "Invalid first argument to `register()`: "
2524
2623
msg_suffix = (
0 commit comments