diff --git a/examples/flask_example/flaskapp.py b/examples/flask_example/flaskapp.py index 8abb3c5..62eab29 100644 --- a/examples/flask_example/flaskapp.py +++ b/examples/flask_example/flaskapp.py @@ -48,7 +48,7 @@ def track_revenue(user_id): @app.route("/flush") def flush_event(): amp_client.flush() - return f"

All events flushed

" + return "

All events flushed

" if __name__ == "__main__": diff --git a/src/amplitude/config.py b/src/amplitude/config.py index ac70308..838ab59 100644 --- a/src/amplitude/config.py +++ b/src/amplitude/config.py @@ -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. @@ -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 @@ -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. diff --git a/src/amplitude/event.py b/src/amplitude/event.py index 3d25bb3..a84b296 100644 --- a/src/amplitude/event.py +++ b/src/amplitude/event.py @@ -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], @@ -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. @@ -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, @@ -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 @@ -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 @@ -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 @@ -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): @@ -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) @@ -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 @@ -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, @@ -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) @@ -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 @@ -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, @@ -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) @@ -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 @@ -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, @@ -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) diff --git a/src/amplitude/plugin.py b/src/amplitude/plugin.py index 469521a..e39bc42 100644 --- a/src/amplitude/plugin.py +++ b/src/amplitude/plugin.py @@ -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): @@ -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. @@ -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 diff --git a/src/test/test_event.py b/src/test/test_event.py index a54a835..4021067 100644 --- a/src/test/test_event.py +++ b/src/test/test_event.py @@ -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"}} diff --git a/src/test/test_plugin.py b/src/test/test_plugin.py index ee342f7..7dabca2 100644 --- a/src/test/test_plugin.py +++ b/src/test/test_plugin.py @@ -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): @@ -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__':