From 232f0a059b365350f913caffa78df44b2b399d0b Mon Sep 17 00:00:00 2001 From: "mjamal@folio3.com" Date: Fri, 19 Jul 2019 12:16:21 +0500 Subject: [PATCH 1/6] feat: Add event_batch datamodels. --- optimizely/event/__init__.py | 12 ++ optimizely/event/entity/__init__.py | 12 ++ optimizely/event/entity/conversion_event.py | 25 +++ optimizely/event/entity/decision.py | 19 +++ optimizely/event/entity/event_batch.py | 25 +++ optimizely/event/entity/event_context.py | 27 ++++ optimizely/event/entity/impression_event.py | 25 +++ optimizely/event/entity/snapshot.py | 18 +++ optimizely/event/entity/snapshot_event.py | 25 +++ optimizely/event/entity/user_event.py | 29 ++++ optimizely/event/entity/visitor.py | 19 +++ optimizely/event/entity/visitor_attribute.py | 20 +++ tests/test_event_entities.py | 162 +++++++++++++++++++ 13 files changed, 418 insertions(+) create mode 100644 optimizely/event/__init__.py create mode 100644 optimizely/event/entity/__init__.py create mode 100644 optimizely/event/entity/conversion_event.py create mode 100644 optimizely/event/entity/decision.py create mode 100644 optimizely/event/entity/event_batch.py create mode 100644 optimizely/event/entity/event_context.py create mode 100644 optimizely/event/entity/impression_event.py create mode 100644 optimizely/event/entity/snapshot.py create mode 100644 optimizely/event/entity/snapshot_event.py create mode 100644 optimizely/event/entity/user_event.py create mode 100644 optimizely/event/entity/visitor.py create mode 100644 optimizely/event/entity/visitor_attribute.py create mode 100644 tests/test_event_entities.py diff --git a/optimizely/event/__init__.py b/optimizely/event/__init__.py new file mode 100644 index 00000000..d6094e5a --- /dev/null +++ b/optimizely/event/__init__.py @@ -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. diff --git a/optimizely/event/entity/__init__.py b/optimizely/event/entity/__init__.py new file mode 100644 index 00000000..d6094e5a --- /dev/null +++ b/optimizely/event/entity/__init__.py @@ -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. diff --git a/optimizely/event/entity/conversion_event.py b/optimizely/event/entity/conversion_event.py new file mode 100644 index 00000000..e6cd746d --- /dev/null +++ b/optimizely/event/entity/conversion_event.py @@ -0,0 +1,25 @@ +# 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 .user_event import UserEvent + + +class ConversionEvent(UserEvent): + """ Class representing Conversion Event. """ + + def __init__(self, event_context, event, user_id, visitor_attributes, event_tags, bot_filtering=None): + self.event_context = event_context + self.event = event + self.user_id = user_id + self.visitor_attributes = visitor_attributes + self.event_tags = event_tags + self.bot_filtering = bot_filtering diff --git a/optimizely/event/entity/decision.py b/optimizely/event/entity/decision.py new file mode 100644 index 00000000..60b965dc --- /dev/null +++ b/optimizely/event/entity/decision.py @@ -0,0 +1,19 @@ +# 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. + + +class Decision(object): + def __init__(self, compaign_id, experiment_id, variation_id): + self.campaign_id = compaign_id + self.experiment_id = experiment_id + self.variation_id = variation_id diff --git a/optimizely/event/entity/event_batch.py b/optimizely/event/entity/event_batch.py new file mode 100644 index 00000000..4bdf008c --- /dev/null +++ b/optimizely/event/entity/event_batch.py @@ -0,0 +1,25 @@ +# 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. + + +class EventBatch(object): + def __init__(self, account_id, project_id, revision, client_name, client_version, + anonymize_ip, enrich_decisions, 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 diff --git a/optimizely/event/entity/event_context.py b/optimizely/event/entity/event_context.py new file mode 100644 index 00000000..5d7efcc5 --- /dev/null +++ b/optimizely/event/entity/event_context.py @@ -0,0 +1,27 @@ +# 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 .. import version + +SDK_VERSION = 'python-sdk' + + +class EventContext(object): + """ Class respresenting 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 = SDK_VERSION + self.client_version = version.__version__ + self.anonymize_ip = anonymize_ip diff --git a/optimizely/event/entity/impression_event.py b/optimizely/event/entity/impression_event.py new file mode 100644 index 00000000..044fb163 --- /dev/null +++ b/optimizely/event/entity/impression_event.py @@ -0,0 +1,25 @@ +# 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 .user_event import UserEvent + + +class ImpressionEvent(UserEvent): + """ Class representing Impression Event. """ + + def __init__(self, event_context, user_id, experiment, visitor_attributes, variation, bot_filtering=None): + self.event_context = event_context + self.user_id = user_id + self.experiment = experiment + self.visitor_attributes = visitor_attributes + self.variation = variation + self.bot_filtering = bot_filtering diff --git a/optimizely/event/entity/snapshot.py b/optimizely/event/entity/snapshot.py new file mode 100644 index 00000000..726eccdb --- /dev/null +++ b/optimizely/event/entity/snapshot.py @@ -0,0 +1,18 @@ +# 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. + + +class Snapshot(object): + def __init__(self, events, decisions=None): + self.events = events + self.decisions = decisions diff --git a/optimizely/event/entity/snapshot_event.py b/optimizely/event/entity/snapshot_event.py new file mode 100644 index 00000000..ef2bdf8a --- /dev/null +++ b/optimizely/event/entity/snapshot_event.py @@ -0,0 +1,25 @@ +# 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. + + +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 diff --git a/optimizely/event/entity/user_event.py b/optimizely/event/entity/user_event.py new file mode 100644 index 00000000..a6343d0d --- /dev/null +++ b/optimizely/event/entity/user_event.py @@ -0,0 +1,29 @@ +# 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 + + +class UserEvent(object): + """ Class respresenting Event Context. """ + + def __init__(self, event_context): + self.event_context = event_context + 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()) diff --git a/optimizely/event/entity/visitor.py b/optimizely/event/entity/visitor.py new file mode 100644 index 00000000..d9886b0e --- /dev/null +++ b/optimizely/event/entity/visitor.py @@ -0,0 +1,19 @@ +# 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. + + +class Visitor(object): + def __init__(self, snapshots, attributes, visitor_id): + self.snapshots = snapshots + self.attributes = attributes + self.visitor_id = visitor_id diff --git a/optimizely/event/entity/visitor_attribute.py b/optimizely/event/entity/visitor_attribute.py new file mode 100644 index 00000000..cafe58c5 --- /dev/null +++ b/optimizely/event/entity/visitor_attribute.py @@ -0,0 +1,20 @@ +# 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. + + +class VisitorAttribute(object): + def __init__(self, entity_id, key, event_type, value): + self.entity_id = entity_id + self.key = key + self.type = event_type + self.value = value diff --git a/tests/test_event_entities.py b/tests/test_event_entities.py new file mode 100644 index 00000000..8b12d461 --- /dev/null +++ b/tests/test_event_entities.py @@ -0,0 +1,162 @@ +# 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 + +from operator import itemgetter + +from optimizely import version +from optimizely.event.entity import event_batch +from optimizely.event.entity import visitor_attribute +from optimizely.event.entity import snapshot_event +from optimizely.event.entity import visitor +from optimizely.event.entity import decision +from optimizely.event.entity import snapshot +from . import base + + +class EventEntitiesTest(base.BaseTest): + def _validate_event_object(self, expected_params, event_obj): + """ Helper method to validate properties of the event object. """ + + expected_params['visitors'][0]['attributes'] = \ + sorted(expected_params['visitors'][0]['attributes'], key=itemgetter('key')) + event_obj['visitors'][0]['attributes'] = \ + sorted(event_obj['visitors'][0]['attributes'], key=itemgetter('key')) + self.assertEqual(expected_params, event_obj) + + 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']: + continue + else: + result[k] = v + return result + + def TestImpressionEventEqualsSerializedPayload(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 = event_batch.EventBatch("12001", "111001", "42", "python-sdk", version.__version__, + False, True) + visitor_attr = visitor_attribute.VisitorAttribute("111094", "test_attribute", "custom", "test_value") + event = snapshot_event.SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", + 42123) + event_decision = decision.Decision("111182", "111127", "111129") + + snapshots = snapshot.Snapshot([event], [event_decision]) + user = visitor.Visitor([snapshots], [visitor_attr], "test_user") + + batch.visitors = [user] + + self.maxDiff = None + self._validate_event_object(expected_params, + json.loads( + json.dumps(batch.__dict__, default=lambda o: o.__dict__), + object_pairs_hook=self.dict_clean + )) + + def TestConversionEventEqualsSerializedPayload(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': [{ + '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', + '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 = event_batch.EventBatch("12001", "111001", "42", "python-sdk", version.__version__, + False, True) + visitor_attr_1 = visitor_attribute.VisitorAttribute("111094", "test_attribute", "custom", "test_value") + visitor_attr_2 = visitor_attribute.VisitorAttribute("111095", "test_attribute2", "custom", "test_value2") + event = snapshot_event.SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", + 42123, 4200, 1.234, {'revenue': 4200, 'value': 1.234, 'non-revenue': 'abc'}) + event_decision = decision.Decision("111182", "111127", "111129") + + snapshots = snapshot.Snapshot([event], [event_decision]) + user = visitor.Visitor([snapshots], [visitor_attr_1, visitor_attr_2], "test_user") + + batch.visitors = [user] + + self._validate_event_object(expected_params, + json.loads( + json.dumps(batch.__dict__, default=lambda o: o.__dict__), + object_pairs_hook=self.dict_clean + )) From 232093950b5bea2182d35baf7d8407cdf0d2e0ba Mon Sep 17 00:00:00 2001 From: "mjamal@folio3.com" Date: Mon, 22 Jul 2019 16:59:03 +0500 Subject: [PATCH 2/6] fix: unit test fixes. --- tests/test_event_entities.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/test_event_entities.py b/tests/test_event_entities.py index 8b12d461..040383cb 100644 --- a/tests/test_event_entities.py +++ b/tests/test_event_entities.py @@ -39,13 +39,13 @@ def dict_clean(self, obj): result = {} for k, v in obj: - if v is None and k in ['revenue', 'value', 'tags']: + if v is None and k in ['revenue', 'value', 'tags', 'decisions']: continue else: result[k] = v return result - def TestImpressionEventEqualsSerializedPayload(self): + def test_impression_event_equals_serialized_payload(self): expected_params = { 'account_id': '12001', 'project_id': '111001', @@ -79,10 +79,10 @@ def TestImpressionEventEqualsSerializedPayload(self): } batch = event_batch.EventBatch("12001", "111001", "42", "python-sdk", version.__version__, - False, True) + False, True) visitor_attr = visitor_attribute.VisitorAttribute("111094", "test_attribute", "custom", "test_value") event = snapshot_event.SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", - 42123) + 42123) event_decision = decision.Decision("111182", "111127", "111129") snapshots = snapshot.Snapshot([event], [event_decision]) @@ -97,7 +97,7 @@ def TestImpressionEventEqualsSerializedPayload(self): object_pairs_hook=self.dict_clean )) - def TestConversionEventEqualsSerializedPayload(self): + def test_conversion_event_equals_serialized_payload(self): expected_params = { 'account_id': '12001', 'project_id': '111001', @@ -115,11 +115,6 @@ def TestConversionEventEqualsSerializedPayload(self): 'key': 'test_attribute2' }], 'snapshots': [{ - 'decisions': [{ - 'variation_id': '111129', - 'experiment_id': '111127', - 'campaign_id': '111182' - }], 'events': [{ 'timestamp': 42123, 'entity_id': '111182', @@ -148,9 +143,8 @@ def TestConversionEventEqualsSerializedPayload(self): visitor_attr_2 = visitor_attribute.VisitorAttribute("111095", "test_attribute2", "custom", "test_value2") event = snapshot_event.SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", 42123, 4200, 1.234, {'revenue': 4200, 'value': 1.234, 'non-revenue': 'abc'}) - event_decision = decision.Decision("111182", "111127", "111129") - snapshots = snapshot.Snapshot([event], [event_decision]) + snapshots = snapshot.Snapshot([event]) user = visitor.Visitor([snapshots], [visitor_attr_1, visitor_attr_2], "test_user") batch.visitors = [user] From c3c9d46dd5ddb51ee2ffeeae268f0865dd517341 Mon Sep 17 00:00:00 2001 From: Sohail Hussain Date: Mon, 19 Aug 2019 23:47:41 -0700 Subject: [PATCH 3/6] Addressed feedback. Restructured classes. --- optimizely/event/entity/__init__.py | 12 --- optimizely/event/entity/conversion_event.py | 25 ------ optimizely/event/entity/decision.py | 19 ----- optimizely/event/entity/event_batch.py | 25 ------ optimizely/event/entity/event_context.py | 27 ------- optimizely/event/entity/impression_event.py | 25 ------ optimizely/event/entity/snapshot.py | 18 ----- optimizely/event/entity/snapshot_event.py | 25 ------ optimizely/event/entity/user_event.py | 29 ------- optimizely/event/entity/visitor.py | 19 ----- optimizely/event/entity/visitor_attribute.py | 20 ----- optimizely/event/event_payload.py | 76 +++++++++++++++++++ optimizely/event/user_event.py | 72 ++++++++++++++++++ ...vent_entities.py => test_event_payload.py} | 41 +++++----- 14 files changed, 166 insertions(+), 267 deletions(-) delete mode 100644 optimizely/event/entity/__init__.py delete mode 100644 optimizely/event/entity/conversion_event.py delete mode 100644 optimizely/event/entity/decision.py delete mode 100644 optimizely/event/entity/event_batch.py delete mode 100644 optimizely/event/entity/event_context.py delete mode 100644 optimizely/event/entity/impression_event.py delete mode 100644 optimizely/event/entity/snapshot.py delete mode 100644 optimizely/event/entity/snapshot_event.py delete mode 100644 optimizely/event/entity/user_event.py delete mode 100644 optimizely/event/entity/visitor.py delete mode 100644 optimizely/event/entity/visitor_attribute.py create mode 100644 optimizely/event/event_payload.py create mode 100644 optimizely/event/user_event.py rename tests/{test_event_entities.py => test_event_payload.py} (72%) diff --git a/optimizely/event/entity/__init__.py b/optimizely/event/entity/__init__.py deleted file mode 100644 index d6094e5a..00000000 --- a/optimizely/event/entity/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# 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. diff --git a/optimizely/event/entity/conversion_event.py b/optimizely/event/entity/conversion_event.py deleted file mode 100644 index e6cd746d..00000000 --- a/optimizely/event/entity/conversion_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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 .user_event import UserEvent - - -class ConversionEvent(UserEvent): - """ Class representing Conversion Event. """ - - def __init__(self, event_context, event, user_id, visitor_attributes, event_tags, bot_filtering=None): - self.event_context = event_context - self.event = event - self.user_id = user_id - self.visitor_attributes = visitor_attributes - self.event_tags = event_tags - self.bot_filtering = bot_filtering diff --git a/optimizely/event/entity/decision.py b/optimizely/event/entity/decision.py deleted file mode 100644 index 60b965dc..00000000 --- a/optimizely/event/entity/decision.py +++ /dev/null @@ -1,19 +0,0 @@ -# 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. - - -class Decision(object): - def __init__(self, compaign_id, experiment_id, variation_id): - self.campaign_id = compaign_id - self.experiment_id = experiment_id - self.variation_id = variation_id diff --git a/optimizely/event/entity/event_batch.py b/optimizely/event/entity/event_batch.py deleted file mode 100644 index 4bdf008c..00000000 --- a/optimizely/event/entity/event_batch.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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. - - -class EventBatch(object): - def __init__(self, account_id, project_id, revision, client_name, client_version, - anonymize_ip, enrich_decisions, 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 diff --git a/optimizely/event/entity/event_context.py b/optimizely/event/entity/event_context.py deleted file mode 100644 index 5d7efcc5..00000000 --- a/optimizely/event/entity/event_context.py +++ /dev/null @@ -1,27 +0,0 @@ -# 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 .. import version - -SDK_VERSION = 'python-sdk' - - -class EventContext(object): - """ Class respresenting 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 = SDK_VERSION - self.client_version = version.__version__ - self.anonymize_ip = anonymize_ip diff --git a/optimizely/event/entity/impression_event.py b/optimizely/event/entity/impression_event.py deleted file mode 100644 index 044fb163..00000000 --- a/optimizely/event/entity/impression_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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 .user_event import UserEvent - - -class ImpressionEvent(UserEvent): - """ Class representing Impression Event. """ - - def __init__(self, event_context, user_id, experiment, visitor_attributes, variation, bot_filtering=None): - self.event_context = event_context - self.user_id = user_id - self.experiment = experiment - self.visitor_attributes = visitor_attributes - self.variation = variation - self.bot_filtering = bot_filtering diff --git a/optimizely/event/entity/snapshot.py b/optimizely/event/entity/snapshot.py deleted file mode 100644 index 726eccdb..00000000 --- a/optimizely/event/entity/snapshot.py +++ /dev/null @@ -1,18 +0,0 @@ -# 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. - - -class Snapshot(object): - def __init__(self, events, decisions=None): - self.events = events - self.decisions = decisions diff --git a/optimizely/event/entity/snapshot_event.py b/optimizely/event/entity/snapshot_event.py deleted file mode 100644 index ef2bdf8a..00000000 --- a/optimizely/event/entity/snapshot_event.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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. - - -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 diff --git a/optimizely/event/entity/user_event.py b/optimizely/event/entity/user_event.py deleted file mode 100644 index a6343d0d..00000000 --- a/optimizely/event/entity/user_event.py +++ /dev/null @@ -1,29 +0,0 @@ -# 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 - - -class UserEvent(object): - """ Class respresenting Event Context. """ - - def __init__(self, event_context): - self.event_context = event_context - 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()) diff --git a/optimizely/event/entity/visitor.py b/optimizely/event/entity/visitor.py deleted file mode 100644 index d9886b0e..00000000 --- a/optimizely/event/entity/visitor.py +++ /dev/null @@ -1,19 +0,0 @@ -# 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. - - -class Visitor(object): - def __init__(self, snapshots, attributes, visitor_id): - self.snapshots = snapshots - self.attributes = attributes - self.visitor_id = visitor_id diff --git a/optimizely/event/entity/visitor_attribute.py b/optimizely/event/entity/visitor_attribute.py deleted file mode 100644 index cafe58c5..00000000 --- a/optimizely/event/entity/visitor_attribute.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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. - - -class VisitorAttribute(object): - def __init__(self, entity_id, key, event_type, value): - self.entity_id = entity_id - self.key = key - self.type = event_type - self.value = value diff --git a/optimizely/event/event_payload.py b/optimizely/event/event_payload.py new file mode 100644 index 00000000..92fe80c6 --- /dev/null +++ b/optimizely/event/event_payload.py @@ -0,0 +1,76 @@ +# 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. + + +class EventBatch(object): + """ Class respresenting Event Batch. """ + + def __init__(self, account_id, project_id, revision, client_name, client_version, + anonymize_ip, enrich_decisions, 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 + + +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, event_type, value): + self.entity_id = entity_id + self.key = key + self.type = event_type + self.value = value diff --git a/optimizely/event/user_event.py b/optimizely/event/user_event.py new file mode 100644 index 00000000..887c0f57 --- /dev/null +++ b/optimizely/event/user_event.py @@ -0,0 +1,72 @@ +# 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 + +SDK_TYPE = 'python-sdk' + + +class UserEvent(object): + """ Class respresenting User Event. """ + + def __init__(self, event_context): + self.event_context = event_context + 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) + self.event_context = event_context + self.user_id = user_id + self.experiment = experiment + self.visitor_attributes = visitor_attributes + self.variation = variation + self.bot_filtering = bot_filtering + + +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) + self.event_context = event_context + self.event = event + self.user_id = user_id + self.visitor_attributes = visitor_attributes + self.event_tags = event_tags + self.bot_filtering = bot_filtering + + +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 = SDK_TYPE + self.client_version = version.__version__ + self.anonymize_ip = anonymize_ip diff --git a/tests/test_event_entities.py b/tests/test_event_payload.py similarity index 72% rename from tests/test_event_entities.py rename to tests/test_event_payload.py index 040383cb..62d5bb40 100644 --- a/tests/test_event_entities.py +++ b/tests/test_event_payload.py @@ -10,21 +10,16 @@ # 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 +import json from operator import itemgetter from optimizely import version -from optimizely.event.entity import event_batch -from optimizely.event.entity import visitor_attribute -from optimizely.event.entity import snapshot_event -from optimizely.event.entity import visitor -from optimizely.event.entity import decision -from optimizely.event.entity import snapshot +from optimizely.event.event_payload import Decision, EventBatch, Snapshot, SnapshotEvent, Visitor, VisitorAttribute from . import base -class EventEntitiesTest(base.BaseTest): +class EventPayloadTest(base.BaseTest): def _validate_event_object(self, expected_params, event_obj): """ Helper method to validate properties of the event object. """ @@ -34,7 +29,7 @@ def _validate_event_object(self, expected_params, event_obj): sorted(event_obj['visitors'][0]['attributes'], key=itemgetter('key')) self.assertEqual(expected_params, event_obj) - def dict_clean(self, obj): + def _dict_clean(self, obj): """ Helper method to remove keys from dictionary with None values. """ result = {} @@ -78,15 +73,15 @@ def test_impression_event_equals_serialized_payload(self): 'revision': '42' } - batch = event_batch.EventBatch("12001", "111001", "42", "python-sdk", version.__version__, + batch = EventBatch("12001", "111001", "42", "python-sdk", version.__version__, False, True) - visitor_attr = visitor_attribute.VisitorAttribute("111094", "test_attribute", "custom", "test_value") - event = snapshot_event.SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", + visitor_attr = VisitorAttribute("111094", "test_attribute", "custom", "test_value") + event = SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", 42123) - event_decision = decision.Decision("111182", "111127", "111129") + event_decision = Decision("111182", "111127", "111129") - snapshots = snapshot.Snapshot([event], [event_decision]) - user = visitor.Visitor([snapshots], [visitor_attr], "test_user") + snapshots = Snapshot([event], [event_decision]) + user = Visitor([snapshots], [visitor_attr], "test_user") batch.visitors = [user] @@ -94,7 +89,7 @@ def test_impression_event_equals_serialized_payload(self): self._validate_event_object(expected_params, json.loads( json.dumps(batch.__dict__, default=lambda o: o.__dict__), - object_pairs_hook=self.dict_clean + object_pairs_hook=self._dict_clean )) def test_conversion_event_equals_serialized_payload(self): @@ -137,20 +132,20 @@ def test_conversion_event_equals_serialized_payload(self): 'revision': '42' } - batch = event_batch.EventBatch("12001", "111001", "42", "python-sdk", version.__version__, + batch = EventBatch("12001", "111001", "42", "python-sdk", version.__version__, False, True) - visitor_attr_1 = visitor_attribute.VisitorAttribute("111094", "test_attribute", "custom", "test_value") - visitor_attr_2 = visitor_attribute.VisitorAttribute("111095", "test_attribute2", "custom", "test_value2") - event = snapshot_event.SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", + visitor_attr_1 = VisitorAttribute("111094", "test_attribute", "custom", "test_value") + visitor_attr_2 = VisitorAttribute("111095", "test_attribute2", "custom", "test_value2") + event = SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", 42123, 4200, 1.234, {'revenue': 4200, 'value': 1.234, 'non-revenue': 'abc'}) - snapshots = snapshot.Snapshot([event]) - user = visitor.Visitor([snapshots], [visitor_attr_1, visitor_attr_2], "test_user") + snapshots = Snapshot([event]) + user = Visitor([snapshots], [visitor_attr_1, visitor_attr_2], "test_user") batch.visitors = [user] self._validate_event_object(expected_params, json.loads( json.dumps(batch.__dict__, default=lambda o: o.__dict__), - object_pairs_hook=self.dict_clean + object_pairs_hook=self._dict_clean )) From 23ab6ceaa0c5cec33354d0a5bbcd85ad351a6537 Mon Sep 17 00:00:00 2001 From: "mjamal@folio3.com" Date: Wed, 21 Aug 2019 16:58:12 +0500 Subject: [PATCH 4/6] fix: addressed more feedback --- .../event/{event_payload.py => payload.py} | 26 +++++++- optimizely/event/user_event.py | 4 +- tests/test_event_payload.py | 59 +++++-------------- 3 files changed, 40 insertions(+), 49 deletions(-) rename optimizely/event/{event_payload.py => payload.py} (77%) diff --git a/optimizely/event/event_payload.py b/optimizely/event/payload.py similarity index 77% rename from optimizely/event/event_payload.py rename to optimizely/event/payload.py index 92fe80c6..979474d3 100644 --- a/optimizely/event/event_payload.py +++ b/optimizely/event/payload.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json + class EventBatch(object): """ Class respresenting Event Batch. """ @@ -26,6 +28,26 @@ def __init__(self, account_id, project_id, revision, client_name, client_version self.enrich_decisions = enrich_decisions self.visitors = visitors + def __eq__(self, other): + batch_obj = json.loads(json.dumps(self.__dict__, default=lambda o: o.__dict__), + object_pairs_hook=self._dict_clean) + + print(batch_obj) + print(other) + + 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. """ @@ -69,8 +91,8 @@ def __init__(self, snapshots, attributes, visitor_id): class VisitorAttribute(object): """ Class representing Visitor Attribute. """ - def __init__(self, entity_id, key, event_type, value): + def __init__(self, entity_id, key, attribute_type, value): self.entity_id = entity_id self.key = key - self.type = event_type + self.type = attribute_type self.value = value diff --git a/optimizely/event/user_event.py b/optimizely/event/user_event.py index 887c0f57..b18c4ef5 100644 --- a/optimizely/event/user_event.py +++ b/optimizely/event/user_event.py @@ -16,7 +16,7 @@ from optimizely import version -SDK_TYPE = 'python-sdk' +CLIENT_NAME = 'python-sdk' class UserEvent(object): @@ -67,6 +67,6 @@ 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 = SDK_TYPE + self.client_name = CLIENT_NAME self.client_version = version.__version__ self.anonymize_ip = anonymize_ip diff --git a/tests/test_event_payload.py b/tests/test_event_payload.py index 62d5bb40..b4a0c866 100644 --- a/tests/test_event_payload.py +++ b/tests/test_event_payload.py @@ -11,34 +11,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json -from operator import itemgetter - from optimizely import version -from optimizely.event.event_payload import Decision, EventBatch, Snapshot, SnapshotEvent, Visitor, VisitorAttribute +from optimizely.event.payload import Decision, EventBatch, Snapshot, SnapshotEvent, Visitor, VisitorAttribute from . import base class EventPayloadTest(base.BaseTest): - def _validate_event_object(self, expected_params, event_obj): - """ Helper method to validate properties of the event object. """ - - expected_params['visitors'][0]['attributes'] = \ - sorted(expected_params['visitors'][0]['attributes'], key=itemgetter('key')) - event_obj['visitors'][0]['attributes'] = \ - sorted(event_obj['visitors'][0]['attributes'], key=itemgetter('key')) - self.assertEqual(expected_params, event_obj) - - 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 def test_impression_event_equals_serialized_payload(self): expected_params = { @@ -73,24 +51,19 @@ def test_impression_event_equals_serialized_payload(self): 'revision': '42' } - batch = EventBatch("12001", "111001", "42", "python-sdk", version.__version__, + batch = EventBatch('12001', '111001', '42', 'python-sdk', version.__version__, False, True) - visitor_attr = VisitorAttribute("111094", "test_attribute", "custom", "test_value") - event = SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", + visitor_attr = VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value') + event = SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated', 42123) - event_decision = Decision("111182", "111127", "111129") + event_decision = Decision('111182', '111127', '111129') snapshots = Snapshot([event], [event_decision]) - user = Visitor([snapshots], [visitor_attr], "test_user") + user = Visitor([snapshots], [visitor_attr], 'test_user') batch.visitors = [user] - self.maxDiff = None - self._validate_event_object(expected_params, - json.loads( - json.dumps(batch.__dict__, default=lambda o: o.__dict__), - object_pairs_hook=self._dict_clean - )) + self.assertEqual(batch, expected_params) def test_conversion_event_equals_serialized_payload(self): expected_params = { @@ -132,20 +105,16 @@ def test_conversion_event_equals_serialized_payload(self): 'revision': '42' } - batch = EventBatch("12001", "111001", "42", "python-sdk", version.__version__, - False, True) - visitor_attr_1 = VisitorAttribute("111094", "test_attribute", "custom", "test_value") - visitor_attr_2 = VisitorAttribute("111095", "test_attribute2", "custom", "test_value2") - event = SnapshotEvent("111182", "a68cf1ad-0393-4e18-af87-efe8f01a7c9c", "campaign_activated", + batch = EventBatch('12001', '111001', '42', 'python-sdk', version.__version__, + False, True) + visitor_attr_1 = VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value') + visitor_attr_2 = VisitorAttribute('111095', 'test_attribute2', 'custom', 'test_value2') + event = SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated', 42123, 4200, 1.234, {'revenue': 4200, 'value': 1.234, 'non-revenue': 'abc'}) snapshots = Snapshot([event]) - user = Visitor([snapshots], [visitor_attr_1, visitor_attr_2], "test_user") + user = Visitor([snapshots], [visitor_attr_1, visitor_attr_2], 'test_user') batch.visitors = [user] - self._validate_event_object(expected_params, - json.loads( - json.dumps(batch.__dict__, default=lambda o: o.__dict__), - object_pairs_hook=self._dict_clean - )) + self.assertEqual(batch, expected_params) From 6474e9871ceffe6c852acdd6a36ec7a7ad4b3fdb Mon Sep 17 00:00:00 2001 From: "FOLIO3PK\\muhammadnoman" Date: Wed, 21 Aug 2019 17:52:22 +0500 Subject: [PATCH 5/6] update: removed print statements. --- optimizely/event/payload.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/optimizely/event/payload.py b/optimizely/event/payload.py index 979474d3..fa145d31 100644 --- a/optimizely/event/payload.py +++ b/optimizely/event/payload.py @@ -31,10 +31,6 @@ def __init__(self, account_id, project_id, revision, client_name, client_version def __eq__(self, other): batch_obj = json.loads(json.dumps(self.__dict__, default=lambda o: o.__dict__), object_pairs_hook=self._dict_clean) - - print(batch_obj) - print(other) - return batch_obj == other def _dict_clean(self, obj): From 80b0963a260cc3886590c1fd1a58973df8645b9e Mon Sep 17 00:00:00 2001 From: "mjamal@folio3.com" Date: Wed, 28 Aug 2019 11:30:33 +0500 Subject: [PATCH 6/6] fix: addressed minor feedback. --- optimizely/event/payload.py | 4 ++-- optimizely/event/user_event.py | 17 ++++++----------- tests/test_event_payload.py | 26 +++++++++++++------------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/optimizely/event/payload.py b/optimizely/event/payload.py index fa145d31..e3dc8b6b 100644 --- a/optimizely/event/payload.py +++ b/optimizely/event/payload.py @@ -18,7 +18,7 @@ class EventBatch(object): """ Class respresenting Event Batch. """ def __init__(self, account_id, project_id, revision, client_name, client_version, - anonymize_ip, enrich_decisions, visitors=None): + anonymize_ip, enrich_decisions=True, visitors=None): self.account_id = account_id self.project_id = project_id self.revision = revision @@ -26,7 +26,7 @@ def __init__(self, account_id, project_id, revision, client_name, client_version self.client_version = client_version self.anonymize_ip = anonymize_ip self.enrich_decisions = enrich_decisions - self.visitors = visitors + self.visitors = visitors or [] def __eq__(self, other): batch_obj = json.loads(json.dumps(self.__dict__, default=lambda o: o.__dict__), diff --git a/optimizely/event/user_event.py b/optimizely/event/user_event.py index b18c4ef5..e64e6989 100644 --- a/optimizely/event/user_event.py +++ b/optimizely/event/user_event.py @@ -22,8 +22,11 @@ class UserEvent(object): """ Class respresenting User Event. """ - def __init__(self, event_context): + 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() @@ -38,26 +41,18 @@ 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) - self.event_context = event_context - self.user_id = user_id + super(ImpressionEvent, self).__init__(event_context, user_id, visitor_attributes, bot_filtering) self.experiment = experiment - self.visitor_attributes = visitor_attributes self.variation = variation - self.bot_filtering = bot_filtering 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) - self.event_context = event_context + super(ConversionEvent, self).__init__(event_context, user_id, visitor_attributes, bot_filtering) self.event = event - self.user_id = user_id - self.visitor_attributes = visitor_attributes self.event_tags = event_tags - self.bot_filtering = bot_filtering class EventContext(object): diff --git a/tests/test_event_payload.py b/tests/test_event_payload.py index b4a0c866..8e3e385b 100644 --- a/tests/test_event_payload.py +++ b/tests/test_event_payload.py @@ -12,7 +12,7 @@ # limitations under the License. from optimizely import version -from optimizely.event.payload import Decision, EventBatch, Snapshot, SnapshotEvent, Visitor, VisitorAttribute +from optimizely.event import payload from . import base @@ -51,15 +51,15 @@ def test_impression_event_equals_serialized_payload(self): 'revision': '42' } - batch = EventBatch('12001', '111001', '42', 'python-sdk', version.__version__, + batch = payload.EventBatch('12001', '111001', '42', 'python-sdk', version.__version__, False, True) - visitor_attr = VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value') - event = SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated', + visitor_attr = payload.VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value') + event = payload.SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated', 42123) - event_decision = Decision('111182', '111127', '111129') + event_decision = payload.Decision('111182', '111127', '111129') - snapshots = Snapshot([event], [event_decision]) - user = Visitor([snapshots], [visitor_attr], 'test_user') + snapshots = payload.Snapshot([event], [event_decision]) + user = payload.Visitor([snapshots], [visitor_attr], 'test_user') batch.visitors = [user] @@ -105,15 +105,15 @@ def test_conversion_event_equals_serialized_payload(self): 'revision': '42' } - batch = EventBatch('12001', '111001', '42', 'python-sdk', version.__version__, + batch = payload.EventBatch('12001', '111001', '42', 'python-sdk', version.__version__, False, True) - visitor_attr_1 = VisitorAttribute('111094', 'test_attribute', 'custom', 'test_value') - visitor_attr_2 = VisitorAttribute('111095', 'test_attribute2', 'custom', 'test_value2') - event = SnapshotEvent('111182', 'a68cf1ad-0393-4e18-af87-efe8f01a7c9c', 'campaign_activated', + 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 = Snapshot([event]) - user = Visitor([snapshots], [visitor_attr_1, visitor_attr_2], 'test_user') + snapshots = payload.Snapshot([event]) + user = payload.Visitor([snapshots], [visitor_attr_1, visitor_attr_2], 'test_user') batch.visitors = [user]