@@ -694,13 +694,32 @@ def _run_setup(self, result):
694694 ValueError is raised.
695695 """
696696 ret = self .setUp ()
697- if not self .__setup_called :
698- raise ValueError (
699- f"In File: { sys .modules [self .__class__ .__module__ ].__file__ } \n "
700- "TestCase.setUp was not called. Have you upcalled all the "
701- "way up the hierarchy from your setUp? e.g. Call "
702- f"super({ self .__class__ .__name__ } , self).setUp() from your setUp()."
703- )
697+
698+ # Check if the return value is a Deferred (duck-typing to avoid hard dependency)
699+ if hasattr (ret , "addBoth" ) and callable (getattr (ret , "addBoth" )):
700+ # Deferred-like object: validate asynchronously after it resolves
701+ def _validate_setup_called (result ):
702+ if not self .__setup_called :
703+ raise ValueError (
704+ f"In File: { sys .modules [self .__class__ .__module__ ].__file__ } \n "
705+ "TestCase.setUp was not called. Have you upcalled all the "
706+ "way up the hierarchy from your setUp? e.g. Call "
707+ f"super({ self .__class__ .__name__ } , self).setUp() "
708+ "from your setUp()."
709+ )
710+ return result
711+
712+ ret .addBoth (_validate_setup_called )
713+ else :
714+ # Synchronous: validate immediately
715+ if not self .__setup_called :
716+ raise ValueError (
717+ f"In File: { sys .modules [self .__class__ .__module__ ].__file__ } \n "
718+ "TestCase.setUp was not called. Have you upcalled all the "
719+ "way up the hierarchy from your setUp? e.g. Call "
720+ f"super({ self .__class__ .__name__ } , self).setUp() "
721+ "from your setUp()."
722+ )
704723 return ret
705724
706725 def _run_teardown (self , result ):
@@ -711,14 +730,32 @@ def _run_teardown(self, result):
711730 ValueError is raised.
712731 """
713732 ret = self .tearDown ()
714- if not self .__teardown_called :
715- raise ValueError (
716- f"In File: { sys .modules [self .__class__ .__module__ ].__file__ } \n "
717- "TestCase.tearDown was not called. Have you upcalled all the "
718- "way up the hierarchy from your tearDown? e.g. Call "
719- f"super({ self .__class__ .__name__ } , self).tearDown() "
720- "from your tearDown()."
721- )
733+
734+ # Check if the return value is a Deferred (duck-typing to avoid hard dependency)
735+ if hasattr (ret , "addBoth" ) and callable (getattr (ret , "addBoth" )):
736+ # Deferred-like object: validate asynchronously after it resolves
737+ def _validate_teardown_called (result ):
738+ if not self .__teardown_called :
739+ raise ValueError (
740+ f"In File: { sys .modules [self .__class__ .__module__ ].__file__ } \n "
741+ "TestCase.tearDown was not called. Have you upcalled all the "
742+ "way up the hierarchy from your tearDown? e.g. Call "
743+ f"super({ self .__class__ .__name__ } , self).tearDown() "
744+ "from your tearDown()."
745+ )
746+ return result
747+
748+ ret .addBoth (_validate_teardown_called )
749+ else :
750+ # Synchronous: validate immediately
751+ if not self .__teardown_called :
752+ raise ValueError (
753+ f"In File: { sys .modules [self .__class__ .__module__ ].__file__ } \n "
754+ "TestCase.tearDown was not called. Have you upcalled all the "
755+ "way up the hierarchy from your tearDown? e.g. Call "
756+ f"super({ self .__class__ .__name__ } , self).tearDown() "
757+ "from your tearDown()."
758+ )
722759 return ret
723760
724761 def _get_test_method (self ):
0 commit comments