From 31a882e0996e704027cf202ecf3e4f616688135f Mon Sep 17 00:00:00 2001 From: Arthur Borem Date: Mon, 15 Sep 2025 10:27:41 -0500 Subject: [PATCH 1/2] Modifies data model to distinguish between IDs pardner creates and IDs the service creates --- src/pardner/services/strava.py | 18 ++++++++++------ src/pardner/verticals/base.py | 22 ++++++++++++++++++-- src/pardner/verticals/conversation_direct.py | 2 ++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/pardner/services/strava.py b/src/pardner/services/strava.py index d8bb486..892a19c 100644 --- a/src/pardner/services/strava.py +++ b/src/pardner/services/strava.py @@ -73,7 +73,9 @@ def _convert_to_datetime(self, raw_datetime: str | None) -> datetime | None: return datetime.strptime(raw_datetime, '%Y-%m-%dT%H:%M:%SZ') return None - def _parse_social_posting(self, raw_data: Any) -> SocialPostingVertical | None: + def parse_social_posting_vertical( + self, raw_data: Any + ) -> SocialPostingVertical | None: """ Given the response from the API request, creates a :class:`SocialPostingVertical` model object, if possible. @@ -114,8 +116,12 @@ def _parse_social_posting(self, raw_data: Any) -> SocialPostingVertical | None: for photo_url in photo_urls ] + athlete_id = str(raw_data_dict['athlete'].get('id')) + return SocialPostingVertical( - creator_user_id=str(raw_data_dict['athlete'].get('id')), + creator_user_id=athlete_id, + data_owner_id=athlete_id, + service_object_id=raw_data_dict.get('id'), service=self._service_name, created_at=created_at, url=url_str, @@ -150,7 +156,7 @@ def fetch_social_posting_vertical( 'athlete/activities', params={'per_page': count, **request_params} ).json() return [ - self._parse_social_posting(raw_social_posting) + self.parse_social_posting_vertical(raw_social_posting) for raw_social_posting in raw_social_postings ], raw_social_postings raise UnsupportedRequestException( @@ -158,7 +164,7 @@ def fetch_social_posting_vertical( f'can only make a request for at most {max_count} posts at a time.', ) - def _parse_physical_activity( + def parse_physical_activity_vertical( self, raw_data: Any ) -> PhysicalActivityVertical | None: """ @@ -170,7 +176,7 @@ def _parse_physical_activity( :returns: :class:`PhysicalActivityVertical` or ``None``, depending on whether it was possible to extract data from the response """ - social_posting = self._parse_social_posting(raw_data) + social_posting = self.parse_social_posting_vertical(raw_data) if not social_posting: return None @@ -233,7 +239,7 @@ def fetch_physical_activity_vertical( 'athlete/activities', params={'per_page': count, **request_params} ).json() return [ - self._parse_physical_activity(raw_activity) + self.parse_physical_activity_vertical(raw_activity) for raw_activity in raw_activities ], raw_activities raise UnsupportedRequestException( diff --git a/src/pardner/verticals/base.py b/src/pardner/verticals/base.py index 0beb253..13b5290 100644 --- a/src/pardner/verticals/base.py +++ b/src/pardner/verticals/base.py @@ -13,8 +13,26 @@ class BaseVertical(BaseModel, ABC): supported by every transfer service. """ - id: str = Field(default_factory=lambda: uuid.uuid4().hex) - creator_user_id: str + pardner_object_id: str = Field( + default_factory=lambda: uuid.uuid4().hex, + description='The id of the vertical object for identification from pardner. ' + 'Differs from the service_generated_id, which is created by the service.', + ) + service_object_id: str | None = Field( + description='The id of the vertical object, generated by the service itself ' + 'rather than pardner.', + default=None, + ) + + creator_user_id: str | None = Field( + description='The user who created the vertical. ' + 'May or may not be the data owner. Generated by the service.', + default=None, + ) + data_owner_id: str = Field( + description='The id of the user whose data the vertical object comes from. ' + 'Generated by the service.' + ) service: str = Field( description='The name of the service the data was pulled from.' ) diff --git a/src/pardner/verticals/conversation_direct.py b/src/pardner/verticals/conversation_direct.py index e2e5d5e..e494667 100644 --- a/src/pardner/verticals/conversation_direct.py +++ b/src/pardner/verticals/conversation_direct.py @@ -8,4 +8,6 @@ class ConversationDirectVertical(ConversationVertical): """ vertical_name: str = 'conversation_direct' + is_group_conversation: bool = False + members_count: int = 2 From e2761a204f3757b0fdb7d59541906239cb164372 Mon Sep 17 00:00:00 2001 From: Arthur Borem Date: Mon, 15 Sep 2025 10:39:14 -0500 Subject: [PATCH 2/2] coerces ints to str --- src/pardner/verticals/base.py | 4 +++- tests/test_transfer_services/test_strava.py | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pardner/verticals/base.py b/src/pardner/verticals/base.py index 13b5290..ee20713 100644 --- a/src/pardner/verticals/base.py +++ b/src/pardner/verticals/base.py @@ -3,7 +3,7 @@ from datetime import datetime from typing import Type -from pydantic import AnyHttpUrl, BaseModel, Field +from pydantic import AnyHttpUrl, BaseModel, ConfigDict, Field class BaseVertical(BaseModel, ABC): @@ -13,6 +13,8 @@ class BaseVertical(BaseModel, ABC): supported by every transfer service. """ + model_config = ConfigDict(coerce_numbers_to_str=True) + pardner_object_id: str = Field( default_factory=lambda: uuid.uuid4().hex, description='The id of the vertical object for identification from pardner. ' diff --git a/tests/test_transfer_services/test_strava.py b/tests/test_transfer_services/test_strava.py index 7d7af0a..007a1da 100644 --- a/tests/test_transfer_services/test_strava.py +++ b/tests/test_transfer_services/test_strava.py @@ -174,10 +174,12 @@ def test_fetch_physical_activity_vertical(mocker, mock_strava_transfer_service): ) model_obj1_json = model_obj1.model_dump() - del model_obj1_json['id'] + del model_obj1_json['pardner_object_id'] assert model_obj1_json == { + 'service_object_id': '154504250376823', 'creator_user_id': '134815', + 'data_owner_id': '134815', 'service': 'Strava', 'vertical_name': 'physical_activity', 'created_at': datetime.datetime(2018, 5, 2, 12, 15, 9), @@ -216,10 +218,12 @@ def test_fetch_physical_activity_vertical(mocker, mock_strava_transfer_service): } model_obj2_json = model_obj2.model_dump() - del model_obj2_json['id'] + del model_obj2_json['pardner_object_id'] assert model_obj2_json == { + 'service_object_id': '1234567809', 'creator_user_id': '167560', + 'data_owner_id': '167560', 'service': 'Strava', 'vertical_name': 'physical_activity', 'created_at': datetime.datetime(2018, 4, 30, 12, 35, 51),