-
Notifications
You must be signed in to change notification settings - Fork 37
Add Audiences to OptimizelyConfig and expose in OptimizelyExperiment #342
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 1 commit
e80fdfb
d58b71a
a583ea5
5b2196c
f964f94
f60ab0a
df1b081
9c9bcea
61d5c24
13703ca
ef95cd8
b8828b9
c3bc816
f1bd533
0ad43d0
942bfe9
528b8f2
c3c3d2c
2fef52a
d3b2a46
dda6e76
4f2d7fb
f90e3e3
4471555
bb98741
48f604b
8179f2b
d694c7f
ec39096
a687a9b
11be430
ecf2e45
f568aad
3b8706f
2504f98
1cd6aab
bc98adc
98ff2b6
d6fa32d
16059d7
0320627
8187f6f
0804bb8
ba3bbef
2567bac
d401c72
6b4a00d
a1ed815
ec4218a
508f82f
26ad430
1f35dda
a4e497f
bf92fd7
2d6def3
bec791a
286f178
c3faba3
199a35f
4fa5d05
4356a4d
a273d11
c8d68f7
a9ac50c
6ce98e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,13 +12,15 @@ | |
# limitations under the License. | ||
|
||
import copy | ||
from optimizely.helpers.condition import ConditionOperatorTypes | ||
from optimizely.entities import Experiment | ||
|
||
from .project_config import ProjectConfig | ||
|
||
|
||
class OptimizelyConfig(object): | ||
def __init__(self, revision, experiments_map, features_map, datafile=None, | ||
sdk_key=None, environment_key=None, attributes=None, events=None): | ||
sdk_key=None, environment_key=None, attributes=None, events=None, audiences=None): | ||
self.revision = revision | ||
self.experiments_map = experiments_map | ||
self.features_map = features_map | ||
|
@@ -27,6 +29,7 @@ def __init__(self, revision, experiments_map, features_map, datafile=None, | |
self.environment_key = environment_key | ||
self.attributes = attributes or [] | ||
self.events = events or [] | ||
self.audiences = audiences or [] | ||
|
||
def get_datafile(self): | ||
""" Get the datafile associated with OptimizelyConfig. | ||
|
@@ -51,7 +54,7 @@ def get_environment_key(self): | |
A string containing environment key. | ||
""" | ||
return self.environment_key | ||
|
||
def get_attributes(self): | ||
""" Get the attributes associated with OptimizelyConfig | ||
|
||
|
@@ -84,12 +87,21 @@ def get_events(self): | |
""" | ||
return self.events | ||
|
||
def get_audiences(self): | ||
""" Get the audiences associated with OptimizelyConfig | ||
|
||
returns: | ||
A list of audiences. | ||
""" | ||
return self.audiences | ||
|
||
|
||
class OptimizelyExperiment(object): | ||
def __init__(self, id, key, variations_map): | ||
self.id = id | ||
self.key = key | ||
self.variations_map = variations_map | ||
self.audiences = "" | ||
|
||
|
||
class OptimizelyFeature(object): | ||
|
@@ -129,6 +141,13 @@ def __init__(self, id, key, experiment_ids): | |
self.experiment_ids = experiment_ids | ||
|
||
|
||
class OptimizelyAudience(object): | ||
def __init__(self, id, name, conditions): | ||
self.id = id | ||
self.name = name | ||
self.conditions = conditions | ||
|
||
|
||
class OptimizelyConfigService(object): | ||
""" Class encapsulating methods to be used in creating instance of OptimizelyConfig. """ | ||
|
||
|
@@ -155,6 +174,97 @@ def __init__(self, project_config): | |
|
||
self._create_lookup_maps() | ||
|
||
''' | ||
Merging typed_audiences with audiences from project_config. | ||
The typed_audiences has higher presidence. | ||
The-inside-man marked this conversation as resolved.
Show resolved
Hide resolved
|
||
''' | ||
|
||
typed_audiences = project_config.typed_audiences or [] | ||
|
||
for old_audience in project_config.audiences: | ||
# check if old_audience.id exists in new_audiences.id from typed_audiences | ||
if len([new_audience for new_audience in typed_audiences if new_audience.get('id') == old_audience.get('id')]) == 0: | ||
if old_audience.get('id') == "$opt_dummy_audience": | ||
continue | ||
else: | ||
typed_audiences.append(old_audience) | ||
|
||
self.audiences = typed_audiences | ||
The-inside-man marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
audiences_map = {} | ||
|
||
for audience in self.audiences: | ||
audiences_map[audience.get('id')] = audience.get('name') | ||
|
||
# Updating each entities.Experiment found in the experiment_key_map | ||
for ent_exp in project_config.experiment_key_map.values(): | ||
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. This covers "experiment" rules. We also need to do the same to experiments in rollout ("delivery" rules) as well. 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. Delivery Rules added to OptimizelyConfig and test cases to cover |
||
experiments_by_key, experiments_by_id = self._get_experiments_maps() | ||
try: | ||
optly_experiment = experiments_by_id[ent_exp.id] | ||
self.update_experiment(optly_experiment, ent_exp.audienceConditions, audiences_map) | ||
The-inside-man marked this conversation as resolved.
Show resolved
Hide resolved
|
||
except KeyError: | ||
# ID not in map | ||
continue | ||
|
||
def update_experiment(self, experiment, conditions, audiences_map): | ||
|
||
audiences = self.replace_ids_with_names(conditions, audiences_map) | ||
experiment.audiences = audiences | ||
|
||
def replace_ids_with_names(self, conditions, audiences_map): | ||
# Confirm where conditions are coming from... | ||
if conditions != None: | ||
return self.stringify_conditions(conditions, audiences_map) | ||
else: | ||
return None | ||
|
||
def lookup_name_from_id(self, audience_id, audiences_map): | ||
name = "" | ||
try: | ||
name = audiences_map[audience_id] | ||
except KeyError: | ||
name = audience_id | ||
|
||
return name | ||
|
||
def stringify_conditions(self, conditions, audiences_map): | ||
ARGS = ConditionOperatorTypes.operators | ||
The-inside-man marked this conversation as resolved.
Show resolved
Hide resolved
|
||
condition = "" | ||
ret = "(" | ||
length = len(conditions) | ||
|
||
if length == 0: | ||
return | ||
if length == 1: | ||
''' | ||
Lookup ID and replace with name | ||
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. I think you could use one line docstring here, for the sake of space, we do multiline dostrings mainly for functions and classes |
||
''' | ||
audience_name = self.lookup_name_from_id(conditions[0], audiences_map) | ||
|
||
return audience_name | ||
|
||
if length > 1: | ||
for i in range(length): | ||
if conditions[i] in ARGS: | ||
condition = conditions[i] | ||
else: | ||
if type(conditions[i]) == list: | ||
if i + 1 < length: | ||
ret += self.stringify_conditions(conditions[i], | ||
audiences_map) + ' ' + condition.upper() + ' ' | ||
else: | ||
ret += self.stringify_conditions(conditions[i], audiences_map) | ||
else: | ||
# Handle ID's here - Lookup required | ||
audience_name = self.lookup_name_from_id(conditions[i], audiences_map) | ||
if audience_name != None: | ||
if i + 1 < length: | ||
ret += '"' + audience_name + '" ' + condition.upper() + ' ' | ||
else: | ||
ret += '"' + audience_name + '"' | ||
|
||
return ret + ")" | ||
|
||
def get_config(self): | ||
""" Gets instance of OptimizelyConfig | ||
|
||
|
@@ -176,7 +286,8 @@ def get_config(self): | |
self.sdk_key, | ||
self.environment_key, | ||
self.attributes, | ||
self.events) | ||
self.events, | ||
self.audiences) | ||
The-inside-man marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def _create_lookup_maps(self): | ||
""" Creates lookup maps to avoid redundant iteration of config objects. """ | ||
|
@@ -311,37 +422,3 @@ def _get_features_map(self, experiments_id_map): | |
features_map[feature['key']] = optly_feature | ||
|
||
return features_map | ||
|
||
def get_attributes_map(self): | ||
""" Gets attributes map for the project config. | ||
|
||
Returns: | ||
dict -- Attribute key, OptimizelyAttribute map | ||
""" | ||
|
||
attributes_map = {} | ||
|
||
for attribute in self.attributes: | ||
optly_attribute = OptimizelyAttribute( | ||
attribute['id'], attribute['key'] | ||
) | ||
attributes_map[attribute['key']] = optly_attribute | ||
|
||
return attributes_map | ||
|
||
def get_events_map(self): | ||
""" Gets events map for the project config. | ||
|
||
Returns: | ||
dict -- Event key, OptimizelyEvent map | ||
""" | ||
|
||
events_map = {} | ||
|
||
for event in self.events: | ||
optly_event = OptimizelyEvent( | ||
event['id'], event['key'], event.get('experimentIds', []) | ||
) | ||
events_map[event['key']] = optly_event | ||
|
||
return events_map |
Uh oh!
There was an error while loading. Please reload this page.