@@ -84,6 +84,12 @@ def __init__(self, datafile, logger, error_handler):
84
84
85
85
self .parsing_succeeded = True
86
86
87
+ # Map of user IDs to another map of experiments to variations.
88
+ # This contains all the forced variations set by the user
89
+ # by calling set_forced_variation (it is not the same as the
90
+ # whitelisting forcedVariations data structure).
91
+ self .forced_variation_map = {}
92
+
87
93
@staticmethod
88
94
def _generate_key_map (list , key , entity_class ):
89
95
""" Helper method to generate map from key to entity object for given list of dicts.
@@ -340,3 +346,107 @@ def get_attribute(self, attribute_key):
340
346
self .logger .log (enums .LogLevels .ERROR , 'Attribute "%s" is not in datafile.' % attribute_key )
341
347
self .error_handler .handle_error (exceptions .InvalidAttributeException (enums .Errors .INVALID_ATTRIBUTE_ERROR ))
342
348
return None
349
+
350
+ def set_forced_variation (self , experiment_key , user_id , variation_key ):
351
+ """ Sets users to a map of experiments to forced variations.
352
+
353
+ Args:
354
+ experiment_key: Key for experiment.
355
+ user_id: The user ID.
356
+ variation_key: Key for variation. If None, then clear the existing experiment-to-variation mapping.
357
+
358
+ Returns:
359
+ A boolean value that indicates if the set completed successfully.
360
+ """
361
+ if not user_id :
362
+ self .logger .log (enums .LogLevels .DEBUG , 'User ID is invalid.' )
363
+ return False
364
+
365
+ experiment = self .get_experiment_from_key (experiment_key )
366
+ if not experiment :
367
+ # The invalid experiment key will be logged inside this call.
368
+ return False
369
+
370
+ experiment_id = experiment .id
371
+ if not variation_key :
372
+ if user_id in self .forced_variation_map :
373
+ experiment_to_variation_map = self .forced_variation_map .get (user_id )
374
+ if experiment_id in experiment_to_variation_map :
375
+ del (self .forced_variation_map [user_id ][experiment_id ])
376
+ self .logger .log (enums .LogLevels .DEBUG ,
377
+ 'Variation mapped to experiment "%s" has been removed for user "%s".'
378
+ % (experiment_key , user_id ))
379
+ else :
380
+ self .logger .log (enums .LogLevels .DEBUG ,
381
+ 'Nothing to remove. Variation mapped to experiment "%s" for user "%s" does not exist.'
382
+ % (experiment_key , user_id ))
383
+ else :
384
+ self .logger .log (enums .LogLevels .DEBUG ,
385
+ 'Nothing to remove. User "%s" does not exist in the forced variation map.' % user_id )
386
+ return True
387
+
388
+ forced_variation = self .get_variation_from_key (experiment_key , variation_key )
389
+ if not forced_variation :
390
+ # The invalid variation key will be logged inside this call.
391
+ return False
392
+
393
+ variation_id = forced_variation .id
394
+
395
+ if user_id not in self .forced_variation_map :
396
+ self .forced_variation_map [user_id ] = {experiment_id : variation_id }
397
+ else :
398
+ self .forced_variation_map [user_id ][experiment_id ] = variation_id
399
+
400
+ self .logger .log (enums .LogLevels .DEBUG ,
401
+ 'Set variation "%s" for experiment "%s" and user "%s" in the forced variation map.'
402
+ % (variation_id , experiment_id , user_id ))
403
+ return True
404
+
405
+ def get_forced_variation (self , experiment_key , user_id ):
406
+ """ Gets the forced variation key for the given user and experiment.
407
+
408
+ Args:
409
+ experiment_key: Key for experiment.
410
+ user_id: The user ID.
411
+
412
+ Returns:
413
+ The variation which the given user and experiment should be forced into.
414
+ """
415
+ if not user_id :
416
+ self .logger .log (enums .LogLevels .DEBUG , 'User ID is invalid.' )
417
+ return None
418
+
419
+ if user_id not in self .forced_variation_map :
420
+ self .logger .log (enums .LogLevels .DEBUG , 'User "%s" is not in the forced variation map.' % user_id )
421
+ return None
422
+
423
+ experiment = self .get_experiment_from_key (experiment_key )
424
+ if not experiment :
425
+ # The invalid experiment key will be logged inside this call.
426
+ return None
427
+
428
+ experiment_to_variation_map = self .forced_variation_map .get (user_id )
429
+
430
+ if not experiment_to_variation_map :
431
+ self .logger .log (enums .LogLevels .DEBUG ,
432
+ 'No experiment "%s" mapped to user "%s" in the forced variation map.'
433
+ % (experiment_key , user_id ))
434
+ return None
435
+
436
+ variation_id = experiment_to_variation_map .get (experiment .id )
437
+ if variation_id is None :
438
+ self .logger .log (enums .LogLevels .DEBUG ,
439
+ 'No variation mapped to experiment "%s" in the forced variation map.'
440
+ % experiment_key )
441
+ return None
442
+
443
+ variation = self .get_variation_from_id (experiment_key , variation_id )
444
+ if not variation :
445
+ # The invalid variation ID will be logged inside this call.
446
+ return None
447
+
448
+ self .logger .log (enums .LogLevels .DEBUG ,
449
+ 'Variation "%s" is mapped to experiment "%s" and user "%s" in the forced variation map'
450
+ % (variation .key , experiment_key , user_id ))
451
+ return variation
452
+
0 commit comments