1717 normalized_hash ,
1818 prepare_common_query_params ,
1919 EXPOSURE_EVENT ,
20+ generate_traceparent
2021)
2122
2223logger = logging .getLogger (__name__ )
@@ -168,17 +169,18 @@ def is_enabled(self, flag_key: str, context: Dict[str, Any]) -> bool:
168169 :param Dict[str, Any] context: Context dictionary containing user's distinct_id and any other attributes needed for rollout evaluation
169170 """
170171 variant_value = self .get_variant_value (flag_key , False , context )
171- return bool ( variant_value )
172+ return variant_value == True
172173
173174 def get_variant (
174- self , flag_key : str , fallback_value : SelectedVariant , context : Dict [str , Any ]
175+ self , flag_key : str , fallback_value : SelectedVariant , context : Dict [str , Any ], report_exposure : bool = True
175176 ) -> SelectedVariant :
176177 """
177178 Gets the selected variant for a feature flag
178179
179180 :param str flag_key: The key of the feature flag to evaluate
180181 :param SelectedVariant fallback_value: The default variant to return if evaluation fails
181182 :param Dict[str, Any] context: Context dictionary containing user's distinct_id and any other attributes needed for rollout evaluation
183+ :param bool report_exposure: Whether to track an exposure event for this flag evaluation. Defaults to True.
182184 """
183185 start_time = time .perf_counter ()
184186 flag_definition = self ._flag_definitions .get (flag_key )
@@ -193,20 +195,21 @@ def get_variant(
193195 )
194196 return fallback_value
195197
198+ selected_variant : Optional [SelectedVariant ] = None
199+
196200 if test_user_variant := self ._get_variant_override_for_test_user (
197201 flag_definition , context
198202 ):
199- return test_user_variant
200-
201- if rollout := self ._get_assigned_rollout (
202- flag_definition , context_value , context
203- ):
204- variant = self ._get_assigned_variant (
203+ selected_variant = test_user_variant
204+ elif rollout := self ._get_assigned_rollout (flag_definition , context_value , context ):
205+ selected_variant = self ._get_assigned_variant (
205206 flag_definition , context_value , flag_key , rollout
206207 )
208+
209+ if report_exposure and selected_variant is not None :
207210 end_time = time .perf_counter ()
208- self ._track_exposure (flag_key , variant , end_time - start_time , context )
209- return variant
211+ self ._track_exposure (flag_key , selected_variant , end_time - start_time , context )
212+ return selected_variant
210213
211214 logger .info (
212215 f"{ flag_definition .context } context { context_value } not eligible for any rollout for flag: { flag_key } "
@@ -241,12 +244,17 @@ def _get_assigned_variant(
241244 ):
242245 return variant
243246
244- variants = flag_definition .ruleset .variants
245247
246248 hash_input = str (context_value ) + flag_name
247249
248250 variant_hash = normalized_hash (hash_input , "variant" )
249251
252+ variants = [variant .model_copy (deep = True ) for variant in flag_definition .ruleset .variants ]
253+ if rollout .variant_splits :
254+ for variant in variants :
255+ if variant .key in rollout .variant_splits :
256+ variant .split = rollout .variant_splits [variant .key ]
257+
250258 selected = variants [0 ]
251259 cumulative = 0.0
252260 for variant in variants :
@@ -255,7 +263,11 @@ def _get_assigned_variant(
255263 if variant_hash < cumulative :
256264 break
257265
258- return SelectedVariant (variant_key = selected .key , variant_value = selected .value )
266+ return SelectedVariant (
267+ variant_key = selected .key ,
268+ variant_value = selected .value ,
269+ experiment_id = flag_definition .experiment_id ,
270+ is_experiment_active = flag_definition .is_experiment_active )
259271
260272 def _get_assigned_rollout (
261273 self ,
@@ -304,15 +316,20 @@ def _get_matching_variant(
304316 for variant in flag .ruleset .variants :
305317 if variant_key .casefold () == variant .key .casefold ():
306318 return SelectedVariant (
307- variant_key = variant .key , variant_value = variant .value
319+ variant_key = variant .key ,
320+ variant_value = variant .value ,
321+ experiment_id = flag .experiment_id ,
322+ is_experiment_active = flag .is_experiment_active ,
323+ is_qa_tester = True ,
308324 )
309325 return None
310326
311327 async def _afetch_flag_definitions (self ) -> None :
312328 try :
313329 start_time = datetime .now ()
330+ headers = {"traceparent" : generate_traceparent ()}
314331 response = await self ._async_client .get (
315- self .FLAGS_DEFINITIONS_URL_PATH , params = self ._request_params
332+ self .FLAGS_DEFINITIONS_URL_PATH , params = self ._request_params , headers = headers
316333 )
317334 end_time = datetime .now ()
318335 self ._handle_response (response , start_time , end_time )
@@ -322,8 +339,9 @@ async def _afetch_flag_definitions(self) -> None:
322339 def _fetch_flag_definitions (self ) -> None :
323340 try :
324341 start_time = datetime .now ()
342+ headers = {"traceparent" : generate_traceparent ()}
325343 response = self ._sync_client .get (
326- self .FLAGS_DEFINITIONS_URL_PATH , params = self ._request_params
344+ self .FLAGS_DEFINITIONS_URL_PATH , params = self ._request_params , headers = headers
327345 )
328346 end_time = datetime .now ()
329347 self ._handle_response (response , start_time , end_time )
@@ -370,6 +388,9 @@ def _track_exposure(
370388 "$experiment_type" : "feature_flag" ,
371389 "Flag evaluation mode" : "local" ,
372390 "Variant fetch latency (ms)" : latency_in_seconds * 1000 ,
391+ "$experiment_id" : variant .experiment_id ,
392+ "$is_experiment_active" : variant .is_experiment_active ,
393+ "$is_qa_tester" : variant .is_qa_tester ,
373394 }
374395
375396 self ._tracker (distinct_id , EXPOSURE_EVENT , properties )
0 commit comments