diff --git a/fideslog/sdk/python/client.py b/fideslog/sdk/python/client.py index 2da5348..0915a58 100644 --- a/fideslog/sdk/python/client.py +++ b/fideslog/sdk/python/client.py @@ -1,10 +1,9 @@ # pylint: disable=too-many-arguments +from asyncio import run from typing import Dict, Optional -from urllib.error import HTTPError -from requests import post -from requests.exceptions import RequestException +from aiohttp import ClientResponseError, ClientSession, ClientTimeout from fideslog.sdk.python.event import AnalyticsEvent from fideslog.sdk.python.exceptions import AnalyticsException @@ -48,19 +47,28 @@ def __init__( self.product_name = product_name self.production_version = production_version self.developer_mode = developer_mode - self.extra_data = extra_data + self.extra_data = extra_data or {} - async def send(self, event: AnalyticsEvent) -> None: + def send(self, event: AnalyticsEvent) -> None: """ Record a new event. """ + run(self.__send(event)) + + def __get_request_payload(self, event: AnalyticsEvent) -> Dict: + """ + Construct the `POST` body required for a new `AnalyticsEvent` to + be recorded via the API server. + """ + payload = { "client_id": self.client_id, "developer": self.developer_mode, "docker": event.docker, "event": event.event, "event_created_at": event.event_created_at.isoformat(), + "extra_data": {**self.extra_data, **event.extra_data}, "local_host": event.local_host, "os": self.os, "product_name": self.product_name, @@ -81,28 +89,26 @@ async def send(self, event: AnalyticsEvent) -> None: if event_dict[extra]: payload[extra] = event_dict[extra] - extra_data: Dict = {} - if self.extra_data is not None: - extra_data = self.extra_data + return payload - if event.extra_data is not None: - for key, val in event.extra_data.items(): - extra_data[key] = val - - payload["extra_data"] = extra_data + async def __send(self, event: AnalyticsEvent) -> None: + """ + Asynchronously record a new `AnalyticsEvent`. + """ - try: - response = post( - f"{self.server_url}/events", - json=payload, - timeout=(3.05, 120), - ) - try: - response.raise_for_status() - except HTTPError as error: - raise AnalyticsException( - error.reason, error.args, status_code=error.code - ) from error - - except RequestException as exc: - raise AnalyticsException(exc.strerror, exc.args) from exc + async with ClientSession( + self.server_url, + timeout=ClientTimeout(connect=3.05, total=120), + ) as session: + async with session.post( + "/events", + json=self.__get_request_payload(event), + ) as resp: + try: + resp.raise_for_status() + except ClientResponseError as err: + raise AnalyticsException( + err.message, + err.args, + status_code=err.status, + ) from err diff --git a/fideslog/sdk/python/event.py b/fideslog/sdk/python/event.py index 4809a35..0807720 100644 --- a/fideslog/sdk/python/event.py +++ b/fideslog/sdk/python/event.py @@ -1,7 +1,6 @@ # pylint: disable= too-many-arguments, too-many-instance-attributes from datetime import datetime, timezone -from json import dumps from typing import Dict, List, Optional from urllib.parse import urlparse @@ -75,7 +74,7 @@ def __init__( self.command = command self.docker = docker self.error = error - self.extra_data = extra_data + self.extra_data = extra_data or {} self.flags = flags self.local_host = local_host self.status_code = status_code diff --git a/fideslog/sdk/python/requirements.txt b/fideslog/sdk/python/requirements.txt index e1814cc..5987fa6 100644 --- a/fideslog/sdk/python/requirements.txt +++ b/fideslog/sdk/python/requirements.txt @@ -1,4 +1,4 @@ +aiohttp[speedups]==3.8.1 bcrypt~=3.2.0 -requests==2.27.1 types-requests==2.27.11 versioneer>=0.19 diff --git a/tests/sdk/test_sdk.py b/tests/sdk/test_sdk.py index 99f25c9..2cbf9ba 100644 --- a/tests/sdk/test_sdk.py +++ b/tests/sdk/test_sdk.py @@ -57,7 +57,7 @@ def test_create_client_attribute(test_create_client: AnalyticsClient) -> None: """ assert test_create_client.client_id == "fake_client_id" - assert test_create_client.extra_data is None + assert test_create_client.extra_data == {} def test_basic_event_payload(test_basic_additional_payload: AnalyticsEvent) -> None: