@@ -446,12 +446,12 @@ def _establish_hooks_and_provider(
446446
447447 def _assert_provider_status (
448448 self ,
449- ) -> None :
449+ ) -> typing . Optional [ OpenFeatureError ] :
450450 status = self .get_provider_status ()
451451 if status == ProviderStatus .NOT_READY :
452- raise ProviderNotReadyError ()
452+ return ProviderNotReadyError ()
453453 if status == ProviderStatus .FATAL :
454- raise ProviderFatalError ()
454+ return ProviderFatalError ()
455455 return None
456456
457457 def _before_hooks_and_merge_context (
@@ -511,7 +511,22 @@ async def evaluate_flag_details_async(
511511 )
512512
513513 try :
514- self ._assert_provider_status ()
514+ if provider_err := self ._assert_provider_status ():
515+ error_hooks (
516+ flag_type ,
517+ hook_context ,
518+ provider_err ,
519+ reversed_merged_hooks ,
520+ hook_hints ,
521+ )
522+ details = FlagEvaluationDetails (
523+ flag_key = flag_key ,
524+ value = default_value ,
525+ reason = Reason .ERROR ,
526+ error_code = provider_err .error_code ,
527+ error_message = provider_err .error_message ,
528+ )
529+ return details
515530
516531 merged_context = self ._before_hooks_and_merge_context (
517532 flag_type ,
@@ -521,34 +536,39 @@ async def evaluate_flag_details_async(
521536 evaluation_context ,
522537 )
523538
524- flag_evaluation = await self ._create_provider_evaluation_async (
539+ details = await self ._create_provider_evaluation_async (
525540 provider ,
526541 flag_type ,
527542 flag_key ,
528543 default_value ,
529544 merged_context ,
530545 )
546+ if err := details .get_exception ():
547+ error_hooks (
548+ flag_type , hook_context , err , reversed_merged_hooks , hook_hints
549+ )
550+ return details
531551
532552 after_hooks (
533553 flag_type ,
534554 hook_context ,
535- flag_evaluation ,
555+ details ,
536556 reversed_merged_hooks ,
537557 hook_hints ,
538558 )
539559
540- return flag_evaluation
560+ return details
541561
542562 except OpenFeatureError as err :
543563 error_hooks (flag_type , hook_context , err , reversed_merged_hooks , hook_hints )
544- flag_evaluation = FlagEvaluationDetails (
564+ details = FlagEvaluationDetails (
545565 flag_key = flag_key ,
546566 value = default_value ,
547567 reason = Reason .ERROR ,
548568 error_code = err .error_code ,
549569 error_message = err .error_message ,
550570 )
551- return flag_evaluation
571+ return details
552572 # Catch any type of exception here since the user can provide any exception
553573 # in the error hooks
554574 except Exception as err : # pragma: no cover
@@ -559,20 +579,20 @@ async def evaluate_flag_details_async(
559579 error_hooks (flag_type , hook_context , err , reversed_merged_hooks , hook_hints )
560580
561581 error_message = getattr (err , "error_message" , str (err ))
562- flag_evaluation = FlagEvaluationDetails (
582+ details = FlagEvaluationDetails (
563583 flag_key = flag_key ,
564584 value = default_value ,
565585 reason = Reason .ERROR ,
566586 error_code = ErrorCode .GENERAL ,
567587 error_message = error_message ,
568588 )
569- return flag_evaluation
589+ return details
570590
571591 finally :
572592 after_all_hooks (
573593 flag_type ,
574594 hook_context ,
575- flag_evaluation ,
595+ details ,
576596 reversed_merged_hooks ,
577597 hook_hints ,
578598 )
@@ -607,7 +627,22 @@ def evaluate_flag_details(
607627 )
608628
609629 try :
610- self ._assert_provider_status ()
630+ if provider_err := self ._assert_provider_status ():
631+ error_hooks (
632+ flag_type ,
633+ hook_context ,
634+ provider_err ,
635+ reversed_merged_hooks ,
636+ hook_hints ,
637+ )
638+ flag_evaluation = FlagEvaluationDetails (
639+ flag_key = flag_key ,
640+ value = default_value ,
641+ reason = Reason .ERROR ,
642+ error_code = provider_err .error_code ,
643+ error_message = provider_err .error_message ,
644+ )
645+ return flag_evaluation
611646
612647 merged_context = self ._before_hooks_and_merge_context (
613648 flag_type ,
@@ -624,6 +659,11 @@ def evaluate_flag_details(
624659 default_value ,
625660 merged_context ,
626661 )
662+ if err := flag_evaluation .get_exception ():
663+ error_hooks (
664+ flag_type , hook_context , err , reversed_merged_hooks , hook_hints
665+ )
666+ return flag_evaluation
627667
628668 after_hooks (
629669 flag_type ,
@@ -693,27 +733,33 @@ async def _create_provider_evaluation_async(
693733 }
694734 get_details_callable = get_details_callables_async .get (flag_type )
695735 if not get_details_callable :
696- raise GeneralError (error_message = "Unknown flag type" )
736+ return FlagEvaluationDetails (
737+ flag_key = flag_key ,
738+ value = default_value ,
739+ reason = Reason .ERROR ,
740+ error_code = ErrorCode .GENERAL ,
741+ error_message = "Unknown flag type" ,
742+ )
697743
698744 resolution = await get_details_callable (
699745 flag_key = flag_key ,
700746 default_value = default_value ,
701747 evaluation_context = evaluation_context ,
702748 )
703- resolution .raise_for_error ()
749+ if resolution .error_code :
750+ return resolution .to_flag_evaluation_details (flag_key )
704751
705752 # we need to check the get_args to be compatible with union types.
706- _typecheck_flag_value (resolution .value , flag_type )
753+ if err := _typecheck_flag_value (value = resolution .value , flag_type = flag_type ):
754+ return FlagEvaluationDetails (
755+ flag_key = flag_key ,
756+ value = resolution .value ,
757+ reason = Reason .ERROR ,
758+ error_code = err .error_code ,
759+ error_message = err .error_message ,
760+ )
707761
708- return FlagEvaluationDetails (
709- flag_key = flag_key ,
710- value = resolution .value ,
711- variant = resolution .variant ,
712- flag_metadata = resolution .flag_metadata or {},
713- reason = resolution .reason ,
714- error_code = resolution .error_code ,
715- error_message = resolution .error_message ,
716- )
762+ return resolution .to_flag_evaluation_details (flag_key )
717763
718764 def _create_provider_evaluation (
719765 self ,
@@ -743,27 +789,33 @@ def _create_provider_evaluation(
743789
744790 get_details_callable = get_details_callables .get (flag_type )
745791 if not get_details_callable :
746- raise GeneralError (error_message = "Unknown flag type" )
792+ return FlagEvaluationDetails (
793+ flag_key = flag_key ,
794+ value = default_value ,
795+ reason = Reason .ERROR ,
796+ error_code = ErrorCode .GENERAL ,
797+ error_message = "Unknown flag type" ,
798+ )
747799
748800 resolution = get_details_callable (
749801 flag_key = flag_key ,
750802 default_value = default_value ,
751803 evaluation_context = evaluation_context ,
752804 )
753- resolution .raise_for_error ()
805+ if resolution .error_code :
806+ return resolution .to_flag_evaluation_details (flag_key )
754807
755808 # we need to check the get_args to be compatible with union types.
756- _typecheck_flag_value (resolution .value , flag_type )
809+ if err := _typecheck_flag_value (value = resolution .value , flag_type = flag_type ):
810+ return FlagEvaluationDetails (
811+ flag_key = flag_key ,
812+ value = resolution .value ,
813+ reason = Reason .ERROR ,
814+ error_code = err .error_code ,
815+ error_message = err .error_message ,
816+ )
757817
758- return FlagEvaluationDetails (
759- flag_key = flag_key ,
760- value = resolution .value ,
761- variant = resolution .variant ,
762- flag_metadata = resolution .flag_metadata or {},
763- reason = resolution .reason ,
764- error_code = resolution .error_code ,
765- error_message = resolution .error_message ,
766- )
818+ return resolution .to_flag_evaluation_details (flag_key )
767819
768820 def add_handler (self , event : ProviderEvent , handler : EventHandler ) -> None :
769821 _event_support .add_client_handler (self , event , handler )
@@ -772,7 +824,9 @@ def remove_handler(self, event: ProviderEvent, handler: EventHandler) -> None:
772824 _event_support .remove_client_handler (self , event , handler )
773825
774826
775- def _typecheck_flag_value (value : typing .Any , flag_type : FlagType ) -> None :
827+ def _typecheck_flag_value (
828+ value : typing .Any , flag_type : FlagType
829+ ) -> typing .Optional [OpenFeatureError ]:
776830 type_map : TypeMap = {
777831 FlagType .BOOLEAN : bool ,
778832 FlagType .STRING : str ,
@@ -782,6 +836,7 @@ def _typecheck_flag_value(value: typing.Any, flag_type: FlagType) -> None:
782836 }
783837 _type = type_map .get (flag_type )
784838 if not _type :
785- raise GeneralError (error_message = "Unknown flag type" )
839+ return GeneralError (error_message = "Unknown flag type" )
786840 if not isinstance (value , _type ):
787- raise TypeMismatchError (f"Expected type { _type } but got { type (value )} " )
841+ return TypeMismatchError (f"Expected type { _type } but got { type (value )} " )
842+ return None
0 commit comments