Skip to content

Commit

Permalink
Resolves conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
rashidsp committed Aug 28, 2018
2 parents 7e13cba + 84736de commit 64c5f2f
Show file tree
Hide file tree
Showing 10 changed files with 400 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.5.5"
- "3.6"
- "pypy"
- "pypy3"
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.1.1
August 21st, 2018

- Fix: record conversions for all experiments using an event when using track([#136](https://github.com/optimizely/python-sdk/pull/136)).

## 2.1.0
July 2nd, 2018

Expand Down
44 changes: 22 additions & 22 deletions optimizely/event_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,40 +244,41 @@ def _get_required_params_for_conversion(self, event_key, event_tags, decisions):
Returns:
Dict consisting of the decisions and events info for conversion event.
"""
snapshot = {}
snapshot[self.EventParams.DECISIONS] = []

for experiment_id, variation_id in decisions:
snapshot = {}

experiment = self.config.get_experiment_from_id(experiment_id)

if variation_id:
snapshot[self.EventParams.DECISIONS] = [{
snapshot[self.EventParams.DECISIONS].append({
self.EventParams.EXPERIMENT_ID: experiment_id,
self.EventParams.VARIATION_ID: variation_id,
self.EventParams.CAMPAIGN_ID: experiment.layerId
}]
})

event_dict = {
self.EventParams.EVENT_ID: self.config.get_event(event_key).id,
self.EventParams.TIME: self._get_time(),
self.EventParams.KEY: event_key,
self.EventParams.UUID: str(uuid.uuid4())
}

if event_tags:
revenue_value = event_tag_utils.get_revenue_value(event_tags, self.logger)
if revenue_value is not None:
event_dict[event_tag_utils.REVENUE_METRIC_TYPE] = revenue_value
event_dict = {
self.EventParams.EVENT_ID: self.config.get_event(event_key).id,
self.EventParams.TIME: self._get_time(),
self.EventParams.KEY: event_key,
self.EventParams.UUID: str(uuid.uuid4())
}

numeric_value = event_tag_utils.get_numeric_value(event_tags, self.logger)
if numeric_value is not None:
event_dict[event_tag_utils.NUMERIC_METRIC_TYPE] = numeric_value
if event_tags:
revenue_value = event_tag_utils.get_revenue_value(event_tags, self.logger)
if revenue_value is not None:
event_dict[event_tag_utils.REVENUE_METRIC_TYPE] = revenue_value

if len(event_tags) > 0:
event_dict[self.EventParams.TAGS] = event_tags
numeric_value = event_tag_utils.get_numeric_value(event_tags, self.logger)
if numeric_value is not None:
event_dict[event_tag_utils.NUMERIC_METRIC_TYPE] = numeric_value

snapshot[self.EventParams.EVENTS] = [event_dict]
if len(event_tags) > 0:
event_dict[self.EventParams.TAGS] = event_tags

return snapshot
snapshot[self.EventParams.EVENTS] = [event_dict]
return snapshot

def create_impression_event(self, experiment, variation_id, user_id, attributes):
""" Create impression Event to be sent to the logging endpoint.
Expand Down Expand Up @@ -320,7 +321,6 @@ def create_conversion_event(self, event_key, user_id, attributes, event_tags, de
conversion_params = self._get_required_params_for_conversion(event_key, event_tags, decisions)

params[self.EventParams.USERS][0][self.EventParams.SNAPSHOTS].append(conversion_params)

return Event(self.EVENTS_URL,
params,
http_verb=self.HTTP_VERB,
Expand Down
18 changes: 17 additions & 1 deletion optimizely/helpers/validator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016-2017, Optimizely
# Copyright 2016-2018, Optimizely
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Expand All @@ -13,6 +13,7 @@

import json
import jsonschema
from six import string_types

from optimizely.user_profile import UserProfile
from . import constants
Expand Down Expand Up @@ -151,3 +152,18 @@ def is_user_profile_valid(user_profile):
return False

return True


def is_non_empty_string(input_id_key):
""" Determine if provided input_id_key is a non-empty string or not.
Args:
input_id_key: Variable which needs to be validated.
Returns:
Boolean depending upon whether input is valid or not.
"""
if input_id_key and isinstance(input_id_key, string_types):
return True

return False
37 changes: 33 additions & 4 deletions optimizely/optimizely.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ def _send_impression_event(self, experiment, variation, user_id, attributes):
self.event_dispatcher.dispatch_event(impression_event)
except:
self.logger.exception('Unable to dispatch impression event!')

self.notification_center.send_notifications(enums.NotificationTypes.ACTIVATE,
experiment, user_id, attributes, variation, impression_event)

Expand Down Expand Up @@ -262,6 +263,14 @@ def activate(self, experiment_key, user_id, attributes=None):
self.logger.error(enums.Errors.INVALID_DATAFILE.format('activate'))
return None

if not validator.is_non_empty_string(experiment_key):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('experiment_key'))
return None

if not validator.is_non_empty_string(user_id):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('user_id'))
return None

variation_key = self.get_variation(experiment_key, user_id, attributes)

if not variation_key:
Expand Down Expand Up @@ -291,6 +300,14 @@ def track(self, event_key, user_id, attributes=None, event_tags=None):
self.logger.error(enums.Errors.INVALID_DATAFILE.format('track'))
return

if not validator.is_non_empty_string(event_key):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('event_key'))
return

if not validator.is_non_empty_string(user_id):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('user_id'))
return

if not self._validate_user_inputs(attributes, event_tags):
return

Expand Down Expand Up @@ -339,6 +356,14 @@ def get_variation(self, experiment_key, user_id, attributes=None):
self.logger.error(enums.Errors.INVALID_DATAFILE.format('get_variation'))
return None

if not validator.is_non_empty_string(experiment_key):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('experiment_key'))
return None

if not validator.is_non_empty_string(user_id):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('user_id'))
return None

experiment = self.config.get_experiment_from_key(experiment_key)

if not experiment:
Expand Down Expand Up @@ -373,12 +398,12 @@ def is_feature_enabled(self, feature_key, user_id, attributes=None):
self.logger.error(enums.Errors.INVALID_DATAFILE.format('is_feature_enabled'))
return False

if feature_key is None:
self.logger.error(enums.Errors.NONE_FEATURE_KEY_PARAMETER)
if not validator.is_non_empty_string(feature_key):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('feature_key'))
return False

if user_id is None:
self.logger.error(enums.Errors.NONE_USER_ID_PARAMETER)
if not validator.is_non_empty_string(user_id):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('user_id'))
return False

feature = self.config.get_feature_from_key(feature_key)
Expand Down Expand Up @@ -417,6 +442,10 @@ def get_enabled_features(self, user_id, attributes=None):
self.logger.error(enums.Errors.INVALID_DATAFILE.format('get_enabled_features'))
return enabled_features

if not validator.is_non_empty_string(user_id):
self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('user_id'))
return enabled_features

for feature in self.config.feature_key_map.values():
if self.is_feature_enabled(feature.key, user_id, attributes):
enabled_features.append(feature.key)
Expand Down
2 changes: 1 addition & 1 deletion optimizely/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.

version_info = (2, 1, 0)
version_info = (2, 1, 1)
__version__ = '.'.join(str(v) for v in version_info)
151 changes: 149 additions & 2 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

class BaseTest(unittest.TestCase):

def setUp(self):
def setUp(self, config_dict='config_dict'):
self.config_dict = {
'revision': '42',
'version': '2',
Expand Down Expand Up @@ -375,5 +375,152 @@ def setUp(self):
}]
}

self.optimizely = optimizely.Optimizely(json.dumps(self.config_dict))
self.config_dict_with_multiple_experiments = {
'revision': '42',
'version': '2',
'events': [{
'key': 'test_event',
'experimentIds': ['111127', '111130'],
'id': '111095'
}, {
'key': 'Total Revenue',
'experimentIds': ['111127'],
'id': '111096'
}],
'experiments': [{
'key': 'test_experiment',
'status': 'Running',
'forcedVariations': {
'user_1': 'control',
'user_2': 'control'
},
'layerId': '111182',
'audienceIds': ['11154'],
'trafficAllocation': [{
'entityId': '111128',
'endOfRange': 4000
}, {
'entityId': '',
'endOfRange': 5000
}, {
'entityId': '111129',
'endOfRange': 9000
}],
'id': '111127',
'variations': [{
'key': 'control',
'id': '111128'
}, {
'key': 'variation',
'id': '111129'
}]
}, {
'key': 'test_experiment_2',
'status': 'Running',
'forcedVariations': {
'user_1': 'control',
'user_2': 'control'
},
'layerId': '111182',
'audienceIds': ['11154'],
'trafficAllocation': [{
'entityId': '111131',
'endOfRange': 4000
}, {
'entityId': '',
'endOfRange': 5000
}, {
'entityId': '111132',
'endOfRange': 9000
}],
'id': '111130',
'variations': [{
'key': 'control',
'id': '111133'
}, {
'key': 'variation',
'id': '111134'
}]
}],
'groups': [{
'id': '19228',
'policy': 'random',
'experiments': [{
'id': '32222',
'key': 'group_exp_1',
'status': 'Running',
'audienceIds': [],
'layerId': '111183',
'variations': [{
'key': 'group_exp_1_control',
'id': '28901'
}, {
'key': 'group_exp_1_variation',
'id': '28902'
}],
'forcedVariations': {
'user_1': 'group_exp_1_control',
'user_2': 'group_exp_1_control'
},
'trafficAllocation': [{
'entityId': '28901',
'endOfRange': 3000
}, {
'entityId': '28902',
'endOfRange': 9000
}]
}, {
'id': '32223',
'key': 'group_exp_2',
'status': 'Running',
'audienceIds': [],
'layerId': '111184',
'variations': [{
'key': 'group_exp_2_control',
'id': '28905'
}, {
'key': 'group_exp_2_variation',
'id': '28906'
}],
'forcedVariations': {
'user_1': 'group_exp_2_control',
'user_2': 'group_exp_2_control'
},
'trafficAllocation': [{
'entityId': '28905',
'endOfRange': 8000
}, {
'entityId': '28906',
'endOfRange': 10000
}]
}],
'trafficAllocation': [{
'entityId': '32222',
"endOfRange": 3000
}, {
'entityId': '32223',
'endOfRange': 7500
}]
}],
'accountId': '12001',
'attributes': [{
'key': 'test_attribute',
'id': '111094'
}],
'audiences': [{
'name': 'Test attribute users 1',
'conditions': '["and", ["or", ["or", '
'{"name": "test_attribute", "type": "custom_attribute", "value": "test_value_1"}]]]',
'id': '11154'
}, {
'name': 'Test attribute users 2',
'conditions': '["and", ["or", ["or", '
'{"name": "test_attribute", "type": "custom_attribute", "value": "test_value_2"}]]]',
'id': '11159'
}],
'projectId': '111001'
}

config = getattr(self, config_dict)
self.optimizely = optimizely.Optimizely(json.dumps(config))
self.project_config = self.optimizely.config

0 comments on commit 64c5f2f

Please sign in to comment.