Source code for psnawp_api.models.trophies.trophy_group

"""Provides the TrophyGroupsSummary class for retrieving trophy summary for main game and each expansion in the video game title."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Generic, TypeVar

from typing_extensions import Self

from psnawp_api.core import PSNAWPNotFoundError
from psnawp_api.models.trophies import PlatformType, TrophySet
from psnawp_api.utils import API_PATH, BASE_PATH, iso_format_to_datetime

if TYPE_CHECKING:
    from datetime import datetime

    from psnawp_api.core import Authenticator


[docs] @dataclass(frozen=True) class TrophyGroupSummary: """TrophyGroupSummary contains trophy count data for one trophy group of a game title. :var str | None trophy_group_id: ID for the trophy group (all titles have default, additional groups are 001 incrementing). :var str | None trophy_group_name: Trophy group name. :var str | None trophy_group_detail: Trophy group description (PS3, PS4 and PS Vita titles only). :var str | None trophy_group_icon_url: URL of the icon for the trophy group. :var TrophySet defined_trophies: Number of trophies for the trophy group by type. .. note:: To initialize this class, use the class method :py:meth:`TrophyGroupSummary.from_dict`. """ trophy_group_id: str | None trophy_group_name: str | None trophy_group_detail: str | None trophy_group_icon_url: str | None defined_trophies: TrophySet
[docs] @classmethod def from_dict(cls, trophy_group_dict: dict[str, Any]) -> Self: """Creates an instance of :py:class:`~TrophyGroupSummary` from a dictionary. :param data: Dictionary containing data, typically from an API response. :returns: A new instance of :py:class:`~TrophyGroupSummary`. Expected keys vary by class but generally map to instance attributes. Missing keys may default to ``None`` or reasonable defaults. """ return cls( trophy_group_id=trophy_group_dict.get("trophyGroupId"), trophy_group_name=trophy_group_dict.get("trophyGroupName"), trophy_group_detail=trophy_group_dict.get("trophyGroupDetail"), trophy_group_icon_url=trophy_group_dict.get("trophyGroupIconUrl"), defined_trophies=TrophySet( **trophy_group_dict.get( "definedTrophies", {"bronze": 0, "silver": 0, "gold": 0, "platinum": 0}, ), ), )
[docs] @dataclass(frozen=True) class TrophyGroupSummaryWithProgress(TrophyGroupSummary): """TrophyGroupSummaryWithProgress contains trophy count data for one trophy group of a game title and user progress for each trophy group. :var int | None progress: Percentage of trophies earned for group. :var TrophySet earned_trophies: Number of trophies for the group which have been earned by type. :var datetime.datetime | None last_updated_datetime: Date most recent trophy earned for the group. .. note:: To initialize this class, use the class method :meth:`TrophyGroupSummaryWithProgress.from_dict`. """ progress: int | None earned_trophies: TrophySet last_updated_datetime: datetime | None
[docs] @classmethod def from_dict(cls, trophy_group_dict: dict[str, Any]) -> Self: """Creates an instance of :py:class:`~TrophyGroupSummaryWithProgress` from a dictionary. :param data: Dictionary containing data, typically from an API response. :returns: A new instance of :py:class:`~TrophyGroupSummaryWithProgress`. Expected keys vary by class but generally map to instance attributes. Missing keys may default to ``None`` or reasonable defaults. """ return cls( trophy_group_id=trophy_group_dict.get("trophyGroupId"), trophy_group_name=trophy_group_dict.get("trophyGroupName"), trophy_group_detail=trophy_group_dict.get("trophyGroupDetail"), trophy_group_icon_url=trophy_group_dict.get("trophyGroupIconUrl"), defined_trophies=TrophySet( **trophy_group_dict.get( "definedTrophies", {"bronze": 0, "silver": 0, "gold": 0, "platinum": 0}, ), ), progress=trophy_group_dict.get("progress"), earned_trophies=TrophySet( **trophy_group_dict.get( "earnedTrophies", {"bronze": 0, "silver": 0, "gold": 0, "platinum": 0}, ), ), last_updated_datetime=iso_format_to_datetime(trophy_group_dict.get("lastUpdatedDateTime")), )
T = TypeVar("T", bound=TrophyGroupSummary)
[docs] class TrophyGroupsSummary(Generic[T]): """Summary of trophy data for a PlayStation game title. This class encapsulates the trophy summary information returned by the PlayStation API. It provides overall trophy counts for a game title as well as detailed summaries for each trophy group. A trophy group represents a segment of the title such as the main game or any associated DLCs/expansions. For example, if a game has two DLCs, the trophy_groups list will include three entries: one for the main game and one for each DLC. :var str | None trophy_set_version: The current version of the trophy set. :var str | None trophy_title_name: Title name. :var str | None trophy_title_detail: Title description (PS3, PS4 and PS Vita titles only). :var str | None trophy_title_icon_url: URL of the icon for the trophy title. :var set[PlatformType] trophy_title_platform: The platform this title belongs to. :var TrophySet defined_trophies: Total number of trophies for the title by type. :var list[T] trophy_groups: Individual object for each trophy group returned. :var bool | None hidden_flag: Whether title has been hidden on the accounts trophy list (Authenticating account only). :var int | None progress: Percentage of trophies earned for the title. :var TrophySet earned_trophies: Number of trophies for the title which have been earned by type. :var datetime.datetime | None last_updated_datetime: Date most recent trophy earned for the title (UTC+00:00 TimeZone). .. note:: To initialize this class, you need the :py:meth:`TrophyGroupsSummaryBuilder.game_title_trophy_groups_summary` or :py:meth:`TrophyGroupsSummaryBuilder.earned_user_trophy_groups_summary`. """
[docs] def __init__( self, trophy_set_version: str | None, trophy_title_name: str | None, trophy_title_detail: str | None, trophy_title_icon_url: str | None, trophy_title_platform: set[PlatformType], defined_trophies: TrophySet, trophy_groups: list[T], hidden_flag: bool | None, progress: int | None, earned_trophies: TrophySet, last_updated_datetime: datetime | None, ) -> None: """Initialize a TrophyGroupsSummary instance with PlayStation trophy data.""" self.trophy_set_version = trophy_set_version self.trophy_title_name = trophy_title_name self.trophy_title_detail = trophy_title_detail self.trophy_title_icon_url = trophy_title_icon_url self.trophy_title_platform = trophy_title_platform self.defined_trophies = defined_trophies self.trophy_groups = trophy_groups self.hidden_flag = hidden_flag self.progress = progress self.earned_trophies = earned_trophies self.last_updated_datetime = last_updated_datetime
def __str__(self) -> str: """Returns a human-readable summary of the trophy group.""" return ( f"TrophyGroupsSummary(Title: {self.trophy_title_name}, Defined: {self.defined_trophies}, Earned: {self.earned_trophies}, Progress: {self.progress})" ) def __repr__(self) -> str: """Returns a detailed string representation of the object for debugging.""" return ( f"TrophyGroupsSummary(trophy_set_version={self.trophy_set_version}, " f"trophy_title_name={self.trophy_title_name}, " f"trophy_title_detail={self.trophy_title_detail}, " f"trophy_title_icon_url={self.trophy_title_icon_url}, " f"trophy_title_platform={self.trophy_title_platform}, " f"defined_trophies={self.defined_trophies}, " f"trophy_groups={self.trophy_groups}, " f"hidden_flag={self.hidden_flag}, " f"progress={self.progress}, " f"earned_trophies={self.earned_trophies}, " f"last_updated_datetime={self.last_updated_datetime})" )
[docs] class TrophyGroupsSummaryBuilder: """Provides methods to build a TrophyGroupsSummary from PlayStation Network endpoints. :var Authenticator authenticator: An instance of :py:class:`~psnawp_api.core.authenticator.Authenticator` used to authenticate and make HTTPS requests. :var str np_communication_id: Unique identifier associated with a game's trophy set, essential for accessing trophy data. .. note:: This class is intended to be used via Client or User class. See :py:meth:`psnawp_api.models.client.Client.trophy_groups_summary` or :py:meth:`psnawp_api.models.user.User.trophy_groups_summary`. """
[docs] def __init__(self, authenticator: Authenticator, np_communication_id: str) -> None: """Initializes the TrophyGroupsSummaryBuilder. :param Authenticator authenticator: Instance used to make HTTP requests. :param str np_communication_id: Unique ID of a game title used to request trophy information. This can be obtained from the :py:class:`~psnawp_api.models.game_title.GameTitle` class. """ self.authenticator = authenticator self.np_communication_id: str = np_communication_id
[docs] @staticmethod def trophy_groups_dict_to_obj( trophy_groups_dict: dict[str, Any], trophy_groups: list[T], ) -> TrophyGroupsSummary[T]: """Takes list of TrophyGroupSummary and TrophyGroupSummaryWithProgress converts them to Class instance. :param trophy_groups_dict: dict from endpoint. :param trophy_groups: list of TrophyGroupSummary or TrophyGroupSummaryWithProgress :returns: TrophyGroupsSummary containing list of TrophyGroupSummary or TrophyGroupSummaryWithProgress along with some more information. """ return TrophyGroupsSummary( trophy_set_version=trophy_groups_dict.get("trophySetVersion"), trophy_title_name=trophy_groups_dict.get("trophyTitleName"), trophy_title_detail=trophy_groups_dict.get("trophyTitleDetail"), trophy_title_icon_url=trophy_groups_dict.get("trophyTitleIconUrl"), trophy_title_platform={ PlatformType(platform_str) for platform_str in trophy_groups_dict.get( "trophyTitlePlatform", "", ).split(",") }, defined_trophies=TrophySet( **trophy_groups_dict.get( "definedTrophies", {"bronze": 0, "silver": 0, "gold": 0, "platinum": 0}, ), ), trophy_groups=trophy_groups, hidden_flag=trophy_groups_dict.get("hiddenFlag"), progress=trophy_groups_dict.get("progress"), earned_trophies=TrophySet( **trophy_groups_dict.get( "earnedTrophies", {"bronze": 0, "silver": 0, "gold": 0, "platinum": 0}, ), ), last_updated_datetime=iso_format_to_datetime(trophy_groups_dict.get("lastUpdatedDateTime")), )
[docs] def game_title_trophy_groups_summary( self, platform: PlatformType, ) -> TrophyGroupsSummary[TrophyGroupSummary]: """Retrieves the trophy groups for a title and their respective trophy count. This is most commonly seen in games which have expansions where additional trophies are added. :param platform: The platform this title belongs to. :returns: TrophyGroupSummary object containing title and title groups trophy information. :raises PSNAWPNotFoundError: if you don't have any trophies for that game. :raises PSNAWPForbiddenError: If the user's profile is private. """ service_name = platform.get_trophy_service_name() params = {"npServiceName": service_name} try: response = self.authenticator.get( url=f"{BASE_PATH['trophies']}{API_PATH['title_trophy_group'].format(np_communication_id=self.np_communication_id)}", params=params, ).json() except PSNAWPNotFoundError as not_found: raise PSNAWPNotFoundError( "The following user has no trophies for the given game title.", ) from not_found trophy_groups = [TrophyGroupSummary.from_dict(trophy_group) for trophy_group in response.get("trophyGroups", [])] return type(self).trophy_groups_dict_to_obj( response, trophy_groups, )
[docs] def earned_user_trophy_groups_summary( self, account_id: str, platform: PlatformType, ) -> TrophyGroupsSummary[TrophyGroupSummaryWithProgress]: """Retrieves the earned trophy groups for a title and their respective trophy count along with their trophy earned progress. This is most commonly seen in games which have expansions where additional trophies are added. .. warning:: Retrieving the progress of TrophyGroupSummary will require double the number of request because the progress has to be fetched via separate endpoint. :param account_id: The account whose trophy list is being accessed. :param platform: The platform this title belongs to. :returns: TrophyGroupSummary object containing title and title groups trophy information. :raises PSNAWPNotFoundError: if you don't have any trophies for that game. :raises PSNAWPForbiddenError: If the user's profile is private. """ service_name = platform.get_trophy_service_name() params = {"npServiceName": service_name} trophy_groups_metadata = self.authenticator.get( url=f"{BASE_PATH['trophies']}{API_PATH['title_trophy_group'].format(np_communication_id=self.np_communication_id)}", params=params, ).json() trophy_groups_user_data = self.authenticator.get( url=f"{BASE_PATH['trophies']}{API_PATH['user_title_trophy_group'].format(account_id=account_id, np_communication_id=self.np_communication_id)}", params=params, ).json() merged_data: dict[str, Any] = trophy_groups_metadata | trophy_groups_user_data merged_trophy_groups: list[dict[str, Any]] = [ x[0] | x[1] for x in zip( trophy_groups_metadata.get("trophyGroups"), trophy_groups_user_data.get("trophyGroups"), strict=False, ) ] merged_data["trophyGroups"] = merged_trophy_groups trophy_groups = [TrophyGroupSummaryWithProgress.from_dict(trophy_group) for trophy_group in merged_data.get("trophyGroups", [])] return type(self).trophy_groups_dict_to_obj( merged_data, trophy_groups, )