Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/pardner/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@

class InsufficientScopeException(Exception):
def __init__(self, *unsupported_verticals: Vertical, service_name: str) -> None:
combined_verticals = ', '.join(unsupported_verticals)
combined_verticals = ', '.join(
[str(vertical) for vertical in unsupported_verticals]
)
super().__init__(
f'Cannot add {combined_verticals} to {service_name} with current scope.'
)


class UnsupportedVerticalException(Exception):
def __init__(self, *unsupported_verticals: Vertical, service_name: str) -> None:
combined_verticals = ', '.join(unsupported_verticals)
combined_verticals = ', '.join(
[str(vertical) for vertical in unsupported_verticals]
)
is_more_than_one_vertical = len(unsupported_verticals) > 1
super().__init__(
f'Cannot fetch {combined_verticals} from {service_name} because '
Expand Down
2 changes: 1 addition & 1 deletion src/pardner/services/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,5 +263,5 @@ def fetch(
vertical, service_name=self._service_name
)

method_name = f'fetch_{vertical.plural}'
method_name = f'fetch_{vertical.vertical_name}_vertical'
getattr(self, method_name)(request_params=request_params, **params)
24 changes: 15 additions & 9 deletions src/pardner/services/groupme.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@

from pardner.exceptions import UnsupportedRequestException
from pardner.services import BaseTransferService
from pardner.verticals import Vertical
from pardner.verticals import (
BlockedUserVertical,
ChatBotVertical,
ConversationDirectVertical,
ConversationGroupVertical,
Vertical,
)


class GroupMeTransferService(BaseTransferService):
Expand All @@ -35,10 +41,10 @@ def __init__(
client_id=client_id,
redirect_uri=redirect_uri,
supported_verticals={
Vertical.BlockedUser,
Vertical.ChatBot,
Vertical.ConversationDirect,
Vertical.ConversationGroup,
BlockedUserVertical,
ChatBotVertical,
ConversationDirectVertical,
ConversationGroupVertical,
},
verticals=verticals,
)
Expand Down Expand Up @@ -129,7 +135,7 @@ def fetch_user_data(self, request_params: dict[str, Any] = {}) -> Any:
self._user_id = user_data['id']
return user_data

def fetch_blocked_users(self, request_params: dict[str, Any] = {}) -> Any:
def fetch_blocked_user_vertical(self, request_params: dict[str, Any] = {}) -> Any:
"""
Sends a GET request to fetch the users blocked by the authenticated user.

Expand All @@ -144,15 +150,15 @@ def fetch_blocked_users(self, request_params: dict[str, Any] = {}) -> Any:

return blocked_users['blocks']

def fetch_chat_bots(self, request_params: dict[str, Any] = {}) -> Any:
def fetch_chat_bot_vertical(self, request_params: dict[str, Any] = {}) -> Any:
"""
Sends a GET request to fetch the chat bots created by the authenticated user.

:returns: a JSON object with the result of the request.
"""
return self._fetch_resource_common('bots', request_params)

def fetch_conversations_direct(
def fetch_conversation_direct_vertical(
self, request_params: dict[str, Any] = {}, count: int = 10
) -> Any:
"""
Expand All @@ -174,7 +180,7 @@ def fetch_conversations_direct(
'can only make a request for at most 10 direct conversations at a time.',
)

def fetch_conversations_group(
def fetch_conversation_group_vertical(
self, request_params: dict[str, Any] = {}, count: int = 10
) -> Any:
"""
Expand Down
8 changes: 4 additions & 4 deletions src/pardner/services/strava.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pardner.exceptions import UnsupportedRequestException, UnsupportedVerticalException
from pardner.services import BaseTransferService
from pardner.services.utils import scope_as_set, scope_as_string
from pardner.verticals import Vertical
from pardner.verticals import PhysicalActivityVertical, Vertical


class StravaTransferService(BaseTransferService):
Expand Down Expand Up @@ -31,7 +31,7 @@ def __init__(
client_secret=client_secret,
redirect_uri=redirect_uri,
state=state,
supported_verticals={Vertical.PhysicalActivity},
supported_verticals={PhysicalActivityVertical},
verticals=verticals,
)

Expand Down Expand Up @@ -60,11 +60,11 @@ def scope_for_verticals(self, verticals: Iterable[Vertical]) -> set[str]:
raise UnsupportedVerticalException(
vertical, service_name=self._service_name
)
if vertical == Vertical.PhysicalActivity:
if vertical == PhysicalActivityVertical:
sub_scopes.update(['activity:read', 'profile:read_all'])
return sub_scopes

def fetch_physical_activities(
def fetch_physical_activity_vertical(
self, request_params: dict[str, Any] = {}, count: int = 30
) -> list[Any]:
"""
Expand Down
6 changes: 3 additions & 3 deletions src/pardner/services/tumblr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pardner.exceptions import UnsupportedRequestException
from pardner.services import BaseTransferService
from pardner.verticals import Vertical
from pardner.verticals import SocialPostingVertical, Vertical


class TumblrTransferService(BaseTransferService):
Expand Down Expand Up @@ -30,7 +30,7 @@ def __init__(
client_secret=client_secret,
redirect_uri=redirect_uri,
state=state,
supported_verticals={Vertical.FeedPost},
supported_verticals={SocialPostingVertical},
verticals=verticals,
)

Expand All @@ -48,7 +48,7 @@ def fetch_token(
) -> dict[str, Any]:
return super().fetch_token(code, authorization_response, include_client_id)

def fetch_feed_posts(
def fetch_social_posting_vertical(
self,
request_params: dict[str, Any] = {},
count: int = 20,
Expand Down
6 changes: 6 additions & 0 deletions src/pardner/verticals/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
from pardner.verticals.blocked_user import BlockedUserVertical as BlockedUserVertical
from pardner.verticals.chat_bot import ChatBotVertical as ChatBotVertical
from pardner.verticals.conversation import ConversationVertical as ConversationVertical
from pardner.verticals.conversation_direct import (
ConversationDirectVertical as ConversationDirectVertical,
)
from pardner.verticals.conversation_group import (
ConversationGroupVertical as ConversationGroupVertical,
)
from pardner.verticals.message import MessageVertical as MessageVertical
from pardner.verticals.physical_activity import (
PhysicalActivityVertical as PhysicalActivityVertical,
Expand Down
32 changes: 7 additions & 25 deletions src/pardner/verticals/base.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,10 @@
from abc import ABC
from datetime import datetime
from enum import StrEnum
from typing import Optional
from typing import Type

from pydantic import AnyHttpUrl, BaseModel, Field


class Vertical(StrEnum):
"""
Represents the verticals, or categories of data, that are supported by this library.
Not all verticals are supported by every transfer service.
"""

BlockedUser = 'blocked_user'
ChatBot = 'chat_bot'
ConversationDirect = 'conversation_direct', 'conversations_direct'
ConversationGroup = 'conversation_group', 'conversations_group'
ConversationMessage = 'conversation_message'
FeedPost = 'feed_post'
PhysicalActivity = 'physical_activity', 'physical_activities'

plural: str

def __new__(cls, singular: str, plural: Optional[str] = None) -> 'Vertical':
vertical_obj = str.__new__(cls, singular)
vertical_obj._value_ = singular
vertical_obj.plural = plural if plural else f'{singular}s'
return vertical_obj


class BaseVertical(BaseModel, ABC):
"""
Base class for all verticals, except sub-verticals. Represents the verticals, or
Expand All @@ -45,3 +21,9 @@ class BaseVertical(BaseModel, ABC):

created_at: datetime | None = None
url: AnyHttpUrl | None = None

def __str__(self):
return self.vertical_name


Vertical = Type[BaseVertical]
11 changes: 11 additions & 0 deletions src/pardner/verticals/conversation_direct.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pardner.verticals.conversation import ConversationVertical


class ConversationDirectVertical(ConversationVertical):
"""
The metadata related to a conversation where messages are exchanged between one
or more people.
"""

vertical_name: str = 'conversation_direct'
is_group_conversation: bool = False
11 changes: 11 additions & 0 deletions src/pardner/verticals/conversation_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pardner.verticals.conversation import ConversationVertical


class ConversationGroupVertical(ConversationVertical):
"""
The metadata related to a conversation where messages are exchanged between one
or more people.
"""

vertical_name: str = 'conversation_group'
is_group_conversation: bool = True
31 changes: 21 additions & 10 deletions tests/test_transfer_services/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,24 @@
StravaTransferService,
TumblrTransferService,
)
from pardner.verticals import Vertical
from pardner.verticals import (
BlockedUserVertical,
ConversationDirectVertical,
PhysicalActivityVertical,
SocialPostingVertical,
)
from pardner.verticals.base import BaseVertical

# CLASSES


class NewVertical(BaseVertical):
vertical_name: str = 'new_vertical'


class ExtraScopeVertical(BaseVertical):
vertical_name: str = 'extra_scope_vertical'


# FIXTURES

Expand Down Expand Up @@ -37,28 +54,22 @@ def mock_oauth2_session_response(mocker):


@pytest.fixture
def mock_vertical():
Vertical.NEW_VERTICAL = 'new_vertical'
Vertical.NEW_VERTICAL_EXTRA_SCOPE = 'new_vertical_unsupported'


@pytest.fixture
def mock_tumblr_transfer_service(verticals=[Vertical.FeedPost]):
def mock_tumblr_transfer_service(verticals=[SocialPostingVertical]):
return TumblrTransferService(
'fake_client_id', 'fake_client_secret', 'https://redirect_uri', None, verticals
)


@pytest.fixture
def mock_strava_transfer_service(verticals=[Vertical.PhysicalActivity]):
def mock_strava_transfer_service(verticals=[PhysicalActivityVertical]):
return StravaTransferService(
'fake_client_id', 'fake_client_secret', 'https://redirect_uri', None, verticals
)


@pytest.fixture
def mock_groupme_transfer_service(
verticals=[Vertical.BlockedUser, Vertical.ConversationDirect],
verticals=[BlockedUserVertical, ConversationDirectVertical],
):
groupme = GroupMeTransferService(
client_id='fake_client_id',
Expand Down
43 changes: 22 additions & 21 deletions tests/test_transfer_services/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
InsufficientScopeException,
UnsupportedVerticalException,
)
from pardner.verticals import Vertical
from pardner.verticals import SocialPostingVertical
from tests.test_transfer_services.conftest import ExtraScopeVertical, NewVertical

SAMPLE_SCOPE = {'fake', 'scope'}
SAMPLE_BASE_URL = 'https://api.example.com/v1'
Expand All @@ -30,51 +31,51 @@ def __init__(self, supported_verticals, verticals):
)

def scope_for_verticals(self, verticals):
if Vertical.NEW_VERTICAL_EXTRA_SCOPE in verticals:
if ExtraScopeVertical in verticals:
return SAMPLE_SCOPE | {'extra_scope'}
return SAMPLE_SCOPE


@pytest.fixture
def blank_transfer_service(monkeypatch):
return FakeTransferService([Vertical.FeedPost], [])
return FakeTransferService([SocialPostingVertical], [])


def test_add_verticals_raises_exception(mock_vertical, blank_transfer_service):
def test_add_verticals_raises_exception(blank_transfer_service):
with pytest.raises(InsufficientScopeException):
blank_transfer_service.add_verticals([Vertical.NEW_VERTICAL_EXTRA_SCOPE])
blank_transfer_service.add_verticals([ExtraScopeVertical])


def test_set_verticals_raises_exception(mock_vertical, blank_transfer_service):
def test_set_verticals_raises_exception(blank_transfer_service):
with pytest.raises(UnsupportedVerticalException):
blank_transfer_service.verticals = [Vertical.NEW_VERTICAL]
blank_transfer_service.verticals = [NewVertical]


@pytest.fixture
def mock_transfer_service(mock_vertical):
def mock_transfer_service():
mock_transfer_service = FakeTransferService(
[Vertical.FeedPost, Vertical.NEW_VERTICAL, Vertical.NEW_VERTICAL_EXTRA_SCOPE],
[Vertical.FeedPost],
[SocialPostingVertical, NewVertical, ExtraScopeVertical],
[SocialPostingVertical],
)
mock_transfer_service.scope = SAMPLE_SCOPE
return mock_transfer_service


def test_set_supported_verticals(mock_vertical, mock_transfer_service):
mock_transfer_service.verticals = [Vertical.NEW_VERTICAL]
assert mock_transfer_service.verticals == {Vertical.NEW_VERTICAL}
def test_set_supported_verticals(mock_transfer_service):
mock_transfer_service.verticals = [NewVertical]
assert mock_transfer_service.verticals == {NewVertical}


def test_add_supported_verticals(mock_vertical, mock_transfer_service):
assert mock_transfer_service.add_verticals([Vertical.NEW_VERTICAL])
assert mock_transfer_service.verticals == {Vertical.FeedPost, Vertical.NEW_VERTICAL}
def test_add_supported_verticals(mock_transfer_service):
assert mock_transfer_service.add_verticals([NewVertical])
assert mock_transfer_service.verticals == {SocialPostingVertical, NewVertical}


def test_add_unsupported_vertical_new_scope_required(
monkeypatch, mock_vertical, mock_transfer_service
monkeypatch, mock_transfer_service
):
def _mock_scope_for_verticals(verticals):
if Vertical.NEW_VERTICAL_EXTRA_SCOPE in verticals:
if ExtraScopeVertical in verticals:
return {'new_scope'}
return SAMPLE_SCOPE

Expand All @@ -83,13 +84,13 @@ def _mock_scope_for_verticals(verticals):
mock_transfer_service, 'scope_for_verticals', _mock_scope_for_verticals
)
assert not mock_transfer_service.add_verticals(
[Vertical.NEW_VERTICAL_EXTRA_SCOPE], should_reauth=True
[ExtraScopeVertical], should_reauth=True
)
assert not mock_transfer_service._oAuth2Session.access_token
assert mock_transfer_service.scope == {'fake', 'scope', 'new_scope'}
assert mock_transfer_service.verticals == {
Vertical.FeedPost,
Vertical.NEW_VERTICAL_EXTRA_SCOPE,
SocialPostingVertical,
ExtraScopeVertical,
}


Expand Down
Loading