@@ -76,7 +76,7 @@ def get_stored_variation(self, experiment, user_profile):
76
76
77
77
return None
78
78
79
- def get_variation (self , experiment , user_id , attributes ):
79
+ def get_variation (self , experiment , user_id , attributes , ignore_user_profile = False ):
80
80
""" Top-level function to help determine variation user should be put in.
81
81
82
82
First, check if experiment is running.
@@ -89,6 +89,7 @@ def get_variation(self, experiment, user_id, attributes):
89
89
experiment_key: Experiment for which user variation needs to be determined.
90
90
user_id: ID for user.
91
91
attributes: Dict representing user attributes.
92
+ ignore_user_profile: True to ignore the user profile lookup. Defaults to False.
92
93
93
94
Returns:
94
95
Variation user should see. None if user is not in experiment or experiment is not running.
@@ -106,7 +107,7 @@ def get_variation(self, experiment, user_id, attributes):
106
107
107
108
# Check to see if user has a decision available for the given experiment
108
109
user_profile = UserProfile (user_id )
109
- if self .user_profile_service :
110
+ if not ignore_user_profile and self .user_profile_service :
110
111
try :
111
112
retrieved_profile = self .user_profile_service .lookup (user_id )
112
113
except :
@@ -137,7 +138,7 @@ def get_variation(self, experiment, user_id, attributes):
137
138
138
139
if variation :
139
140
# Store this new decision and return the variation for the user
140
- if self .user_profile_service :
141
+ if not ignore_user_profile and self .user_profile_service :
141
142
try :
142
143
user_profile .save_variation_for_experiment (experiment .id , variation .id )
143
144
self .user_profile_service .save (user_profile .__dict__ )
@@ -148,3 +149,98 @@ def get_variation(self, experiment, user_id, attributes):
148
149
return variation
149
150
150
151
return None
152
+
153
+ def get_variation_for_layer (self , layer , user_id , attributes = None , ignore_user_profile = False ):
154
+ """ Determine which variation the user is in for a given layer. Returns the variation of the first experiment the user qualifies for.
155
+
156
+ Args:
157
+ layer: Layer for which we are getting the variation.
158
+ user_id: ID for user.
159
+ attributes: Dict representing user attributes.
160
+ ignore_user_profile: True to ignore the user profile lookup. Defaults to False.
161
+
162
+
163
+ Returns:
164
+ Variation the user should see. None if the user is not in any of the layer's experiments.
165
+ """
166
+ # Go through each experiment in order and try to get the variation for the user
167
+ if layer :
168
+ for experiment_dict in layer .experiments :
169
+ experiment = self .config .get_experiment_from_key (experiment_dict ['key' ])
170
+ variation = self .get_variation (experiment , user_id , attributes , ignore_user_profile )
171
+ if variation :
172
+ self .logger .log (enums .LogLevels .DEBUG , 'User "%s" is in variation %s of experiment %s.' % (user_id , variation .key , experiment .key ))
173
+ # Return as soon as we get a variation
174
+ return variation
175
+
176
+ return None
177
+
178
+ def get_variation_for_feature (self , feature , user_id , attributes = None ):
179
+ """ Returns the variation the user is bucketed in for the given feature.
180
+
181
+ Args:
182
+ feature: Feature for which we are determining if it is enabled or not for the given user.
183
+ user_id: ID for user.
184
+ attributes: Dict representing user attributes.
185
+
186
+ Returns:
187
+ Variation that the user is bucketed in. None if the user is not in any variation.
188
+ """
189
+ variation = None
190
+
191
+ # First check if the feature is in a mutex group
192
+ if feature .groupId :
193
+ group = self .config .get_group (feature .groupId )
194
+ if group :
195
+ experiment = self .get_experiment_in_group (group , user_id )
196
+ if experiment and experiment .id in feature .experimentIds :
197
+ variation = self .get_variation (experiment , user_id , attributes )
198
+
199
+ if variation :
200
+ self .logger .log (enums .LogLevels .DEBUG , 'User "%s" is in variation %s of experiment %s.' % (user_id , variation .key , experiment .key ))
201
+ else :
202
+ self .logger .log (enums .LogLevels .ERROR , enums .Errors .INVALID_GROUP_ID_ERROR .format ('_get_variation_for_feature' ))
203
+
204
+ # Next check if the feature is being experimented on
205
+ elif feature .experimentIds :
206
+ # If an experiment is not in a group, then the feature can only be associated with one experiment
207
+ experiment = self .config .get_experiment_from_id (feature .experimentIds [0 ])
208
+ if experiment :
209
+ variation = self .get_variation (experiment , user_id , attributes )
210
+
211
+ if variation :
212
+ self .logger .log (enums .LogLevels .DEBUG , 'User "%s" is in variation %s of experiment %s.' % (user_id , variation .key , experiment .key ))
213
+
214
+ # Next check if user is part of a rollout
215
+ if not variation and feature .layerId :
216
+ layer = self .config .get_layer_from_id (feature .layerId )
217
+ variation = self .get_variation_for_layer (layer , user_id , attributes , ignore_user_profile = True )
218
+
219
+ return variation
220
+
221
+ def get_experiment_in_group (self , group , user_id ):
222
+ """ Determine which experiment in the group the user is bucketed into.
223
+
224
+ Args:
225
+ group: The group to bucket the user into.
226
+ user_id: ID of the user.
227
+
228
+ Returns:
229
+ Experiment if the user is bucketed into an experiment in the specified group. None otherwise.
230
+ """
231
+
232
+ experiment_id = self .bucketer .find_bucket (user_id , group .id , group .trafficAllocation )
233
+ if experiment_id :
234
+ experiment = self .config .get_experiment_from_id (experiment_id )
235
+ if experiment :
236
+ self .logger .log (enums .LogLevels .INFO ,
237
+ 'User "%s" is in experiment %s of group %s.' %
238
+ (user_id , experiment .key , group .id ))
239
+ return experiment
240
+
241
+ self .logger .log (enums .LogLevels .INFO ,
242
+ 'User "%s" is not in any experiments of group %s.' %
243
+ (user_id , group .id ))
244
+
245
+ return None
246
+
0 commit comments