Skip to content

Commit 96b4d55

Browse files
msohailhussainaliabbasrizvi
authored andcommitted
feat(eventprocessor): Datamodel for event processor (#192)
1 parent f5b0d0c commit 96b4d55

File tree

4 files changed

+293
-0
lines changed

4 files changed

+293
-0
lines changed

Diff for: optimizely/event/__init__.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright 2019, Optimizely
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.

Diff for: optimizely/event/payload.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Copyright 2019 Optimizely
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
import json
15+
16+
17+
class EventBatch(object):
18+
""" Class respresenting Event Batch. """
19+
20+
def __init__(self, account_id, project_id, revision, client_name, client_version,
21+
anonymize_ip, enrich_decisions=True, visitors=None):
22+
self.account_id = account_id
23+
self.project_id = project_id
24+
self.revision = revision
25+
self.client_name = client_name
26+
self.client_version = client_version
27+
self.anonymize_ip = anonymize_ip
28+
self.enrich_decisions = enrich_decisions
29+
self.visitors = visitors or []
30+
31+
def __eq__(self, other):
32+
batch_obj = json.loads(json.dumps(self.__dict__, default=lambda o: o.__dict__),
33+
object_pairs_hook=self._dict_clean)
34+
return batch_obj == other
35+
36+
def _dict_clean(self, obj):
37+
""" Helper method to remove keys from dictionary with None values. """
38+
39+
result = {}
40+
for k, v in obj:
41+
if v is None and k in ['revenue', 'value', 'tags', 'decisions']:
42+
continue
43+
else:
44+
result[k] = v
45+
return result
46+
47+
48+
class Decision(object):
49+
""" Class respresenting Decision. """
50+
51+
def __init__(self, campaign_id, experiment_id, variation_id):
52+
self.campaign_id = campaign_id
53+
self.experiment_id = experiment_id
54+
self.variation_id = variation_id
55+
56+
57+
class Snapshot(object):
58+
""" Class representing Snapshot. """
59+
60+
def __init__(self, events, decisions=None):
61+
self.events = events
62+
self.decisions = decisions
63+
64+
65+
class SnapshotEvent(object):
66+
""" Class representing Snapshot Event. """
67+
68+
def __init__(self, entity_id, uuid, key, timestamp, revenue=None, value=None, tags=None):
69+
self.entity_id = entity_id
70+
self.uuid = uuid
71+
self.key = key
72+
self.timestamp = timestamp
73+
self.revenue = revenue
74+
self.value = value
75+
self.tags = tags
76+
77+
78+
class Visitor(object):
79+
""" Class representing Visitor. """
80+
81+
def __init__(self, snapshots, attributes, visitor_id):
82+
self.snapshots = snapshots
83+
self.attributes = attributes
84+
self.visitor_id = visitor_id
85+
86+
87+
class VisitorAttribute(object):
88+
""" Class representing Visitor Attribute. """
89+
90+
def __init__(self, entity_id, key, attribute_type, value):
91+
self.entity_id = entity_id
92+
self.key = key
93+
self.type = attribute_type
94+
self.value = value

Diff for: optimizely/event/user_event.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright 2019 Optimizely
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
import time
15+
import uuid
16+
17+
from optimizely import version
18+
19+
CLIENT_NAME = 'python-sdk'
20+
21+
22+
class UserEvent(object):
23+
""" Class respresenting User Event. """
24+
25+
def __init__(self, event_context, user_id, visitor_attributes, bot_filtering=None):
26+
self.event_context = event_context
27+
self.user_id = user_id
28+
self.visitor_attributes = visitor_attributes
29+
self.bot_filtering = bot_filtering
30+
self.uuid = self._get_uuid()
31+
self.timestamp = self._get_time()
32+
33+
def _get_time(self):
34+
return int(round(time.time() * 1000))
35+
36+
def _get_uuid(self):
37+
return str(uuid.uuid4())
38+
39+
40+
class ImpressionEvent(UserEvent):
41+
""" Class representing Impression Event. """
42+
43+
def __init__(self, event_context, user_id, experiment, visitor_attributes, variation, bot_filtering=None):
44+
super(ImpressionEvent, self).__init__(event_context, user_id, visitor_attributes, bot_filtering)
45+
self.experiment = experiment
46+
self.variation = variation
47+
48+
49+
class ConversionEvent(UserEvent):
50+
""" Class representing Conversion Event. """
51+
52+
def __init__(self, event_context, event, user_id, visitor_attributes, event_tags, bot_filtering=None):
53+
super(ConversionEvent, self).__init__(event_context, user_id, visitor_attributes, bot_filtering)
54+
self.event = event
55+
self.event_tags = event_tags
56+
57+
58+
class EventContext(object):
59+
""" Class respresenting User Event Context. """
60+
61+
def __init__(self, account_id, project_id, revision, anonymize_ip):
62+
self.account_id = account_id
63+
self.project_id = project_id
64+
self.revision = revision
65+
self.client_name = CLIENT_NAME
66+
self.client_version = version.__version__
67+
self.anonymize_ip = anonymize_ip

Diff for: tests/test_event_payload.py

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Copyright 2019, Optimizely
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
from optimizely import version
15+
from optimizely.event import payload
16+
from . import base
17+
18+
19+
class EventPayloadTest(base.BaseTest):
20+
21+
def test_impression_event_equals_serialized_payload(self):
22+
expected_params = {
23+
'account_id': '12001',
24+
'project_id': '111001',
25+
'visitors': [{
26+
'visitor_id': 'test_user',
27+
'attributes': [{
28+
'type': 'custom',
29+
'value': 'test_value',
30+
'entity_id': '111094',
31+
'key': 'test_attribute'
32+
}],
33+
'snapshots': [{
34+
'decisions': [{
35+
'variation_id': '111129',
36+
'experiment_id': '111127',
37+
'campaign_id': '111182'
38+
}],
39+
'events': [{
40+
'timestamp': 42123,
41+
'entity_id': '111182',
42+
'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c',
43+
'key': 'campaign_activated'
44+
}]
45+
}]
46+
}],
47+
'client_name': 'python-sdk',
48+
'client_version': version.__version__,
49+
'enrich_decisions': True,
50+
'anonymize_ip': False,
51+
'revision': '42'
52+
}
53+
54+
batch = payload.EventBatch('12001', '111001', '42', 'python-sdk', version.__version__,
55+
False, True)
56+
visitor_attr = payload.VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value')
57+
event = payload.SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated',
58+
42123)
59+
event_decision = payload.Decision('111182', '111127', '111129')
60+
61+
snapshots = payload.Snapshot([event], [event_decision])
62+
user = payload.Visitor([snapshots], [visitor_attr], 'test_user')
63+
64+
batch.visitors = [user]
65+
66+
self.assertEqual(batch, expected_params)
67+
68+
def test_conversion_event_equals_serialized_payload(self):
69+
expected_params = {
70+
'account_id': '12001',
71+
'project_id': '111001',
72+
'visitors': [{
73+
'visitor_id': 'test_user',
74+
'attributes': [{
75+
'type': 'custom',
76+
'value': 'test_value',
77+
'entity_id': '111094',
78+
'key': 'test_attribute'
79+
}, {
80+
'type': 'custom',
81+
'value': 'test_value2',
82+
'entity_id': '111095',
83+
'key': 'test_attribute2'
84+
}],
85+
'snapshots': [{
86+
'events': [{
87+
'timestamp': 42123,
88+
'entity_id': '111182',
89+
'uuid': 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c',
90+
'key': 'campaign_activated',
91+
'revenue': 4200,
92+
'tags': {
93+
'non-revenue': 'abc',
94+
'revenue': 4200,
95+
'value': 1.234
96+
},
97+
'value': 1.234
98+
}]
99+
}]
100+
}],
101+
'client_name': 'python-sdk',
102+
'client_version': version.__version__,
103+
'enrich_decisions': True,
104+
'anonymize_ip': False,
105+
'revision': '42'
106+
}
107+
108+
batch = payload.EventBatch('12001', '111001', '42', 'python-sdk', version.__version__,
109+
False, True)
110+
visitor_attr_1 = payload.VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value')
111+
visitor_attr_2 = payload.VisitorAttribute('111095', 'test_attribute2', 'custom', 'test_value2')
112+
event = payload.SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated',
113+
42123, 4200, 1.234, {'revenue': 4200, 'value': 1.234, 'non-revenue': 'abc'})
114+
115+
snapshots = payload.Snapshot([event])
116+
user = payload.Visitor([snapshots], [visitor_attr_1, visitor_attr_2], 'test_user')
117+
118+
batch.visitors = [user]
119+
120+
self.assertEqual(batch, expected_params)

0 commit comments

Comments
 (0)