@@ -261,6 +261,25 @@ def _get_feature_enabled(self, variation: Optional[Union[entities.Variation, Var
261261 except (AttributeError , KeyError , TypeError ):
262262 return False
263263
264+ def _get_experiment_key (self , experiment : Optional [Union [entities .Experiment , dict ]]) -> Optional [str ]:
265+ """Helper to extract experiment/holdout key from either dict or Experiment object.
266+ Args:
267+ experiment: Either a dict (from holdout) or entities.Experiment object
268+ Returns:
269+ The experiment/holdout key as a string, or None if not available
270+ """
271+ if experiment is None :
272+ return None
273+
274+ try :
275+ if isinstance (experiment , dict ):
276+ return experiment .get ('key' )
277+ else :
278+ return experiment .key
279+ except (AttributeError , KeyError , TypeError ):
280+ self .logger .warning (f"Unable to extract experiment key from { type (experiment )} " )
281+ return None
282+
264283 def _validate_instantiation_options (self ) -> None :
265284 """ Helper method to validate all instantiation parameters.
266285
@@ -455,7 +474,7 @@ def _get_feature_variable_for_type(
455474
456475 if decision .source in (enums .DecisionSources .FEATURE_TEST , enums .DecisionSources .HOLDOUT ):
457476 source_info = {
458- 'experiment_key' : decision . experiment . key if decision .experiment else None ,
477+ 'experiment_key' : self . _get_experiment_key ( decision .experiment ) ,
459478 'variation_key' : self ._get_variation_key (decision .variation ),
460479 }
461480
@@ -559,7 +578,7 @@ def _get_all_feature_variables_for_type(
559578
560579 if decision .source == enums .DecisionSources .FEATURE_TEST :
561580 source_info = {
562- 'experiment_key' : decision . experiment . key if decision .experiment else None ,
581+ 'experiment_key' : self . _get_experiment_key ( decision .experiment ) ,
563582 'variation_key' : self ._get_variation_key (decision .variation ),
564583 }
565584
@@ -804,19 +823,21 @@ def is_feature_enabled(self, feature_key: str, user_id: str, attributes: Optiona
804823 if (decision and (is_source_rollout or not decision .variation ) and
805824 project_config .get_send_flag_decisions_value ()):
806825 self ._send_impression_event (
807- project_config , decision .experiment , decision .variation , feature .key , decision .experiment .key if
808- decision .experiment else '' , str (decision .source ), feature_enabled , user_id , attributes , cmab_uuid
826+ project_config , decision .experiment , decision .variation , feature .key ,
827+ self ._get_experiment_key (decision .experiment ) or '' , str (decision .source ), feature_enabled ,
828+ user_id , attributes , cmab_uuid
809829 )
810830
811831 # Send event if Decision came from an experiment.
812832 if decision and is_source_experiment and decision .variation and decision .experiment :
813833 source_info = {
814- 'experiment_key' : decision .experiment . key ,
834+ 'experiment_key' : self . _get_experiment_key ( decision .experiment ) ,
815835 'variation_key' : self ._get_variation_key (decision .variation ),
816836 }
817837 self ._send_impression_event (
818- project_config , decision .experiment , decision .variation , feature .key , decision .experiment .key ,
819- str (decision .source ), feature_enabled , user_id , attributes , cmab_uuid
838+ project_config , decision .experiment , decision .variation , feature .key ,
839+ self ._get_experiment_key (decision .experiment ) or '' , str (decision .source ), feature_enabled ,
840+ user_id , attributes , cmab_uuid
820841 )
821842
822843 if feature_enabled :
@@ -1253,7 +1274,7 @@ def _create_optimizely_decision(
12531274
12541275 # Create Optimizely Decision Result.
12551276 attributes = user_context .get_user_attributes ()
1256- rule_key = flag_decision .experiment . key if ( flag_decision and flag_decision . experiment ) else None
1277+ rule_key = self . _get_experiment_key ( flag_decision .experiment ) if flag_decision else None
12571278 all_variables = {}
12581279 decision_source = flag_decision .source if flag_decision else None
12591280 decision_event_dispatched = False
0 commit comments