Skip to content

Commit

Permalink
Merge 900d96d into f5b0d0c
Browse files Browse the repository at this point in the history
  • Loading branch information
msohailhussain committed Aug 28, 2019
2 parents f5b0d0c + 900d96d commit 846c91e
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 0 deletions.
12 changes: 12 additions & 0 deletions optimizely/event/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2019, 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
94 changes: 94 additions & 0 deletions optimizely/event/payload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Copyright 2019 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json


class EventBatch(object):
""" Class respresenting Event Batch. """

def __init__(self, account_id, project_id, revision, client_name, client_version,
anonymize_ip, enrich_decisions=True, visitors=None):
self.account_id = account_id
self.project_id = project_id
self.revision = revision
self.client_name = client_name
self.client_version = client_version
self.anonymize_ip = anonymize_ip
self.enrich_decisions = enrich_decisions
self.visitors = visitors or []

def __eq__(self, other):
batch_obj = json.loads(json.dumps(self.__dict__, default=lambda o: o.__dict__),
object_pairs_hook=self._dict_clean)
return batch_obj == other

def _dict_clean(self, obj):
""" Helper method to remove keys from dictionary with None values. """

result = {}
for k, v in obj:
if v is None and k in ['revenue', 'value', 'tags', 'decisions']:
continue
else:
result[k] = v
return result


class Decision(object):
""" Class respresenting Decision. """

def __init__(self, campaign_id, experiment_id, variation_id):
self.campaign_id = campaign_id
self.experiment_id = experiment_id
self.variation_id = variation_id


class Snapshot(object):
""" Class representing Snapshot. """

def __init__(self, events, decisions=None):
self.events = events
self.decisions = decisions


class SnapshotEvent(object):
""" Class representing Snapshot Event. """

def __init__(self, entity_id, uuid, key, timestamp, revenue=None, value=None, tags=None):
self.entity_id = entity_id
self.uuid = uuid
self.key = key
self.timestamp = timestamp
self.revenue = revenue
self.value = value
self.tags = tags


class Visitor(object):
""" Class representing Visitor. """

def __init__(self, snapshots, attributes, visitor_id):
self.snapshots = snapshots
self.attributes = attributes
self.visitor_id = visitor_id


class VisitorAttribute(object):
""" Class representing Visitor Attribute. """

def __init__(self, entity_id, key, attribute_type, value):
self.entity_id = entity_id
self.key = key
self.type = attribute_type
self.value = value
67 changes: 67 additions & 0 deletions optimizely/event/user_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2019 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import time
import uuid

from optimizely import version

CLIENT_NAME = 'python-sdk'


class UserEvent(object):
""" Class respresenting User Event. """

def __init__(self, event_context, user_id, visitor_attributes, bot_filtering=None):
self.event_context = event_context
self.user_id = user_id
self.visitor_attributes = visitor_attributes
self.bot_filtering = bot_filtering
self.uuid = self._get_uuid()
self.timestamp = self._get_time()

def _get_time(self):
return int(round(time.time() * 1000))

def _get_uuid(self):
return str(uuid.uuid4())


class ImpressionEvent(UserEvent):
""" Class representing Impression Event. """

def __init__(self, event_context, user_id, experiment, visitor_attributes, variation, bot_filtering=None):
super(ImpressionEvent, self).__init__(event_context, user_id, visitor_attributes, bot_filtering)
self.experiment = experiment
self.variation = variation


class ConversionEvent(UserEvent):
""" Class representing Conversion Event. """

def __init__(self, event_context, event, user_id, visitor_attributes, event_tags, bot_filtering=None):
super(ConversionEvent, self).__init__(event_context, user_id, visitor_attributes, bot_filtering)
self.event = event
self.event_tags = event_tags


class EventContext(object):
""" Class respresenting User Event Context. """

def __init__(self, account_id, project_id, revision, anonymize_ip):
self.account_id = account_id
self.project_id = project_id
self.revision = revision
self.client_name = CLIENT_NAME
self.client_version = version.__version__
self.anonymize_ip = anonymize_ip
120 changes: 120 additions & 0 deletions tests/test_event_payload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Copyright 2019, 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from optimizely import version
from optimizely.event import payload
from . import base


class EventPayloadTest(base.BaseTest):

def test_impression_event_equals_serialized_payload(self):
expected_params = {
'account_id': '12001',
'project_id': '111001',
'visitors': [{
'visitor_id': 'test_user',
'attributes': [{
'type': 'custom',
'value': 'test_value',
'entity_id': '111094',
'key': 'test_attribute'
}],
'snapshots': [{
'decisions': [{
'variation_id': '111129',
'experiment_id': '111127',
'campaign_id': '111182'
}],
'events': [{
'timestamp': 42123,
'entity_id': '111182',
'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c',
'key': 'campaign_activated'
}]
}]
}],
'client_name': 'python-sdk',
'client_version': version.__version__,
'enrich_decisions': True,
'anonymize_ip': False,
'revision': '42'
}

batch = payload.EventBatch('12001', '111001', '42', 'python-sdk', version.__version__,
False, True)
visitor_attr = payload.VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value')
event = payload.SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated',
42123)
event_decision = payload.Decision('111182', '111127', '111129')

snapshots = payload.Snapshot([event], [event_decision])
user = payload.Visitor([snapshots], [visitor_attr], 'test_user')

batch.visitors = [user]

self.assertEqual(batch, expected_params)

def test_conversion_event_equals_serialized_payload(self):
expected_params = {
'account_id': '12001',
'project_id': '111001',
'visitors': [{
'visitor_id': 'test_user',
'attributes': [{
'type': 'custom',
'value': 'test_value',
'entity_id': '111094',
'key': 'test_attribute'
}, {
'type': 'custom',
'value': 'test_value2',
'entity_id': '111095',
'key': 'test_attribute2'
}],
'snapshots': [{
'events': [{
'timestamp': 42123,
'entity_id': '111182',
'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c',
'key': 'campaign_activated',
'revenue': 4200,
'tags': {
'non-revenue': 'abc',
'revenue': 4200,
'value': 1.234
},
'value': 1.234
}]
}]
}],
'client_name': 'python-sdk',
'client_version': version.__version__,
'enrich_decisions': True,
'anonymize_ip': False,
'revision': '42'
}

batch = payload.EventBatch('12001', '111001', '42', 'python-sdk', version.__version__,
False, True)
visitor_attr_1 = payload.VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value')
visitor_attr_2 = payload.VisitorAttribute('111095', 'test_attribute2', 'custom', 'test_value2')
event = payload.SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated',
42123, 4200, 1.234, {'revenue': 4200, 'value': 1.234, 'non-revenue': 'abc'})

snapshots = payload.Snapshot([event])
user = payload.Visitor([snapshots], [visitor_attr_1, visitor_attr_2], 'test_user')

batch.visitors = [user]

self.assertEqual(batch, expected_params)

0 comments on commit 846c91e

Please sign in to comment.