@@ -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+ flag_evaluation = 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 flag_evaluation
515530
516531 merged_context = self ._before_hooks_and_merge_context (
517532 flag_type ,
@@ -528,6 +543,11 @@ async def evaluate_flag_details_async(
528543 default_value ,
529544 merged_context ,
530545 )
546+ if err := flag_evaluation .get_exception ():
547+ error_hooks (
548+ flag_type , hook_context , err , reversed_merged_hooks , hook_hints
549+ )
550+ return flag_evaluation
531551
532552 after_hooks (
533553 flag_type ,
@@ -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,12 @@ 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+ flag_evaluation .value = default_value
667+ return flag_evaluation
627668
628669 after_hooks (
629670 flag_type ,
@@ -693,27 +734,33 @@ async def _create_provider_evaluation_async(
693734 }
694735 get_details_callable = get_details_callables_async .get (flag_type )
695736 if not get_details_callable :
696- raise GeneralError (error_message = "Unknown flag type" )
737+ return FlagEvaluationDetails (
738+ flag_key = flag_key ,
739+ value = default_value ,
740+ reason = Reason .ERROR ,
741+ error_code = ErrorCode .GENERAL ,
742+ error_message = "Unknown flag type" ,
743+ )
697744
698745 resolution = await get_details_callable (
699746 flag_key = flag_key ,
700747 default_value = default_value ,
701748 evaluation_context = evaluation_context ,
702749 )
703- resolution .raise_for_error ()
750+ if resolution .error_code :
751+ return resolution .to_flag_evaluation_details (flag_key )
704752
705753 # we need to check the get_args to be compatible with union types.
706- _typecheck_flag_value (resolution .value , flag_type )
754+ if err := _typecheck_flag_value (value = resolution .value , flag_type = flag_type ):
755+ return FlagEvaluationDetails (
756+ flag_key = flag_key ,
757+ value = resolution .value ,
758+ reason = Reason .ERROR ,
759+ error_code = err .error_code ,
760+ error_message = err .error_message ,
761+ )
707762
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- )
763+ return resolution .to_flag_evaluation_details (flag_key )
717764
718765 def _create_provider_evaluation (
719766 self ,
@@ -743,27 +790,33 @@ def _create_provider_evaluation(
743790
744791 get_details_callable = get_details_callables .get (flag_type )
745792 if not get_details_callable :
746- raise GeneralError (error_message = "Unknown flag type" )
793+ return FlagEvaluationDetails (
794+ flag_key = flag_key ,
795+ value = default_value ,
796+ reason = Reason .ERROR ,
797+ error_code = ErrorCode .GENERAL ,
798+ error_message = "Unknown flag type" ,
799+ )
747800
748801 resolution = get_details_callable (
749802 flag_key = flag_key ,
750803 default_value = default_value ,
751804 evaluation_context = evaluation_context ,
752805 )
753- resolution .raise_for_error ()
806+ if resolution .error_code :
807+ return resolution .to_flag_evaluation_details (flag_key )
754808
755809 # we need to check the get_args to be compatible with union types.
756- _typecheck_flag_value (resolution .value , flag_type )
810+ if err := _typecheck_flag_value (value = resolution .value , flag_type = flag_type ):
811+ return FlagEvaluationDetails (
812+ flag_key = flag_key ,
813+ value = resolution .value ,
814+ reason = Reason .ERROR ,
815+ error_code = err .error_code ,
816+ error_message = err .error_message ,
817+ )
757818
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- )
819+ return resolution .to_flag_evaluation_details (flag_key )
767820
768821 def add_handler (self , event : ProviderEvent , handler : EventHandler ) -> None :
769822 _event_support .add_client_handler (self , event , handler )
@@ -772,7 +825,9 @@ def remove_handler(self, event: ProviderEvent, handler: EventHandler) -> None:
772825 _event_support .remove_client_handler (self , event , handler )
773826
774827
775- def _typecheck_flag_value (value : typing .Any , flag_type : FlagType ) -> None :
828+ def _typecheck_flag_value (
829+ value : typing .Any , flag_type : FlagType
830+ ) -> typing .Optional [OpenFeatureError ]:
776831 type_map : TypeMap = {
777832 FlagType .BOOLEAN : bool ,
778833 FlagType .STRING : str ,
@@ -782,6 +837,7 @@ def _typecheck_flag_value(value: typing.Any, flag_type: FlagType) -> None:
782837 }
783838 _type = type_map .get (flag_type )
784839 if not _type :
785- raise GeneralError (error_message = "Unknown flag type" )
840+ return GeneralError (error_message = "Unknown flag type" )
786841 if not isinstance (value , _type ):
787- raise TypeMismatchError (f"Expected type { _type } but got { type (value )} " )
842+ return TypeMismatchError (f"Expected type { _type } but got { type (value )} " )
843+ return None
0 commit comments