From 287fd946b453c3a9ca7d95c2beac11d40bb5f9f3 Mon Sep 17 00:00:00 2001 From: Anthony Correa Date: Sat, 19 Nov 2022 13:54:23 -0600 Subject: [PATCH] implement slots, implement sorting to Availability --- pyteamsnap/models/__init__.py | 4 +- pyteamsnap/models/availability.py | 60 ++++++++++++++---- pyteamsnap/models/availabilitysummary.py | 19 +++--- pyteamsnap/models/base.py | 59 +++++++++-------- pyteamsnap/models/event.py | 80 ++++++------------------ pyteamsnap/models/eventlineup.py | 12 ++-- pyteamsnap/models/eventlineupentry.py | 20 +++--- pyteamsnap/models/location.py | 28 ++++----- pyteamsnap/models/member.py | 54 ++++++++-------- pyteamsnap/models/memberstatistics.py | 15 +++++ pyteamsnap/models/opponent.py | 22 +++---- pyteamsnap/models/statistics.py | 35 +++++------ pyteamsnap/models/team.py | 49 ++++++--------- pyteamsnap/models/user.py | 44 ++++++++----- 14 files changed, 252 insertions(+), 249 deletions(-) diff --git a/pyteamsnap/models/__init__.py b/pyteamsnap/models/__init__.py index 658ed4f..679f876 100644 --- a/pyteamsnap/models/__init__.py +++ b/pyteamsnap/models/__init__.py @@ -1,4 +1,4 @@ -from .availability import Availability +from .availability import Availability, AvailabilityStatusCode from .availabilitysummary import AvailabilitySummary from .event import Event from .eventlineup import EventLineup @@ -13,7 +13,7 @@ from .team import Team from .user import User __all__ = [ - "Availability", + "Availability", "AvailabilityStatusCode", "AvailabilitySummary", "Event", "EventLineup", diff --git a/pyteamsnap/models/availability.py b/pyteamsnap/models/availability.py index de02504..3ec8368 100644 --- a/pyteamsnap/models/availability.py +++ b/pyteamsnap/models/availability.py @@ -1,22 +1,56 @@ from .base import BaseApiObject +from enum import Enum +class AvailabilityStatusCode(Enum): + YES = 1 + MAYBE = 2 + NO = 0 class Availability(BaseApiObject): rel = "availabilities" type = "availability" version = "3.866.0" - @property - def data(self): - """Data dictionary for object + __slots__ = [ + "event_id", + "member_id", + "notes", + "notes_author_member_id", + "status", + "status_code", + "team_id", + "is_current_user", + ] - :return: dict: dict with keys: - - event_id - - member_id - - notes - - notes_author_member_id - - source - - status_code - - type - """ - return super().data + def __str__(self): + return self.data.get('status') + + def __repr__(self): + return f'' + + @classmethod + def __sort_value(cls, availability_obj): + if not isinstance(availability_obj, Availability): + raise TypeError(f"Cannot compare type {availability_obj.__class__} with {cls.__class__}") + return [ + AvailabilityStatusCode.YES.value, + AvailabilityStatusCode.MAYBE.value, + AvailabilityStatusCode.NO.value, + None, + ].index(availability_obj.status_code) + + def __lt__(self, obj): + return (self.__sort_value(self) < (self.__sort_value(obj))) + + def __gt__(self, obj): + return ((self.__sort_value(self)) > (self.__sort_value(obj))) + + def __le__(self, obj): + return ((self.__sort_value(self)) <= (self.__sort_value(obj))) + + def __ge__(self, obj): + return ((self.__sort_value(self)) >= (self.__sort_value(obj))) + + def __eq__(self, obj): + + return (self.__sort_value(self) == self.__sort_value(obj)) diff --git a/pyteamsnap/models/availabilitysummary.py b/pyteamsnap/models/availabilitysummary.py index 44d10ca..801d46e 100644 --- a/pyteamsnap/models/availabilitysummary.py +++ b/pyteamsnap/models/availabilitysummary.py @@ -6,10 +6,15 @@ class AvailabilitySummary(BaseApiObject): type = "availability_summary" version = "3.866.0" - @property - def data(self): - """Data dictionary for object - - :return: dict: dict with keys: - """ - return super().data + __slots__ = [ + "event_id", + "team_id", + "going_count", + "not_going_count", + "maybe_count", + "unknown_count", + "player_going_count", + "player_not_going_count", + "player_maybe_count", + "player_unknown_count", + ] diff --git a/pyteamsnap/models/base.py b/pyteamsnap/models/base.py index 182276f..196941c 100644 --- a/pyteamsnap/models/base.py +++ b/pyteamsnap/models/base.py @@ -4,17 +4,28 @@ from apiclient import ( APIClient, ) import typing as T -import copy +from abc import ABC +from itertools import chain + # Import "preview" of Self typing # https://stackoverflow.com/a/70932112 from typing_extensions import Self +class NotPossibleError(Exception): + """Raised for actions that are not possible to perform this action per API""" + pass -class BaseApiObject: +class BaseApiObject(ABC): rel: str = None version: str = None + __slots__ = [ + 'client', + 'id', + 'id_', + ] + def __init__( self, client: APIClient, data: T.Dict[str, T.Union[str, list]] = {} ) -> None: @@ -24,31 +35,28 @@ class BaseApiObject: :param data: Data to instantiate instance, defaults to empty dict. """ self.client = client + + slots = list(chain.from_iterable(getattr(cls, '__slots__', []) for cls in self.__class__.__mro__)) for k, v in data.items(): - if k == 'type': continue - if k == 'id': continue - setattr(self, k, v) - self._internal_data_dict = copy.deepcopy(data) - self.rel = self.__class__.rel - """rel: Relationship between a linked resource and the current document""" + if k == "id" : + setattr(self, 'id', v) #TODO remove this, here for backward compatibility, but bad idea + setattr(self, 'id_', v) + elif k in ['type', 'rel']: #read only, inherit to class type + continue + elif k in slots: + setattr(self, k, v) + else: + # print(f'Warning: {k} not in {self}') + pass + pass + + + def __str__(self): + return self.name def __repr__(self): - return f'TeamSnap<{self.__class__.__name__}:{self.id}> "{self.data.get("name")}"' + return f'' - def __getitem__(self, key): - return self._internal_data_dict.__getitem__(key) - # return getattr(self, key) - - def __setitem__(self, key, newvalue): - return self._internal_data_dict.__setitem__(key, newvalue) - # return setattr(self, key, newvalue) - - def __iter__(self): - return iter(self._internal_data_dict.items()) - - @property - def id(self) -> int: - return self._internal_data_dict["id"] @property def data(self) -> T.Dict[str, T.Union[str, list]]: @@ -56,7 +64,8 @@ class BaseApiObject: :return: dict: dict with keys: """ - return self._internal_data_dict + slots = chain.from_iterable(getattr(cls, '__slots__', []) for cls in self.__class__.__mro__) + return {k:getattr(self, k, None) for k in slots} @classmethod def search(cls, client: APIClient, **kwargs): @@ -82,7 +91,6 @@ class BaseApiObject: } } r = self.client.post_item(self.rel, data=data) - self._internal_data_dict = r return self def put(self) -> Self: @@ -93,7 +101,6 @@ class BaseApiObject: } id = self.data.get("id") r = self.client.put_item(self.rel, id=id, data=data) - self._internal_data_dict = r return self def delete(self): diff --git a/pyteamsnap/models/event.py b/pyteamsnap/models/event.py index 76e0c07..5014557 100644 --- a/pyteamsnap/models/event.py +++ b/pyteamsnap/models/event.py @@ -11,13 +11,15 @@ class Event(BaseApiObject): type = "event" version = "3.866.0" - __slots__ = ( - # "type", + __slots__ = [ "additional_location_details", - "browser_time_zone", + "arrival_date", "division_location_id", "doesnt_count_towards_record", "duration_in_minutes", + "end_date", + "formatted_results", + "game_type", "game_type_code", "icon_color", "is_canceled", @@ -30,18 +32,12 @@ class Event(BaseApiObject): "minutes_to_arrive_early", "name", "notes", - "notify_opponent", - "notify_opponent_contacts_email", - "notify_opponent_contacts_name", - "notify_opponent_notes", - "notify_team", - "notify_team_as_member_id", "opponent_id", "points_for_opponent", "points_for_team", - "repeating_include", + "repeating_type", "repeating_type_code", - "repeating_until", + "repeating_uuid", "results", "results_url", "shootout_points_for_opponent", @@ -49,56 +45,20 @@ class Event(BaseApiObject): "start_date", "team_id", "time_zone", + "time_zone_description", + "time_zone_iana_name", + "time_zone_offset", + "source_time_zone_iana_name", "tracks_availability", "uniform", - ) + "is_league_controlled", + "opponent_name", + "location_name", + "formatted_title", + "formatted_title_for_multi_team", + "created_at", + "updated_at", + ] def __str__(self): - return f'{self["formatted_title"]}' - - @property - def data(self): - """Data dictionary for object - - :return: dict: dict with strings: - - type - - additional_location_details - - browser_time_zone - - division_location_id - - doesnt_count_towards_record - - duration_in_minutes - - game_type_code - - icon_color - - is_canceled - - is_game - - is_overtime - - is_shootout - - is_tbd - - label - - location_id - - minutes_to_arrive_early - - name - - notes - - notify_opponent - - notify_opponent_contacts_email - - notify_opponent_contacts_name - - notify_opponent_notes - - notify_team - - notify_team_as_member_id - - opponent_id - - points_for_opponent - - points_for_team - - repeating_include - - repeating_type_code - - repeating_until - - results - - results_url - - shootout_points_for_opponent - - shootout_points_for_team - - start_date - - team_id - - time_zone - - tracks_availability - - uniform - """ - return super().data + return f'{self.formatted_title}' diff --git a/pyteamsnap/models/eventlineup.py b/pyteamsnap/models/eventlineup.py index 0d906ae..2a531b6 100644 --- a/pyteamsnap/models/eventlineup.py +++ b/pyteamsnap/models/eventlineup.py @@ -5,11 +5,9 @@ class EventLineup(BaseApiObject): rel = "event_lineups" type = "event_lineup" version = "3.866.0" - template = {} - @property - def data(self): - """ - :return: dict: dict with strings: - """ - return super().data + __slots__ = [ + "event_id", + "is_published", + "entries_count" + ] diff --git a/pyteamsnap/models/eventlineupentry.py b/pyteamsnap/models/eventlineupentry.py index c151507..6be65f2 100644 --- a/pyteamsnap/models/eventlineupentry.py +++ b/pyteamsnap/models/eventlineupentry.py @@ -6,16 +6,16 @@ class EventLineupEntry(BaseApiObject): type = "event_lineup_entry" version = "3.866.0" - @property - def data(self): - """ - :return: dict: dict with strings: - - member_id - - sequence - - label - - type - """ - return super().data + __slots__ = [ + "event_lineup_id", + "event_id", + "member_id", + "sequence", + "label", + "member_name", + "member_photo", + "availability_status_code" + ] @classmethod def search(cls, client, **kwargs): diff --git a/pyteamsnap/models/location.py b/pyteamsnap/models/location.py index a39025d..bd5f34d 100644 --- a/pyteamsnap/models/location.py +++ b/pyteamsnap/models/location.py @@ -6,20 +6,14 @@ class Location(BaseApiObject): type = "location" version = "3.866.0" - @property - def data(self): - """Data dictionary for object - - :return: dict: dict with keys: - - name - - url - - phone - - notes - - address - - latitude - - longitude - - team_id - - is_retired - - type - """ - return super().data + __slots__ = [ + 'name', + 'url', + 'phone', + 'notes', + 'address', + 'latitude', + 'longitude', + 'team_id', + 'is_retired', + ] diff --git a/pyteamsnap/models/member.py b/pyteamsnap/models/member.py index 5185e9d..22c81d0 100644 --- a/pyteamsnap/models/member.py +++ b/pyteamsnap/models/member.py @@ -11,31 +11,31 @@ class Member(BaseApiObject): type = "member" version = "3.866.0" - @property - def data(self): - """Data dictionary for object + __slots__ = [ + 'first_name', + 'last_name', + 'address_city', + 'address_state', + 'address_street1', + 'address_street2', + 'address_zip', + 'birthday', + 'gender', + 'hide_address', + 'hide_age', + 'is_address_hidden', + 'is_age_hidden', + 'is_manager', + 'is_non_player', + 'is_ownership_pending', + 'jersey_number', + 'position', + 'source_action', + 'team_id', + ] - :return: dict: dict with keys: - - first_name - - last_name - - address_city - - address_state - - address_street1 - - address_street2 - - address_zip - - birthday - - gender - - hide_address - - hide_age - - is_address_hidden - - is_age_hidden - - is_manager - - is_non_player - - is_ownership_pending - - jersey_number - - position - - source_action - - team_id - - type - """ - return super().data + def __str__(self): + return f"{self.first_name} {self.last_name}" + + def __repr__(self): + return f'' diff --git a/pyteamsnap/models/memberstatistics.py b/pyteamsnap/models/memberstatistics.py index 453444c..15e0aaf 100644 --- a/pyteamsnap/models/memberstatistics.py +++ b/pyteamsnap/models/memberstatistics.py @@ -3,3 +3,18 @@ from .base import BaseApiObject class MemberStatistics(BaseApiObject): rel = "member_statistics" + type = "member_statistic" + + __slots__ = [ + "id", + "count_games_played", + "total", + "average", + "total_ranking", + "average_ranking", + "total_ranking_for_query", + "average_ranking_for_query", + "statistic_id", + "member_id", + "team_id", + ] diff --git a/pyteamsnap/models/opponent.py b/pyteamsnap/models/opponent.py index fa8c423..949d0f1 100644 --- a/pyteamsnap/models/opponent.py +++ b/pyteamsnap/models/opponent.py @@ -6,17 +6,11 @@ class Opponent(BaseApiObject): type = "opponent" version = "3.866.0" - @property - def data(self): - """Data dictionary for object - - :return: dict: dict with keys: - - name - - contacts_name - - contacts_phone - - contacts_email - - notes - - team_id - - type - """ - return super().data + __slots__ = [ + 'name', + 'contacts_name', + 'contacts_phone', + 'contacts_email', + 'notes', + 'team_id', + ] diff --git a/pyteamsnap/models/statistics.py b/pyteamsnap/models/statistics.py index f3fd6b2..80430e7 100644 --- a/pyteamsnap/models/statistics.py +++ b/pyteamsnap/models/statistics.py @@ -6,24 +6,19 @@ class Statistics(BaseApiObject): type = "statistic" version = "3.866.0" - @property - def data(self): - """Data dictionary for object + __slots__ = [ + 'acronym', + 'always_display_decimals', + 'formula', + 'is_in_descending_order', + 'display_zero_totals', + 'is_percentage', + 'is_private', + 'is_team_statistic', + 'is_top_statistic', + 'name', + 'precision', + 'statistic_group_id', + 'team_id', + ] - :return: dict: dict with keys: - - acronym - - always_display_decimals - - formula - - is_in_descending_order - - display_zero_totals - - is_percentage - - is_private - - is_team_statistic - - is_top_statistic - - name - - precision - - statistic_group_id - - team_id - - type - """ - return super().data diff --git a/pyteamsnap/models/team.py b/pyteamsnap/models/team.py index 73e3672..dc19110 100644 --- a/pyteamsnap/models/team.py +++ b/pyteamsnap/models/team.py @@ -12,32 +12,23 @@ class Team(BaseApiObject): type = "team" version = "3.866.0" - # Override this class property to add docstring - # should not change functionality. Probably a better - # to do this... - @property - def data(self): - """Data dictionary for object - - :return: dict: dict with keys: - - ad_unit_hero_id - - ad_unit_hero_template_id - - ad_unit_inline_id - - division_id - - division_name - - is_ownership_pending - - league_name - - league_url - - location_country - - location_postal_code - - name - - owner_email - - owner_first_name - - owner_last_name - - season_name - - sport_id - - team - - time_zone - - type - """ - return super().data + __slots__ = [ + 'ad_unit_hero_id', + 'ad_unit_hero_template_id', + 'ad_unit_inline_id', + 'division_id', + 'division_name', + 'is_ownership_pending', + 'league_name', + 'league_url', + 'location_country', + 'location_postal_code', + 'name', + 'owner_email', + 'owner_first_name', + 'owner_last_name', + 'season_name', + 'sport_id', + 'team', + 'time_zone', + ] diff --git a/pyteamsnap/models/user.py b/pyteamsnap/models/user.py index 87b50ae..47ebc90 100644 --- a/pyteamsnap/models/user.py +++ b/pyteamsnap/models/user.py @@ -1,28 +1,38 @@ -from .base import BaseApiObject +from .base import BaseApiObject, NotPossibleError class User(BaseApiObject): + rel = "users" type = "user" version = "3.866.0" + __slots__ = [ + 'first_name', + 'last_name', + 'password', + 'birthday', + 'email', + 'facebook_id', + 'facebook_access_token', + 'is_lab_rat', + 'receives_newsletter', + ] + def __str__(self): return f'{self["first_name"]} {self["last_name"]}' - @property - def data(self): - """Data dictionary for object + def delete(self): + """It is not possible to create or delete users via the API; + however, it is possible to update data on a user's record.""" + raise NotPossibleError ('It is not possible to delete users via the API') - :return: dict: dict with keys: - - first_name - - last_name - - password - - birthday - - email - - facebook_id - - facebook_access_token - - type - - is_lab_rat - - receives_newsletter - """ - return super().data + def new(self): + """It is not possible to create or delete users via the API; + however, it is possible to update data on a user's record.""" + raise NotPossibleError('It is not possible to create users via the API') + + def post(self): + """It is not possible to create or delete users via the API; + however, it is possible to update data on a user's record.""" + raise NotPossibleError('It is not possible to create users via the API')