Skip to content

Commit

Permalink
feat: add library context identifier (#33)
Browse files Browse the repository at this point in the history
* feat: add library context identifier

* docs: add docstring for library_context

* feat: add library_context to BaseEvent constructor

* revert server host

* revert server host
  • Loading branch information
liuyang1520 committed Aug 19, 2022
1 parent d32204c commit d1c8f52
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 8 deletions.
2 changes: 1 addition & 1 deletion examples/flask_example/flaskapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def track_revenue(user_id):
@app.route("/flush")
def flush_event():
amp_client.flush()
return f"<p>All events flushed</p>"
return "<p>All events flushed</p>"


if __name__ == "__main__":
Expand Down
5 changes: 4 additions & 1 deletion src/amplitude/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Config:
storage_provider (amplitude.storage.StorageProvider, optional): Default to InMemoryStorageProvider.
Provide storage instance for events buffer.
plan (amplitude.event.Plan, optional): Tracking plan information. Default to None.
library_context (str, optional): Library context information. Default to None.
Properties:
options: A dictionary contains minimum id length information. None if min_id_length not set.
Expand All @@ -55,7 +56,8 @@ def __init__(self, api_key: str = None,
use_batch: bool = False,
server_url: Optional[str] = None,
storage_provider: StorageProvider = InMemoryStorageProvider(),
plan: Plan = None):
plan: Plan = None,
library_context: str = None):
"""The constructor of Config class"""
self.api_key: str = api_key
self._flush_queue_size: int = flush_queue_size
Expand All @@ -71,6 +73,7 @@ def __init__(self, api_key: str = None,
self.storage_provider: StorageProvider = storage_provider
self.opt_out: bool = False
self.plan: Plan = plan
self.library_context: str = library_context

def get_storage(self) -> Storage:
"""Use configured StorageProvider to create a Storage instance then return.
Expand Down
17 changes: 17 additions & 0 deletions src/amplitude/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def get_plan_body(self):
"session_id": ["session_id", int],
"insert_id": ["insert_id", str],
"library": ["library", str],
"library_context": ["library_context", str],
"plan": ["plan", Plan],
"group_properties": ["group_properties", dict],
"partner_id": ["partner_id", str],
Expand Down Expand Up @@ -157,6 +158,7 @@ class EventOptions:
session_id (int, optional): The start timestamp of the session in milliseconds.
insert_id (str, optional): A unique identifier for the event. Events sent with the same insert_id and device_id
we have already seen before within the past 7 days will be deduplicated.
library_context (str, optional): Library context information, e.g., used by SDK library loader/wrapper.
plan (Plan, optional): Tracking plan properties.
partner_id (str, optional): The partner id.
version_name (str, optional): The version name.
Expand Down Expand Up @@ -202,6 +204,7 @@ def __init__(self, user_id: Optional[str] = None,
event_id: Optional[int] = None,
session_id: Optional[int] = None,
insert_id: Optional[str] = None,
library_context: Optional[str] = None,
plan: Optional[Plan] = None,
partner_id: Optional[str] = None,
version_name: Optional[str] = None,
Expand Down Expand Up @@ -239,6 +242,7 @@ def __init__(self, user_id: Optional[str] = None,
self.session_id: Optional[int] = None
self.insert_id: Optional[str] = None
self.library: Optional[str] = None
self.library_context: Optional[str] = None
self.plan: Optional[Plan] = None
self.partner_id: Optional[str] = None
self.version_name: Optional[str] = None
Expand Down Expand Up @@ -273,6 +277,7 @@ def __init__(self, user_id: Optional[str] = None,
self["event_id"] = event_id
self["session_id"] = session_id
self["insert_id"] = insert_id
self["library_context"] = library_context
self["plan"] = plan
self["partner_id"] = partner_id
self["version_name"] = version_name
Expand Down Expand Up @@ -393,6 +398,7 @@ class BaseEvent(EventOptions):
session_id (int, optional): The start timestamp of the session in milliseconds.
insert_id (str, optional): A unique identifier for the event. Events sent with the same insert_id and device_id
we have already seen before within the past 7 days will be deduplicated.
library_context (str, optional): Library context information, e.g., used by SDK library loader/wrapper.
plan (Plan, optional): Tracking plan properties.
partner_id (str, optional): The partner id.
callback (callable, optional): Event level callback method. Triggered when event is sent or failed. Take three
Expand Down Expand Up @@ -438,6 +444,7 @@ def __init__(self, event_type: str,
event_id: Optional[int] = None,
session_id: Optional[int] = None,
insert_id: Optional[str] = None,
library_context: Optional[str] = None,
plan: Optional[Plan] = None,
partner_id: Optional[str] = None,
callback: Optional[Callable[[EventOptions, int, Optional[str]], None]] = None):
Expand Down Expand Up @@ -473,6 +480,7 @@ def __init__(self, event_type: str,
event_id=event_id,
session_id=session_id,
insert_id=insert_id,
library_context=library_context,
plan=plan,
partner_id=partner_id,
callback=callback)
Expand Down Expand Up @@ -729,6 +737,7 @@ class GroupIdentifyEvent(BaseEvent):
session_id (int, optional): The start timestamp of the session in milliseconds.
insert_id (str, optional): A unique identifier for the event. Events sent with the same insert_id and device_id
we have already seen before within the past 7 days will be deduplicated.
library_context (str, optional): Library context information, e.g., used by SDK library loader/wrapper.
plan (Plan, optional): Tracking plan properties.
partner_id (str, optional): The partner id.
callback (callable, optional): Event level callback method. Triggered when event is sent or failed. Take three
Expand Down Expand Up @@ -771,6 +780,7 @@ def __init__(self, user_id: Optional[str] = None,
event_id: Optional[int] = None,
session_id: Optional[int] = None,
insert_id: Optional[str] = None,
library_context: Optional[str] = None,
plan: Optional[Plan] = None,
partner_id: Optional[str] = None,
callback: Optional[Callable[[EventOptions, int, Optional[str]], None]] = None,
Expand Down Expand Up @@ -811,6 +821,7 @@ def __init__(self, user_id: Optional[str] = None,
event_id=event_id,
session_id=session_id,
insert_id=insert_id,
library_context=library_context,
plan=plan,
partner_id=partner_id,
callback=callback)
Expand Down Expand Up @@ -861,6 +872,7 @@ class IdentifyEvent(BaseEvent):
session_id (int, optional): The start timestamp of the session in milliseconds.
insert_id (str, optional): A unique identifier for the event. Events sent with the same insert_id and device_id
we have already seen before within the past 7 days will be deduplicated.
library_context (str, optional): Library context information, e.g., used by SDK library loader/wrapper.
plan (Plan, optional): Tracking plan properties.
partner_id (str, optional): The partner id.
callback (callable, optional): Event level callback method. Triggered when event is sent or failed. Take three
Expand Down Expand Up @@ -903,6 +915,7 @@ def __init__(self, user_id: Optional[str] = None,
event_id: Optional[int] = None,
session_id: Optional[int] = None,
insert_id: Optional[str] = None,
library_context: Optional[str] = None,
plan: Optional[Plan] = None,
partner_id: Optional[str] = None,
callback: Optional[Callable[[EventOptions, int, Optional[str]], None]] = None,
Expand Down Expand Up @@ -942,6 +955,7 @@ def __init__(self, user_id: Optional[str] = None,
event_id=event_id,
session_id=session_id,
insert_id=insert_id,
library_context=library_context,
plan=plan,
partner_id=partner_id,
callback=callback)
Expand Down Expand Up @@ -1081,6 +1095,7 @@ class RevenueEvent(BaseEvent):
session_id (int, optional): The start timestamp of the session in milliseconds.
insert_id (str, optional): A unique identifier for the event. Events sent with the same insert_id and device_id
we have already seen before within the past 7 days will be deduplicated.
library_context (str, optional): Library context information, e.g., used by SDK library loader/wrapper.
plan (Plan, optional): Tracking plan properties.
partner_id (str, optional): The partner id.
callback (callable, optional): Event level callback method. Triggered when event is sent or failed. Take three
Expand Down Expand Up @@ -1123,6 +1138,7 @@ def __init__(self, user_id: Optional[str] = None,
event_id: Optional[int] = None,
session_id: Optional[int] = None,
insert_id: Optional[str] = None,
library_context: Optional[str] = None,
plan: Optional[Plan] = None,
partner_id: Optional[str] = None,
callback: Optional[Callable[[EventOptions, int, Optional[str]], None]] = None,
Expand Down Expand Up @@ -1163,6 +1179,7 @@ def __init__(self, user_id: Optional[str] = None,
event_id=event_id,
session_id=session_id,
insert_id=insert_id,
library_context=library_context,
plan=plan,
partner_id=partner_id,
callback=callback)
Expand Down
14 changes: 9 additions & 5 deletions src/amplitude/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,17 @@ class ContextPlugin(Plugin):
Also set event default timestamp and insert_id if not set elsewhere.
Methods:
apply_context_data(event): Add SDK name and version to event.library.
apply_context_data(event):
- Add SDK name and version to event.library.
execute(event): Set event default timestamp and insert_id if not set elsewhere.
Add SDK name and version to event.library.
- Add SDK name and version to event.library.
- Add library context information to event.library_context.
"""

def __init__(self):
"""The constructor of ContextPlugin class"""
super().__init__(constants.PluginType.BEFORE)
self.context_string = f"{constants.SDK_LIBRARY}/{constants.SDK_VERSION}"
self.library = f"{constants.SDK_LIBRARY}/{constants.SDK_VERSION}"
self.configuration = None

def setup(self, client):
Expand All @@ -198,10 +200,10 @@ def apply_context_data(self, event: BaseEvent):
Args:
event (BaseEvent): The event to be processed.
"""
event.library = self.context_string
event.library = self.library

def execute(self, event: BaseEvent) -> BaseEvent:
"""Set event default timestamp and insert_id if not set elsewhere. Add SDK name and version to event.library.
"""Set event default timestamp and insert_id if not set elsewhere. Apply context data to event.
Args:
event (BaseEvent): The event to be processed.
Expand All @@ -212,6 +214,8 @@ def execute(self, event: BaseEvent) -> BaseEvent:
event["insert_id"] = str(uuid.uuid4())
if self.configuration.plan and (not event.plan):
event["plan"] = self.configuration.plan
if self.configuration.library_context and (not event.library_context):
event["library_context"] = self.configuration.library_context
self.apply_context_data(event)
return event

Expand Down
10 changes: 9 additions & 1 deletion src/test/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,20 @@ def test_base_event_set_plan_attribute_success(self):
"event_type": "test_event",
"plan": {"branch": "test_branch", "versionId": "v1.1"}}, event.get_event_body())

def test_base_event_set_library_context_attribute_success(self):
event = BaseEvent("test_event", user_id="test_user")
event["library_context"] = "test_library_context/1.x"
self.assertEqual({"user_id": "test_user",
"event_type": "test_event",
"library_context": "test_library_context/1.x"}, event.get_event_body())

def test_base_event_load_event_options_update_attributes_value(self):
event = BaseEvent(event_type="test_event", event_properties={"properties1": "test"}, time=0)
event_options = EventOptions(user_id="test_user", device_id="test_device", time=10)
event_options = EventOptions(user_id="test_user", device_id="test_device", library_context="test_library_context/1.x", time=10)
event.load_event_options(event_options)
expect_event_body = {"user_id": "test_user",
"device_id": "test_device",
"library_context": "test_library_context/1.x",
"time": 10,
"event_type": "test_event",
"event_properties": {"properties1": "test"}}
Expand Down
6 changes: 6 additions & 0 deletions src/test/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,22 @@ def test_plugin_initialize_amplitude_client_context_plugin_creation_success(self
client.shutdown()

def test_plugin_context_plugin_execute_event_success(self):
test_library_context = "test_library_context"
context_plugin = ContextPlugin()
context_plugin.setup(Amplitude("test_api_key"))
context_plugin.configuration.plan = Plan(source="test_source")
context_plugin.configuration.library_context = test_library_context
event = BaseEvent("test_event", user_id="test_user")
self.assertIsNone(event.time)
self.assertIsNone(event.insert_id)
self.assertIsNone(event.library)
self.assertIsNone(event.library_context)
self.assertIsNone(event.plan)
context_plugin.execute(event)
self.assertTrue(isinstance(event.time, int))
self.assertTrue(isinstance(event.insert_id, str))
self.assertTrue(isinstance(event.library, str))
self.assertEqual(event.library_context, test_library_context)
self.assertTrue(isinstance(event.plan, Plan))

def test_plugin_event_plugin_process_event_success(self):
Expand All @@ -61,12 +65,14 @@ def test_plugin_destination_plugin_add_remove_plugin_success(self):
self.assertTrue(isinstance(event.time, int))
self.assertTrue(isinstance(event.insert_id, str))
self.assertTrue(isinstance(event.library, str))
self.assertIsNone(event.library_context)
destination_plugin.remove(context_plugin)
event = BaseEvent("test_event", user_id="test_user")
destination_plugin.execute(event)
self.assertIsNone(event.time)
self.assertIsNone(event.insert_id)
self.assertIsNone(event.library)
self.assertIsNone(event.library_context)


if __name__ == '__main__':
Expand Down

0 comments on commit d1c8f52

Please sign in to comment.