-
Notifications
You must be signed in to change notification settings - Fork 36
Add forced-decisions APIs to OptimizelyUserContext #361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
c5d9dae
17ad742
cee1fb8
58977d2
340cbce
c81a425
c89bc3c
2fe78ab
d80c555
5ed2fb4
6003fdc
e4dc745
d75f389
68146a1
a261899
a837f03
de4a31c
0c52707
4116b43
081cd79
e061abc
337f8d9
a71f50e
981cbe5
94d5af9
e9cd304
2dff4c6
e2f1db3
6849c33
55fe98f
94a0c26
e5aaccb
44373e9
e6c1772
ab40d9e
795b41a
dbbc051
75fe2bb
243d447
1010ece
17efc27
201548f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,11 +12,12 @@ | |
# limitations under the License. | ||
|
||
import json | ||
from collections import OrderedDict | ||
|
||
from .helpers import condition as condition_helper | ||
from .helpers import enums | ||
from . import entities | ||
from . import exceptions | ||
from .helpers import condition as condition_helper | ||
from .helpers import enums | ||
|
||
SUPPORTED_VERSIONS = [ | ||
enums.DatafileVersions.V2, | ||
|
@@ -134,11 +135,45 @@ def __init__(self, datafile, logger, error_handler): | |
self.experiment_feature_map = {} | ||
for feature in self.feature_key_map.values(): | ||
feature.variables = self._generate_key_map(feature.variables, 'key', entities.Variable) | ||
|
||
for exp_id in feature.experimentIds: | ||
# Add this experiment in experiment-feature map. | ||
self.experiment_feature_map[exp_id] = [feature.id] | ||
|
||
# all rules(experiment rules and delivery rules) for each flag | ||
self.flag_rules_map = {} | ||
for flag in self.feature_flags: | ||
|
||
experiments = [] | ||
if not flag['experimentIds'] == '': | ||
Mat001 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for exp_id in flag['experimentIds']: | ||
experiments.append(self.experiment_id_map[exp_id]) | ||
if not flag['rolloutId'] == '': | ||
Mat001 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rollout = self.rollout_id_map[flag['rolloutId']] | ||
|
||
rollout_experiments = self.get_rollout_experiments_map(rollout) | ||
jaeopt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if rollout and rollout.experiments: | ||
experiments.extend(rollout_experiments) | ||
|
||
self.flag_rules_map[flag['key']] = experiments | ||
jaeopt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# All variations for each flag | ||
# Datafile does not contain a separate entity for this. | ||
# We collect variations used in each rule (experiment rules and delivery rules) | ||
self.flag_variations_map = {} | ||
|
||
for flag_key, rules in self.flag_rules_map.items(): | ||
Mat001 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
variations = [] | ||
for rule in rules: | ||
# get variations as objects (rule.variations gives list) | ||
variation_objects = self.variation_key_map[rule.key].values() | ||
|
||
for variation in variation_objects: | ||
if variation.id not in [var.id for var in variations]: | ||
variations.append(variation) | ||
|
||
self.flag_variations_map[flag_key] = variations | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add test cases for validating flag_variations_map if not done yet
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in progress |
||
|
||
@staticmethod | ||
def _generate_key_map(entity_list, key, entity_class): | ||
""" Helper method to generate map from key to entity object for given list of dicts. | ||
|
@@ -152,7 +187,10 @@ def _generate_key_map(entity_list, key, entity_class): | |
Map mapping key to entity object. | ||
""" | ||
|
||
key_map = {} | ||
# using ordered dict here to preserve insertion order of entities | ||
# OrderedDict() is needed for Py versions 3.5 and less to work. | ||
# Insertion order has been made default in dicts since Py 3.6 | ||
key_map = OrderedDict() | ||
for obj in entity_list: | ||
key_map[obj[key]] = entity_class(**obj) | ||
|
||
|
@@ -175,6 +213,21 @@ def _deserialize_audience(audience_map): | |
|
||
return audience_map | ||
|
||
def get_rollout_experiments_map(self, rollout): | ||
""" Helper method to get rollout experiments as a map. | ||
jaeopt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Args: | ||
rollout: rollout | ||
|
||
Returns: | ||
Mapped rollout experiments. | ||
""" | ||
|
||
rollout_experiments_id_map = self._generate_key_map(rollout.experiments, 'id', entities.Experiment) | ||
jaeopt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rollout_experiments = [exper for exper in rollout_experiments_id_map.values()] | ||
Mat001 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return rollout_experiments | ||
|
||
jaeopt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
def get_typecast_value(self, value, type): | ||
""" Helper method to determine actual value based on type of feature variable. | ||
|
||
|
@@ -334,31 +387,40 @@ def get_audience(self, audience_id): | |
self.logger.error('Audience ID "%s" is not in datafile.' % audience_id) | ||
self.error_handler.handle_error(exceptions.InvalidAudienceException((enums.Errors.INVALID_AUDIENCE))) | ||
|
||
def get_variation_from_key(self, experiment_key, variation_key): | ||
""" Get variation given experiment and variation key. | ||
def get_variation_from_key(self, experiment_key, variation): | ||
""" Get variation given experiment and variation. | ||
jaeopt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Args: | ||
experiment: Key representing parent experiment of variation. | ||
variation_key: Key representing the variation. | ||
Variation is of type variation object or None. | ||
|
||
Returns | ||
Object representing the variation. | ||
""" | ||
|
||
variation_map = self.variation_key_map.get(experiment_key) | ||
variation_key = None | ||
|
||
if variation_map: | ||
variation = variation_map.get(variation_key) | ||
if variation: | ||
return variation | ||
if isinstance(variation, tuple): | ||
if isinstance(variation[0], entities.Variation): | ||
variation_key, received_reasons = variation | ||
jaeopt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: | ||
variation_map = self.variation_key_map.get(experiment_key) | ||
|
||
if variation_map: | ||
variation_key = variation_map.get(variation) | ||
else: | ||
self.logger.error('Variation key "%s" is not in datafile.' % variation_key) | ||
self.error_handler.handle_error(exceptions.InvalidVariationException(enums.Errors.INVALID_VARIATION)) | ||
self.logger.error('Experiment key "%s" is not in datafile.' % experiment_key) | ||
self.error_handler.handle_error( | ||
exceptions.InvalidExperimentException(enums.Errors.INVALID_EXPERIMENT_KEY)) | ||
return None | ||
|
||
self.logger.error('Experiment key "%s" is not in datafile.' % experiment_key) | ||
self.error_handler.handle_error(exceptions.InvalidExperimentException(enums.Errors.INVALID_EXPERIMENT_KEY)) | ||
return None | ||
if variation_key: | ||
return variation_key | ||
else: | ||
self.logger.error('Variation key "%s" is not in datafile.' % variation) | ||
self.error_handler.handle_error(exceptions.InvalidVariationException(enums.Errors.INVALID_VARIATION)) | ||
return None | ||
|
||
def get_variation_from_id(self, experiment_key, variation_id): | ||
""" Get variation given experiment and variation ID. | ||
|
@@ -485,7 +547,6 @@ def get_variable_value_for_variation(self, variable, variation): | |
|
||
if not variable or not variation: | ||
return None | ||
|
||
if variation.id not in self.variation_variable_usage_map: | ||
self.logger.error('Variation with ID "%s" is not in the datafile.' % variation.id) | ||
return None | ||
|
Uh oh!
There was an error while loading. Please reload this page.