@@ -212,9 +212,7 @@ def _format_decision(self, decision_dict: Dict[str, str]) -> Dict[str, Any]:
212212
213213 return out
214214
215- def _send_expose (
216- self , event : str , exposure_fields : dict , overwrite_identifier : bool = False
217- ) -> None :
215+ def _send_expose (self , event : str , exposure_fields : dict ) -> None :
218216 event_fields = deepcopy (exposure_fields )
219217 try :
220218 (
@@ -245,8 +243,7 @@ def _send_expose(
245243 owner = owner ,
246244 )
247245
248- if overwrite_identifier :
249- event_fields = {** event_fields , ** {bucket_val : bucketing_value }}
246+ event_fields = {** event_fields , ** {bucket_val : bucketing_value }}
250247
251248 self ._event_logger .log (
252249 experiment = experiment ,
@@ -258,9 +255,7 @@ def _send_expose(
258255 )
259256 return
260257
261- def _send_expose_if_holdout (
262- self , event : str , exposure_fields : dict , overwrite_identifier : bool = False
263- ) -> None :
258+ def _send_expose_if_holdout (self , event : str , exposure_fields : dict ) -> None :
264259 event_fields = deepcopy (exposure_fields )
265260 try :
266261 (
@@ -296,8 +291,7 @@ def _send_expose_if_holdout(
296291 owner = owner ,
297292 )
298293
299- if overwrite_identifier :
300- event_fields = {** event_fields , ** {bucket_val : bucketing_value }}
294+ event_fields = {** event_fields , ** {bucket_val : bucketing_value }}
301295
302296 self ._event_logger .log (
303297 experiment = experiment ,
@@ -459,6 +453,14 @@ def get_variant_for_identifier(
459453 ) -> Optional [str ]:
460454 """Return a bucketing variant, if any, with auto-exposure for a given :code:`identifier`.
461455
456+ Note: If the experiment's :code:`bucket_val` (e.g. "user_id", "device_id", "canonical_url")
457+ does not match the :code:`identifier_type` param,
458+ the :code:`identifier` will be ignored and not used to bucket (:code:`{identifier_type: identifier}` is
459+ added to internal :code:`DeciderContext` instance, but doesn't act like a bucketing override).
460+
461+ If the :code:`bucket_val` field exists on the :code:`DeciderContext` instance,
462+ that field will be used to bucket, since it corresponds to the experiment's config.
463+
462464 Since calling :code:`get_variant_for_identifier()` will fire an exposure event, it
463465 is best to call it when you are sure the user will be exposed to the experiment.
464466
@@ -467,8 +469,11 @@ def get_variant_for_identifier(
467469 :param identifier: an arbitary string used to bucket the experiment by
468470 being set on :code:`DeciderContext`'s :code:`identifier_type` field.
469471
470- :param identifier_type: Sets :code:`{identifier_type: identifier}` on DeciderContext and
471- should match an experiment's :code:`bucket_val` to get a variant.
472+ :param identifier_type: Sets :code:`{identifier_type: identifier}` on :code:`DeciderContext`.
473+ The experiment's :code:`bucket_val` will be looked up in :code:`DeciderContext` and be used to bucket.
474+ If the experiment's :code:`bucket_val` field does not match :code:`identifier_type` param,
475+ :code:`identifier` will be ignored, and the field corresponding :code:`bucket_val` will be looked up
476+ from :code:`DeciderContext` for bucketing.
472477
473478 :param exposure_kwargs: Additional arguments that will be passed
474479 to :code:`events_logger` (keys must be part of v2 event schema,
@@ -483,38 +488,29 @@ def get_variant_for_identifier(
483488 )
484489 return None
485490
486- decider = self ._get_decider ()
487- if decider is None :
488- return None
489-
490- ctx = self ._get_ctx_with_set_identifier (
491- identifier = identifier , identifier_type = identifier_type
492- )
493- ctx_err = ctx .err ()
494- if ctx_err is not None :
495- logger .info (f"Encountered error in rust_decider.make_ctx(): { ctx_err } " )
491+ if self ._internal is None :
492+ logger .error ("RustDecider is None--did not initialize." )
496493 return None
497494
498- choice = decider .choose (
499- feature_name = experiment_name , ctx = ctx , identifier_type = identifier_type
500- )
501- error = choice .err ()
495+ ctx = self ._decider_context .to_dict ()
496+ ctx [identifier_type ] = identifier
502497
503- if error :
504- logger .info (f"Encountered error in decider.choose(): { error } " )
498+ try :
499+ decision = self ._internal .choose (experiment_name , ctx )
500+ except FeatureNotFoundException as exc :
501+ warnings .warn (str (exc ))
502+ return None
503+ except DeciderException as exc :
504+ logger .info (str (exc ))
505505 return None
506-
507- variant = choice .decision ()
508506
509507 event_context_fields = self ._decider_context .to_event_dict ()
510508 event_context_fields .update (exposure_kwargs or {})
511509
512- for event in choice .events ():
513- self ._send_expose (
514- event = event , exposure_fields = event_context_fields , overwrite_identifier = True
515- )
510+ for event in decision .events :
511+ self ._send_expose (event = event , exposure_fields = event_context_fields )
516512
517- return variant
513+ return decision . variant
518514
519515 def get_variant_for_identifier_without_expose (
520516 self ,
@@ -524,6 +520,14 @@ def get_variant_for_identifier_without_expose(
524520 ) -> Optional [str ]:
525521 """Return a bucketing variant, if any, without emitting exposure event for a given :code:`identifier`.
526522
523+ Note: If the experiment's :code:`bucket_val` (e.g. "user_id", "device_id", "canonical_url")
524+ does not match the :code:`identifier_type` param,
525+ the :code:`identifier` will be ignored and not used to bucket (:code:`{identifier_type: identifier}` is
526+ added to internal :code:`DeciderContext` instance, but doesn't act like a bucketing override).
527+
528+ If the :code:`bucket_val` field exists on the :code:`DeciderContext` instance,
529+ that field will be used to bucket, since it corresponds to the experiment's config.
530+
527531 The :code:`expose()` function is available to be manually called afterward to emit
528532 exposure event.
529533
@@ -538,8 +542,11 @@ def get_variant_for_identifier_without_expose(
538542 :param identifier: an arbitary string used to bucket the experiment by
539543 being set on :code:`DeciderContext`'s :code:`identifier_type` field.
540544
541- :param identifier_type: Sets :code:`{identifier_type: identifier}` on DeciderContext and
542- should match an experiment's :code:`bucket_val` to get a variant.
545+ :param identifier_type: Sets :code:`{identifier_type: identifier}` on :code:`DeciderContext`.
546+ The experiment's :code:`bucket_val` will be looked up in :code:`DeciderContext` and be used to bucket.
547+ If the experiment's :code:`bucket_val` field does not match :code:`identifier_type` param,
548+ :code:`identifier` will be ignored and the field corresponding :code:`bucket_val` will be looked up
549+ from :code:`DeciderContext` for bucketing.
543550
544551 :return: Variant name if a variant is assigned, None otherwise.
545552 """
@@ -549,37 +556,29 @@ def get_variant_for_identifier_without_expose(
549556 )
550557 return None
551558
552- decider = self ._get_decider ()
553- if decider is None :
559+ if self ._internal is None :
560+ logger . error ( "RustDecider is None--did not initialize." )
554561 return None
555562
556- ctx = self ._get_ctx_with_set_identifier (
557- identifier = identifier , identifier_type = identifier_type
558- )
559- ctx_err = ctx .err ()
560- if ctx_err is not None :
561- logger .info (f"Encountered error in rust_decider.make_ctx(): { ctx_err } " )
562- return None
563+ ctx = self ._decider_context .to_dict ()
564+ ctx [identifier_type ] = identifier
563565
564- choice = decider .choose (
565- feature_name = experiment_name , ctx = ctx , identifier_type = identifier_type
566- )
567- error = choice .err ()
568- if error :
569- logger .info (f"Encountered error in decider.choose(): { error } " )
566+ try :
567+ decision = self ._internal .choose (experiment_name , ctx )
568+ except FeatureNotFoundException as exc :
569+ warnings .warn (str (exc ))
570+ return None
571+ except DeciderException as exc :
572+ logger .info (str (exc ))
570573 return None
571-
572- variant = choice .decision ()
573574
574575 event_context_fields = self ._decider_context .to_event_dict ()
575576
576577 # expose Holdout if the experiment is part of one
577- for event in choice .events ():
578- self ._send_expose_if_holdout (
579- event = event , exposure_fields = event_context_fields , overwrite_identifier = True
580- )
578+ for event in decision .events :
579+ self ._send_expose_if_holdout (event = event , exposure_fields = event_context_fields )
581580
582- return variant
581+ return decision . variant
583582
584583 def get_all_variants_without_expose (self ) -> List [Dict [str , Union [str , int ]]]:
585584 """Return a list of experiment dicts in this format:
@@ -648,7 +647,8 @@ def _decision_to_dict(self, decision: Decision) -> Dict[str, Any]:
648647 def get_all_variants_for_identifier_without_expose (
649648 self , identifier : str , identifier_type : Literal ["user_id" , "device_id" , "canonical_url" ]
650649 ) -> List [Dict [str , Union [str , int ]]]:
651- """Return a list of experiment dicts for a given :code:`identifier` in this format:
650+ """Return a list of experiment dicts for experiments having :code:`bucket_val` match
651+ :code:`identifier_type`, for a given :code:`identifier`, in this format:
652652
653653 .. code-block:: json
654654
@@ -675,7 +675,7 @@ def get_all_variants_for_identifier_without_expose(
675675 being set on :code:`DeciderContext`'s :code:`identifier_type` field.
676676
677677 :param identifier_type: Sets :code:`{identifier_type: identifier}` on DeciderContext and
678- should match an experiment's :code:`bucket_val` to get a variant .
678+ buckets all experiment with matching :code:`bucket_val`.
679679
680680 :return: list of experiment dicts with non-:code:`None` variants.
681681 """
0 commit comments