@@ -519,10 +519,8 @@ def _modify_function(func):
519519 num_params = len (inspect .signature (func ).parameters )
520520 empty_args = ([inspect .Parameter .empty ()] * num_params )
521521 workflow_level_promise = scheduled_workflow (* empty_args )
522+ _validate_decorated_function (func , empty_args )
522523 step_level_promise = func (* empty_args )
523- if not isinstance (step_level_promise , PromisedObject ):
524- raise TypeError ("The workflow does not return a 'promise'. Did you use the "
525- "is_fairstep decorator on all the steps?" )
526524
527525 # Description of workflow is the raw function code
528526 description = inspect .getsource (func )
@@ -531,3 +529,22 @@ def _modify_function(func):
531529 is_pplan_plan = is_pplan_plan , derived_from = None )
532530 return workflow_level_promise
533531 return _modify_function
532+
533+
534+ def _validate_decorated_function (func , empty_args ):
535+ """
536+ Validate that a function decorated with is_fairworkflow actually consists of steps that are
537+ decorated with is_fairstep. Call the function using empty arguments to test. NB: This won't
538+ catch all edgecases of users misusing the is_fairworkflow decorator, but at least will
539+ provide more useful error messages in frequently occurring cases.
540+ """
541+ try :
542+ result = func (* empty_args )
543+ except TypeError as e :
544+ raise TypeError ("Marking the function as workflow with `is_fairworkflow` decorator "
545+ "failed. "
546+ "Did you use the is_fairstep decorator on all the steps? "
547+ f"Detailed error message: { e } " )
548+ if not isinstance (result , PromisedObject ):
549+ raise TypeError ("The workflow does not return a 'promise'. Did you use the "
550+ "is_fairstep decorator on all the steps?" )
0 commit comments