"""File for Category class.""" import json from classes.score import Score, ScoreTime # pylint: disable=import-error class Category: """Stores a category's information and relative scores.""" def __init__(self, name: str) -> None: """ Default constructor for Category class. Creates empty category and populates with defaults. Args: name (str): Category's name """ self._name: str = name self._ascending: bool = False self._time_record: bool = False self._scores_map: dict = {} def __str__(self) -> str: """ Returns Category class as a string for printing. Returns: str: Category class as a string """ return self.to_str() @classmethod def from_dict(cls, name: str, data: dict): """ Creates a Category class from the passed data. Args: name (str): Category name data (dict): Rest of Category data in dictionary format Returns: Category: Populated Category object """ category = cls(name) category.ascending = data["ascending"] category.time_record = data["time_record"] for user, score in data["scores"].items(): if category.time_record: score_obj: ScoreTime = ScoreTime(user) score_obj.value = float(score) category.add_score(score_obj) else: score_obj: Score = Score(user) score_obj.value = int(score) category.add_score(score_obj) return category @property def ascending(self) -> bool: """ Getter for is ascending. Returns: bool: is ascending """ return self._ascending @ascending.setter def ascending(self, ascending: bool) -> None: """ Setter for is ascending. Args: ascending (bool): is ascending """ self._ascending = ascending @property def name(self) -> str: """ Getter for name. Returns: str: name """ return self._name @property def time_record(self) -> bool: """ Getter for is time record. Returns: bool: is time record """ return self._time_record @time_record.setter def time_record(self, time_record: bool) -> None: """ Setter for is time record. Args: time_record (bool): is time record """ self._time_record = time_record @property def scores(self) -> "list[Score]": """ Getter for Scores list. Returns: list[Score]: List of Scores in this Category """ return self._scores_map.values() def add_score(self, score: Score) -> None: """ Adds score to dictionary storage map. Sorts dictionary by score value. Args: score (Score): Score to be added """ if score.user in self._scores_map: self._scores_map[score.user].value = score.value else: self._scores_map[score.user] = score self._scores_map = dict(sorted(self._scores_map.items(), key=lambda x: x[1].value, reverse=not self.ascending)) def clear(self) -> None: """ Clears all Scores tracked in score map. This is a test function and shouldn't really be used. """ self._scores_map.clear() def get_users(self) -> "list[str]": """ Returns list of users in this category. Returns: list[str]: List of all users in category. """ return self._scores_map.keys() def get_user_score(self, user: str) -> Score: """ Gets a user's score. Returns None if user is not found. Args: user (str): Name of score to find Returns: Score: User's Score or None """ if user in self._scores_map: return self._scores_map[user] return None def remove_score(self, user: str) -> Score: """ Removes a user's score from dictionary storage. Args: user (str): user whose score to remove Returns: Score: User's Score or None """ if user in self._scores_map: return self._scores_map.pop(user) return None def to_dict(self) -> dict: """ Saves category data as a python dictionary. Does not include category name. It should be the key of above data structure. Returns: dict: Category class in dictionary format """ data = {} data["ascending"] = self.ascending data["time_record"] = self.time_record data["scores"] = {} for score in self.scores: data["scores"][score.user] = score.value return data def to_str(self) -> str: """ Returns Category object as a string. Returns: str: string of json representation of Category """ return json.dumps(self.to_dict(), indent=4)