|
15 | 15 | import sys
|
16 | 16 |
|
17 | 17 | from . import decision_service
|
| 18 | +from . import entities |
18 | 19 | from . import event_builder
|
19 | 20 | from . import exceptions
|
20 | 21 | from . import project_config
|
21 | 22 | from .error_handler import NoOpErrorHandler as noop_error_handler
|
22 | 23 | from .event_dispatcher import EventDispatcher as default_event_dispatcher
|
23 | 24 | from .helpers import enums
|
24 |
| -from .helpers import event_tag_utils |
25 | 25 | from .helpers import validator
|
26 | 26 | from .logger import NoOpLogger as noop_logger
|
27 | 27 | from .logger import SimpleLogger
|
@@ -178,6 +178,64 @@ def _send_impression_event(self, experiment, variation, user_id, attributes):
|
178 | 178 | error = sys.exc_info()[1]
|
179 | 179 | self.logger.log(enums.LogLevels.ERROR, 'Unable to dispatch impression event. Error: %s' % str(error))
|
180 | 180 |
|
| 181 | + def _get_feature_variable_for_type(self, feature_key, variable_key, variable_type, user_id, attributes): |
| 182 | + """ Helper method to determine value for a certain variable attached to a feature flag based on type of variable. |
| 183 | +
|
| 184 | + Args: |
| 185 | + feature_key: Key of the feature whose variable's value is being accessed. |
| 186 | + variable_key: Key of the variable whose value is to be accessed. |
| 187 | + variable_type: Type of variable which could be one of boolean/double/integer/string. |
| 188 | + user_id: ID for user. |
| 189 | + attributes: Dict representing user attributes. |
| 190 | +
|
| 191 | + Returns: |
| 192 | + Value of the variable. None if: |
| 193 | + - Feature key is invalid. |
| 194 | + - Variable key is invalid. |
| 195 | + - Mismatch with type of variable. |
| 196 | + """ |
| 197 | + |
| 198 | + feature_flag = self.config.get_feature_from_key(feature_key) |
| 199 | + if not feature_flag: |
| 200 | + return None |
| 201 | + |
| 202 | + variable = self.config.get_variable_for_feature(feature_key, variable_key) |
| 203 | + if not variable: |
| 204 | + return None |
| 205 | + |
| 206 | + # Return None if type differs |
| 207 | + if variable.type != variable_type: |
| 208 | + self.logger.log( |
| 209 | + enums.LogLevels.WARNING, |
| 210 | + 'Requested variable type "%s", but variable is of type "%s". ' |
| 211 | + 'Use correct API to retrieve value. Returning None.' % (variable_type, variable.type) |
| 212 | + ) |
| 213 | + return None |
| 214 | + |
| 215 | + decision = self.decision_service.get_variation_for_feature(feature_flag, user_id, attributes) |
| 216 | + if decision.variation: |
| 217 | + variable_value = self.config.get_variable_value_for_variation(variable, decision.variation) |
| 218 | + self.logger.log( |
| 219 | + enums.LogLevels.INFO, |
| 220 | + 'Value for variable "%s" of feature flag "%s" is %s for user "%s".' % ( |
| 221 | + variable_key, feature_key, variable_value, user_id |
| 222 | + )) |
| 223 | + else: |
| 224 | + variable_value = variable.defaultValue |
| 225 | + self.logger.log( |
| 226 | + enums.LogLevels.INFO, |
| 227 | + 'User "%s" is not in any variation or rollout rule. ' |
| 228 | + 'Returning default value for variable "%s" of feature flag "%s".' % (user_id, variable_key, feature_key) |
| 229 | + ) |
| 230 | + |
| 231 | + try: |
| 232 | + actual_value = self.config.get_typecast_value(variable_value, variable_type) |
| 233 | + except: |
| 234 | + self.logger.log(enums.LogLevels.ERROR, 'Unable to cast value. Returning None.') |
| 235 | + actual_value = None |
| 236 | + |
| 237 | + return actual_value |
| 238 | + |
181 | 239 | def activate(self, experiment_key, user_id, attributes=None):
|
182 | 240 | """ Buckets visitor and sends impression event to Optimizely.
|
183 | 241 |
|
@@ -350,6 +408,82 @@ def get_enabled_features(self, user_id, attributes=None):
|
350 | 408 |
|
351 | 409 | return enabled_features
|
352 | 410 |
|
| 411 | + def get_feature_variable_boolean(self, feature_key, variable_key, user_id, attributes=None): |
| 412 | + """ Returns value for a certain boolean variable attached to a feature flag. |
| 413 | +
|
| 414 | + Args: |
| 415 | + feature_key: Key of the feature whose variable's value is being accessed. |
| 416 | + variable_key: Key of the variable whose value is to be accessed. |
| 417 | + user_id: ID for user. |
| 418 | + attributes: Dict representing user attributes. |
| 419 | +
|
| 420 | + Returns: |
| 421 | + Boolean value of the variable. None if: |
| 422 | + - Feature key is invalid. |
| 423 | + - Variable key is invalid. |
| 424 | + - Mismatch with type of variable. |
| 425 | + """ |
| 426 | + |
| 427 | + variable_type = entities.Variable.Type.BOOLEAN |
| 428 | + return self._get_feature_variable_for_type(feature_key, variable_key, variable_type, user_id, attributes) |
| 429 | + |
| 430 | + def get_feature_variable_double(self, feature_key, variable_key, user_id, attributes=None): |
| 431 | + """ Returns value for a certain double variable attached to a feature flag. |
| 432 | +
|
| 433 | + Args: |
| 434 | + feature_key: Key of the feature whose variable's value is being accessed. |
| 435 | + variable_key: Key of the variable whose value is to be accessed. |
| 436 | + user_id: ID for user. |
| 437 | + attributes: Dict representing user attributes. |
| 438 | +
|
| 439 | + Returns: |
| 440 | + Double value of the variable. None if: |
| 441 | + - Feature key is invalid. |
| 442 | + - Variable key is invalid. |
| 443 | + - Mismatch with type of variable. |
| 444 | + """ |
| 445 | + |
| 446 | + variable_type = entities.Variable.Type.DOUBLE |
| 447 | + return self._get_feature_variable_for_type(feature_key, variable_key, variable_type, user_id, attributes) |
| 448 | + |
| 449 | + def get_feature_variable_integer(self, feature_key, variable_key, user_id, attributes=None): |
| 450 | + """ Returns value for a certain integer variable attached to a feature flag. |
| 451 | +
|
| 452 | + Args: |
| 453 | + feature_key: Key of the feature whose variable's value is being accessed. |
| 454 | + variable_key: Key of the variable whose value is to be accessed. |
| 455 | + user_id: ID for user. |
| 456 | + attributes: Dict representing user attributes. |
| 457 | +
|
| 458 | + Returns: |
| 459 | + Integer value of the variable. None if: |
| 460 | + - Feature key is invalid. |
| 461 | + - Variable key is invalid. |
| 462 | + - Mismatch with type of variable. |
| 463 | + """ |
| 464 | + |
| 465 | + variable_type = entities.Variable.Type.INTEGER |
| 466 | + return self._get_feature_variable_for_type(feature_key, variable_key, variable_type, user_id, attributes) |
| 467 | + |
| 468 | + def get_feature_variable_string(self, feature_key, variable_key, user_id, attributes=None): |
| 469 | + """ Returns value for a certain string variable attached to a feature. |
| 470 | +
|
| 471 | + Args: |
| 472 | + feature_key: Key of the feature whose variable's value is being accessed. |
| 473 | + variable_key: Key of the variable whose value is to be accessed. |
| 474 | + user_id: ID for user. |
| 475 | + attributes: Dict representing user attributes. |
| 476 | +
|
| 477 | + Returns: |
| 478 | + String value of the variable. None if: |
| 479 | + - Feature key is invalid. |
| 480 | + - Variable key is invalid. |
| 481 | + - Mismatch with type of variable. |
| 482 | + """ |
| 483 | + |
| 484 | + variable_type = entities.Variable.Type.STRING |
| 485 | + return self._get_feature_variable_for_type(feature_key, variable_key, variable_type, user_id, attributes) |
| 486 | + |
353 | 487 | def set_forced_variation(self, experiment_key, user_id, variation_key):
|
354 | 488 | """ Force a user into a variation for a given experiment.
|
355 | 489 |
|
|
0 commit comments