@@ -444,12 +444,12 @@ def _establish_hooks_and_provider(
444444
445445 def _assert_provider_status (
446446 self ,
447- ) -> None :
447+ ) -> typing . Optional [ OpenFeatureError ] :
448448 status = self .get_provider_status ()
449449 if status == ProviderStatus .NOT_READY :
450- raise ProviderNotReadyError ()
450+ return ProviderNotReadyError ()
451451 if status == ProviderStatus .FATAL :
452- raise ProviderFatalError ()
452+ return ProviderFatalError ()
453453 return None
454454
455455 def _before_hooks_and_merge_context (
@@ -509,7 +509,22 @@ async def evaluate_flag_details_async(
509509 )
510510
511511 try :
512- self ._assert_provider_status ()
512+ if provider_err := self ._assert_provider_status ():
513+ error_hooks (
514+ flag_type ,
515+ hook_context ,
516+ provider_err ,
517+ reversed_merged_hooks ,
518+ hook_hints ,
519+ )
520+ flag_evaluation = FlagEvaluationDetails (
521+ flag_key = flag_key ,
522+ value = default_value ,
523+ reason = Reason .ERROR ,
524+ error_code = provider_err .error_code ,
525+ error_message = provider_err .error_message ,
526+ )
527+ return flag_evaluation
513528
514529 merged_context = self ._before_hooks_and_merge_context (
515530 flag_type ,
@@ -526,6 +541,11 @@ async def evaluate_flag_details_async(
526541 default_value ,
527542 merged_context ,
528543 )
544+ if err := flag_evaluation .get_exception ():
545+ error_hooks (
546+ flag_type , hook_context , err , reversed_merged_hooks , hook_hints
547+ )
548+ return flag_evaluation
529549
530550 after_hooks (
531551 flag_type ,
@@ -605,7 +625,22 @@ def evaluate_flag_details(
605625 )
606626
607627 try :
608- self ._assert_provider_status ()
628+ if provider_err := self ._assert_provider_status ():
629+ error_hooks (
630+ flag_type ,
631+ hook_context ,
632+ provider_err ,
633+ reversed_merged_hooks ,
634+ hook_hints ,
635+ )
636+ flag_evaluation = FlagEvaluationDetails (
637+ flag_key = flag_key ,
638+ value = default_value ,
639+ reason = Reason .ERROR ,
640+ error_code = provider_err .error_code ,
641+ error_message = provider_err .error_message ,
642+ )
643+ return flag_evaluation
609644
610645 merged_context = self ._before_hooks_and_merge_context (
611646 flag_type ,
@@ -622,6 +657,12 @@ def evaluate_flag_details(
622657 default_value ,
623658 merged_context ,
624659 )
660+ if err := flag_evaluation .get_exception ():
661+ error_hooks (
662+ flag_type , hook_context , err , reversed_merged_hooks , hook_hints
663+ )
664+ flag_evaluation .value = default_value
665+ return flag_evaluation
625666
626667 after_hooks (
627668 flag_type ,
@@ -691,27 +732,33 @@ async def _create_provider_evaluation_async(
691732 }
692733 get_details_callable = get_details_callables_async .get (flag_type )
693734 if not get_details_callable :
694- raise GeneralError (error_message = "Unknown flag type" )
735+ return FlagEvaluationDetails (
736+ flag_key = flag_key ,
737+ value = default_value ,
738+ reason = Reason .ERROR ,
739+ error_code = ErrorCode .GENERAL ,
740+ error_message = "Unknown flag type" ,
741+ )
695742
696743 resolution = await get_details_callable (
697744 flag_key = flag_key ,
698745 default_value = default_value ,
699746 evaluation_context = evaluation_context ,
700747 )
701- resolution .raise_for_error ()
748+ if resolution .error_code :
749+ return resolution .to_flag_evaluation_details (flag_key )
702750
703751 # we need to check the get_args to be compatible with union types.
704- _typecheck_flag_value (resolution .value , flag_type )
752+ if err := _typecheck_flag_value (value = resolution .value , flag_type = flag_type ):
753+ return FlagEvaluationDetails (
754+ flag_key = flag_key ,
755+ value = resolution .value ,
756+ reason = Reason .ERROR ,
757+ error_code = err .error_code ,
758+ error_message = err .error_message ,
759+ )
705760
706- return FlagEvaluationDetails (
707- flag_key = flag_key ,
708- value = resolution .value ,
709- variant = resolution .variant ,
710- flag_metadata = resolution .flag_metadata or {},
711- reason = resolution .reason ,
712- error_code = resolution .error_code ,
713- error_message = resolution .error_message ,
714- )
761+ return resolution .to_flag_evaluation_details (flag_key )
715762
716763 def _create_provider_evaluation (
717764 self ,
@@ -741,27 +788,33 @@ def _create_provider_evaluation(
741788
742789 get_details_callable = get_details_callables .get (flag_type )
743790 if not get_details_callable :
744- raise GeneralError (error_message = "Unknown flag type" )
791+ return FlagEvaluationDetails (
792+ flag_key = flag_key ,
793+ value = default_value ,
794+ reason = Reason .ERROR ,
795+ error_code = ErrorCode .GENERAL ,
796+ error_message = "Unknown flag type" ,
797+ )
745798
746799 resolution = get_details_callable (
747800 flag_key = flag_key ,
748801 default_value = default_value ,
749802 evaluation_context = evaluation_context ,
750803 )
751- resolution .raise_for_error ()
804+ if resolution .error_code :
805+ return resolution .to_flag_evaluation_details (flag_key )
752806
753807 # we need to check the get_args to be compatible with union types.
754- _typecheck_flag_value (resolution .value , flag_type )
808+ if err := _typecheck_flag_value (value = resolution .value , flag_type = flag_type ):
809+ return FlagEvaluationDetails (
810+ flag_key = flag_key ,
811+ value = resolution .value ,
812+ reason = Reason .ERROR ,
813+ error_code = err .error_code ,
814+ error_message = err .error_message ,
815+ )
755816
756- return FlagEvaluationDetails (
757- flag_key = flag_key ,
758- value = resolution .value ,
759- variant = resolution .variant ,
760- flag_metadata = resolution .flag_metadata or {},
761- reason = resolution .reason ,
762- error_code = resolution .error_code ,
763- error_message = resolution .error_message ,
764- )
817+ return resolution .to_flag_evaluation_details (flag_key )
765818
766819 def add_handler (self , event : ProviderEvent , handler : EventHandler ) -> None :
767820 _event_support .add_client_handler (self , event , handler )
@@ -770,7 +823,9 @@ def remove_handler(self, event: ProviderEvent, handler: EventHandler) -> None:
770823 _event_support .remove_client_handler (self , event , handler )
771824
772825
773- def _typecheck_flag_value (value : typing .Any , flag_type : FlagType ) -> None :
826+ def _typecheck_flag_value (
827+ value : typing .Any , flag_type : FlagType
828+ ) -> typing .Optional [OpenFeatureError ]:
774829 type_map : TypeMap = {
775830 FlagType .BOOLEAN : bool ,
776831 FlagType .STRING : str ,
@@ -780,6 +835,7 @@ def _typecheck_flag_value(value: typing.Any, flag_type: FlagType) -> None:
780835 }
781836 _type = type_map .get (flag_type )
782837 if not _type :
783- raise GeneralError (error_message = "Unknown flag type" )
838+ return GeneralError (error_message = "Unknown flag type" )
784839 if not isinstance (value , _type ):
785- raise TypeMismatchError (f"Expected type { _type } but got { type (value )} " )
840+ return TypeMismatchError (f"Expected type { _type } but got { type (value )} " )
841+ return None
0 commit comments