diff --git a/i3pystatus/scores/__init__.py b/i3pystatus/scores/__init__.py index 5eefe3a2..731fd556 100644 --- a/i3pystatus/scores/__init__.py +++ b/i3pystatus/scores/__init__.py @@ -118,11 +118,13 @@ def add_ordinal(number): return f'{number}{suffix}' @staticmethod - def force_int(value): + def zero_fallback(value): try: - return int(value) + int(value) except (TypeError, ValueError): - return 0 + return '0' + else: + return str(value) def get_nested(self, data, expr, callback=None, default=''): if callback is None: @@ -219,7 +221,7 @@ class Scores(Module): .. code-block:: python from i3pystatus import Status - from i3pystatus.scores import mlb, nhl + from i3pystatus.scores import mlb, nhl, nba status = Status() @@ -228,9 +230,11 @@ class Scores(Module): hints={'markup': 'pango'}, colorize_teams=True, favorite_icon='', + team_format='abbreviation', backends=[ mlb.MLB( teams=['CWS', 'SF'], + team_format='name', format_no_games='No games today :(', inning_top='⬆', inning_bottom='⬇', @@ -240,7 +244,6 @@ class Scores(Module): teams=['GSW'], all_games=False, ), - epl.EPL(), ], ) @@ -362,6 +365,7 @@ class Scores(Module): 'shown by the module) when refreshing scores. ' '**NOTE:** Depending on how quickly the update is ' 'performed, the icon may not be displayed.'), + ('team_format', 'One of ``name``, ``abbreviation``, or ``city``'), ) backends = [] @@ -371,6 +375,7 @@ class Scores(Module): colorize_teams = False scroll_arrow = '⬍' refresh_icon = '⟳' + team_format = 'name' output = {'full_text': ''} game_map = {} @@ -417,6 +422,9 @@ def init(self): ) backend.display_order[index] = order_lc + if backend.team_format is None: + backend.team_format = self.team_format + self.condition = threading.Condition() self.thread = threading.Thread(target=self.update_thread, daemon=True) self.thread.start() @@ -566,7 +574,14 @@ def check_scores(self, force=False): self.show_refresh_icon() cur_id = self.current_game_id cur_games = self.current_backend.games.keys() + self.current_backend.check_scores() + for game in self.current_backend.games.values(): + if game['status'] in ('pregame', 'postponed'): + # Allow formatp to conditionally hide the score when game + # hasn't started (or has been postponed) + game['home_score'] = game['away_score'] = '' + if cur_games == self.current_backend.games.keys(): # Set the index to the scroll position of the current game (it # may have changed due to this game or other games changing @@ -623,31 +638,55 @@ def refresh_display(self): else: game = copy.copy(self.current_game) - fstr = str(getattr(self.current_backend, f'format_{game["status"]}')) + # Set the game_status using the formatter + game_status_opt = f'status_{game["status"]}' + try: + game['game_status'] = formatp( + str(getattr(self.current_backend, game_status_opt)), + **game + ) + except AttributeError: + self.logger.error( + f'Unable to find {self.current_backend.name} option ' + f'{game_status_opt}' + ) + game['game_status'] = 'Unknown Status' for team in ('home', 'away'): - abbrev_key = f'{team}_abbrev' + team_abbrev = game[f'{team}_abbreviation'] # Set favorite icon, if applicable game[f'{team}_favorite'] = self.favorite_icon \ - if game[abbrev_key] in self.current_backend.favorite_teams \ + if team_abbrev in self.current_backend.favorite_teams \ else '' - if self.colorize_teams: - # Wrap in Pango markup - color = self.current_backend.team_colors.get( - game.get(abbrev_key) + try: + game[f'{team}_team'] = game[f'{team}_{self.current_backend.team_format}'] + except KeyError: + self.logger.debug( + f'Unable to find {self.current_backend.team_format} ' + f'value, falling back to {team_abbrev}' ) - if color is not None: - for item in ('abbrev', 'city', 'name', 'name_short'): - key = f'{team}_{item}' - if key in game: - game[key] = f'{game[key]}' + game[f'{team}_team'] = team_abbrev + + if self.colorize_teams: + try: + color = self.current_backend.team_colors[team_abbrev] + except KeyError: + pass + else: + for val in ('team', 'name', 'city', 'abbreviation'): + # Wrap in Pango markup + game[f'{team}_{val}'] = ''.join(( + f'', + game[f'{team}_{val}'], + '', + )) game['scroll'] = self.scroll_arrow \ if len(self.current_backend.games) > 1 \ else '' - output = formatp(fstr, **game).strip() + output = formatp(self.current_backend.format, **game).strip() self.output = {'full_text': output, 'color': self.color} diff --git a/i3pystatus/scores/mlb.py b/i3pystatus/scores/mlb.py index 99a7a081..ed60064e 100644 --- a/i3pystatus/scores/mlb.py +++ b/i3pystatus/scores/mlb.py @@ -21,18 +21,16 @@ class MLB(ScoresBackend): .. rubric:: Available formatters - * `{home_name}` — Name of home team - * `{home_city}` — Name of home team's city - * `{home_abbrev}` — 2 or 3-letter abbreviation for home team's city + * `{home_team}` — Depending on the value of the ``team_format`` option, + will contain either the home team's name, abbreviation, or city * `{home_score}` — Home team's current score * `{home_wins}` — Home team's number of wins * `{home_losses}` — Home team's number of losses * `{home_favorite}` — Displays the value for the :py:mod:`.scores` module's ``favorite`` attribute, if the home team is one of the teams being followed. Otherwise, this formatter will be blank. - * `{away_name}` — Name of away team - * `{away_city}` — Name of away team's city - * `{away_abbrev}` — 2 or 3-letter abbreviation for away team's city + * `{away_team}` — Depending on the value of the ``team_format`` option, + will contain either the away team's name, abbreviation, or city * `{away_score}` — Away team's current score * `{away_wins}` — Away team's number of wins * `{away_losses}` — Away team's number of losses @@ -51,6 +49,8 @@ class MLB(ScoresBackend): this formatter will be blank. * `{postponed}` — Reason for postponement, if game has been postponed. Otherwise, this formatter will be blank. + * `{suspended}` — Reason for suspension, if game has been suspended. + Otherwise, this formatter will be blank. * `{extra_innings}` — When a game lasts longer than 9 innings, this formatter will show that number of innings. Otherwise, it will blank. @@ -105,11 +105,17 @@ class MLB(ScoresBackend): ('format_no_games', 'Format used when no tracked games are scheduled ' 'for the current day (does not support formatter ' 'placeholders)'), - ('format_pregame', 'Format used when the game has not yet started'), - ('format_in_progress', 'Format used when the game is in progress'), - ('format_final', 'Format used when the game is complete'), - ('format_postponed', 'Format used when the game has been postponed'), - ('format_suspended', 'Format used when the game has been suspended'), + ('format', 'Format used to display game information'), + ('status_pregame', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has not started '), + ('status_in_progress', 'Format string used for the ``{game_status}`` ' + 'formatter when the game is in progress'), + ('status_final', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has finished'), + ('status_postponed', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has been postponed'), + ('status_suspended', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has been suspended'), ('inning_top', 'Value for the ``{top_bottom}`` formatter when game ' 'is in the top half of an inning'), ('inning_bottom', 'Value for the ``{top_bottom}`` formatter when game ' @@ -118,6 +124,9 @@ class MLB(ScoresBackend): 'codes. If overridden, the passed values will be ' 'merged with the defaults, so it is not necessary to ' 'define all teams if specifying this value.'), + ('team_format', 'One of ``name``, ``abbreviation``, or ``city``. If ' + 'not specified, takes the value from the ``scores`` ' + 'module.'), ('date', 'Date for which to display game scores, in **YYYY-MM-DD** ' 'format. If unspecified, the current day\'s games will be ' 'displayed starting at 10am Eastern time, with last ' @@ -169,15 +178,16 @@ class MLB(ScoresBackend): } _valid_teams = [x for x in _default_colors] - _valid_display_order = ['in_progress', 'suspended', 'final', 'postponed', 'pregame'] + _valid_display_order = ['in_progress', 'suspended', 'final', 'pregame', 'postponed'] display_order = _valid_display_order format_no_games = 'MLB: No games' - format_pregame = '[{scroll} ]MLB: [{away_favorite} ]{away_abbrev} ({away_wins}-{away_losses}) at [{home_favorite} ]{home_abbrev} ({home_wins}-{home_losses}) {start_time:%H:%M %Z}[ ({delay} Delay)]' - format_in_progress = '[{scroll} ]MLB: [{away_favorite} ]{away_abbrev} {away_score}, [{home_favorite} ]{home_abbrev} {home_score} ({top_bottom} {inning}, {outs} Out)[ ({delay} Delay)]' - format_final = '[{scroll} ]MLB: [{away_favorite} ]{away_abbrev} {away_score} ({away_wins}-{away_losses}) at [{home_favorite} ]{home_abbrev} {home_score} ({home_wins}-{home_losses}) (Final[/{extra_innings}])' - format_postponed = '[{scroll} ]MLB: [{away_favorite} ]{away_abbrev} ({away_wins}-{away_losses}) at [{home_favorite} ]{home_abbrev} ({home_wins}-{home_losses}) (PPD: {postponed})' - format_suspended = '[{scroll} ]MLB: [{away_favorite} ]{away_abbrev} {away_score} ({away_wins}-{away_losses}) at [{home_favorite} ]{home_abbrev} {home_score} ({home_wins}-{home_losses}) (Suspended: {suspended})' + format = '[{scroll} ]MLB: [{away_favorite} ]{away_team} [{away_score} ]({away_wins}-{away_losses}) at [{home_favorite} ]{home_team} [{home_score} ]({home_wins}-{home_losses}) {game_status}' + status_pregame = '{start_time:%H:%M %Z}[ ({delay} Delay)]' + status_in_progress = '({top_bottom} {inning}, {outs} Out)[ ({delay} Delay)]' + status_final = '(Final[/{extra_innings}])' + status_postponed = '(PPD: {postponed})' + status_suspended = '(Suspended: {suspended})' inning_top = 'Top' inning_bottom = 'Bot' team_colors = _default_colors @@ -185,6 +195,9 @@ class MLB(ScoresBackend): scoreboard_url = SCOREBOARD_URL api_url = API_URL + # These will inherit from the Scores class if not overridden + team_format = None + @require(internet) def check_scores(self): self.get_api_date() @@ -252,7 +265,7 @@ def process_game(self, game): ret[f'{team}_name'] = self.get_nested( team_data, 'team:teamName') - ret[f'{team}_abbrev'] = self.get_nested( + ret[f'{team}_abbreviation'] = self.get_nested( team_data, 'team:abbreviation') @@ -268,7 +281,7 @@ def process_game(self, game): ret[f'{team}_score'] = self.get_nested( linescore, f'teams:{team}:runs', - default=0) + default='0') for key in ('delay', 'postponed', 'suspended'): ret[key] = '' diff --git a/i3pystatus/scores/nba.py b/i3pystatus/scores/nba.py index 3dc8a065..a0b030d5 100644 --- a/i3pystatus/scores/nba.py +++ b/i3pystatus/scores/nba.py @@ -18,9 +18,8 @@ class NBA(ScoresBackend): .. rubric:: Available formatters - * `{home_name}` — Name of home team - * `{home_city}` — Name of home team's city - * `{home_abbrev}` — 3-letter abbreviation for home team's city + * `{home_team}` — Depending on the value of the ``team_format`` option, + will contain either the home team's name, abbreviation, or city * `{home_score}` — Home team's current score * `{home_wins}` — Home team's number of wins * `{home_losses}` — Home team's number of losses @@ -29,9 +28,8 @@ class NBA(ScoresBackend): * `{home_favorite}` — Displays the value for the :py:mod:`.scores` module's ``favorite`` attribute, if the home team is one of the teams being followed. Otherwise, this formatter will be blank. - * `{away_name}` — Name of away team - * `{away_city}` — Name of away team's city - * `{away_abbrev}` — 2 or 3-letter abbreviation for away team's city + * `{away_team}` — Depending on the value of the ``team_format`` option, + will contain either the away team's name, abbreviation, or city * `{away_score}` — Away team's current score * `{away_wins}` — Away team's number of wins * `{away_losses}` — Away team's number of losses @@ -99,14 +97,22 @@ class NBA(ScoresBackend): ('format_no_games', 'Format used when no tracked games are scheduled ' 'for the current day (does not support formatter ' 'placeholders)'), - ('format_pregame', 'Format used when the game has not yet started'), - ('format_in_progress', 'Format used when the game is in progress'), - ('format_final', 'Format used when the game is complete'), - ('format_postponed', 'Format used when the game has been postponed'), + ('format', 'Format used to display game information'), + ('status_pregame', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has not started '), + ('status_in_progress', 'Format string used for the ``{game_status}`` ' + 'formatter when the game is in progress'), + ('status_final', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has finished'), + ('status_postponed', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has been postponed'), ('team_colors', 'Dictionary mapping team abbreviations to hex color ' 'codes. If overridden, the passed values will be ' 'merged with the defaults, so it is not necessary to ' 'define all teams if specifying this value.'), + ('team_format', 'One of ``name``, ``abbreviation``, or ``city``. If ' + 'not specified, takes the value from the ``scores`` ' + 'module.'), ('date', 'Date for which to display game scores, in **YYYY-MM-DD** ' 'format. If unspecified, the current day\'s games will be ' 'displayed starting at 10am Eastern time, with last ' @@ -155,18 +161,22 @@ class NBA(ScoresBackend): } _valid_teams = [x for x in _default_colors] - _valid_display_order = ['in_progress', 'final', 'postponed', 'pregame'] + _valid_display_order = ['in_progress', 'final', 'pregame', 'postponed'] display_order = _valid_display_order format_no_games = 'NBA: No games' - format_pregame = '[{scroll} ]NBA: [{away_favorite} ][{away_seed} ]{away_abbrev} ({away_wins}-{away_losses}) at [{home_favorite} ][{home_seed} ]{home_abbrev} ({home_wins}-{home_losses}) {start_time:%H:%M %Z}' - format_in_progress = '[{scroll} ]NBA: [{away_favorite} ]{away_abbrev} {away_score}[ ({away_power_play})], [{home_favorite} ]{home_abbrev} {home_score}[ ({home_power_play})] ({time_remaining} {quarter})' - format_postponed = '[{scroll} ]NBA: [{away_favorite} ]{away_abbrev} ({away_wins}-{away_losses}) at [{home_favorite} ]{home_abbrev} ({home_wins}-{home_losses}) PPD' - format_final = '[{scroll} ]NBA: [{away_favorite} ]{away_abbrev} {away_score} ({away_wins}-{away_losses}) at [{home_favorite} ]{home_abbrev} {home_score} ({home_wins}-{home_losses}) (Final[/{overtime}])' + format = '[{scroll} ]NBA: [{away_favorite} ][{away_seed} ]{away_team} [{away_score} ]({away_wins}-{away_losses}) at [{home_favorite} ][{home_seed} ]{home_team} [{home_score} ]({home_wins}-{home_losses}) {game_status}' + status_pregame = '{start_time:%H:%M %Z}' + status_in_progress = '({time_remaining} {quarter})' + status_final = '(Final[/{overtime}])' + status_postponed = 'PPD' team_colors = _default_colors live_url = LIVE_URL api_url = API_URL + # These will inherit from the Scores class if not overridden + team_format = None + def check_scores(self): self.get_api_date() @@ -257,20 +267,20 @@ def _update(ret_key, game_key=None, callback=None, default='?'): for key in ('home', 'away'): team_key = f'{key}Team' _update(f'{key}_score', f'{team_key}:score', - callback=self.force_int, default=0) + callback=self.zero_fallback, default='0') _update(f'{key}_city', f'{team_key}:teamCity') _update(f'{key}_name', f'{team_key}:teamName') - _update(f'{key}_abbrev', f'{team_key}:teamTricode') + _update(f'{key}_abbreviation', f'{team_key}:teamTricode') if 'playoffs' in game: _update(f'{key}_wins', f'playoffs:{key}_wins', - callback=self.force_int, default=0) + callback=self.zero_fallback, default='0') _update(f'{key}_seed', f'playoffs:{key}_seed', - callback=self.force_int, default=0) + callback=self.zero_fallback, default='0') else: _update(f'{key}_wins', f'{team_key}:wins', - callback=self.force_int, default=0) + callback=self.zero_fallback, default='0') _update(f'{key}_losses', f'{team_key}:losses', - callback=self.force_int, default=0) + callback=self.zero_fallback, default='0') ret[f'{key}_seed'] = '' if 'playoffs' in game: diff --git a/i3pystatus/scores/nhl.py b/i3pystatus/scores/nhl.py index 17b96498..783871f6 100644 --- a/i3pystatus/scores/nhl.py +++ b/i3pystatus/scores/nhl.py @@ -21,9 +21,8 @@ class NHL(ScoresBackend): .. rubric:: Available formatters - * `{home_name}` — Name of home team - * `{home_city}` — Name of home team's city - * `{home_abbrev}` — 3-letter abbreviation for home team's city + * `{home_team}` — Depending on the value of the ``team_format`` option, + will contain either the home team's name, abbreviation, or city * `{home_score}` — Home team's current score * `{home_wins}` — Home team's number of wins * `{home_losses}` — Home team's number of losses @@ -33,9 +32,8 @@ class NHL(ScoresBackend): followed. Otherwise, this formatter will be blank. * `{home_empty_net}` — Shows the value from the ``empty_net`` parameter when the home team's net is empty. - * `{away_name}` — Name of away team - * `{away_city}` — Name of away team's city - * `{away_abbrev}` — 2 or 3-letter abbreviation for away team's city + * `{away_team}` — Depending on the value of the ``team_format`` option, + will contain either the away team's name, abbreviation, or city * `{away_score}` — Away team's current score * `{away_wins}` — Away team's number of wins * `{away_losses}` — Away team's number of losses @@ -74,8 +72,7 @@ class NHL(ScoresBackend): backends=[ nhl.NHL( favorite_teams=['CHI'], - format_pregame = '[{scroll} ]NHL: [{away_favorite} ]{away_abbrev} ({away_wins}) at [{home_favorite} ]{home_abbrev} ({home_wins}) {start_time:%H:%M %Z}', - format_final = '[{scroll} ]NHL: [{away_favorite} ]{away_abbrev} {away_score} ({away_wins}) at [{home_favorite} ]{home_abbrev} {home_score} ({home_wins}) (Final[/{overtime}])', + format='[{scroll} ]NHL: [{away_favorite} ]{away_team} ({away_wins}) at [{home_favorite} ]{home_team} ({home_wins}) {game_status}' ), ], ) @@ -133,10 +130,15 @@ class NHL(ScoresBackend): ('format_no_games', 'Format used when no tracked games are scheduled ' 'for the current day (does not support formatter ' 'placeholders)'), - ('format_pregame', 'Format used when the game has not yet started'), - ('format_in_progress', 'Format used when the game is in progress'), - ('format_final', 'Format used when the game is complete'), - ('format_postponed', 'Format used when the game has been postponed'), + ('format', 'Format used to display game information'), + ('status_pregame', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has not started '), + ('status_in_progress', 'Format string used for the ``{game_status}`` ' + 'formatter when the game is in progress'), + ('status_final', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has finished'), + ('status_postponed', 'Format string used for the ``{game_status}`` ' + 'formatter when the game has been postponed'), ('empty_net', 'Value for the ``{away_empty_net}`` or ' '``{home_empty_net}`` formatter when the net is empty. ' 'When the net is not empty, these formatters will be ' @@ -145,6 +147,9 @@ class NHL(ScoresBackend): 'codes. If overridden, the passed values will be ' 'merged with the defaults, so it is not necessary to ' 'define all teams if specifying this value.'), + ('team_format', 'One of ``name``, ``abbreviation``, or ``city``. If ' + 'not specified, takes the value from the ``scores`` ' + 'module.'), ('date', 'Date for which to display game scores, in **YYYY-MM-DD** ' 'format. If unspecified, the current day\'s games will be ' 'displayed starting at 10am Eastern time, with last ' @@ -198,20 +203,24 @@ class NHL(ScoresBackend): } _valid_teams = [x for x in _default_colors] - _valid_display_order = ['in_progress', 'final', 'postponed', 'pregame'] + _valid_display_order = ['in_progress', 'final', 'pregame', 'postponed'] display_order = _valid_display_order format_no_games = 'NHL: No games' - format_pregame = '[{scroll} ]NHL: [{away_favorite} ]{away_abbrev} ({away_wins}-{away_losses}-{away_otl}) at [{home_favorite} ]{home_abbrev} ({home_wins}-{home_losses}-{home_otl}) {start_time:%H:%M %Z}' - format_in_progress = '[{scroll} ]NHL: [{away_favorite} ]{away_abbrev} {away_score}[ ({away_power_play})][ ({away_empty_net})], [{home_favorite} ]{home_abbrev} {home_score}[ ({home_power_play})][ ({home_empty_net})] ({time_remaining} {period})' - format_final = '[{scroll} ]NHL: [{away_favorite} ]{away_abbrev} {away_score} ({away_wins}-{away_losses}-{away_otl}) at [{home_favorite} ]{home_abbrev} {home_score} ({home_wins}-{home_losses}-{home_otl}) (Final[/{overtime}])' - format_postponed = '[{scroll} ]NHL: [{away_favorite} ]{away_abbrev} ({away_wins}-{away_losses}-{away_otl}) at [{home_favorite} ]{home_abbrev} ({home_wins}-{home_losses}-{home_otl}) PPD' + format = '[{scroll} ]NHL: [{away_favorite} ]{away_team} [{away_score} ]({away_wins}-{away_losses}-{away_otl}) at [{home_favorite} ]{home_team} [{home_score} ]({home_wins}-{home_losses}-{home_otl}) {game_status}' + status_pregame = '{start_time:%H:%M %Z}' + status_in_progress = '({time_remaining} {period})' + status_final = '(Final[/{overtime}])' + status_postponed = 'PPD' empty_net = 'EN' team_colors = _default_colors live_url = LIVE_URL scoreboard_url = SCOREBOARD_URL api_url = API_URL + # These will inherit from the Scores class if not overridden + team_format = None + @require(internet) def check_scores(self): self.get_api_date() @@ -265,48 +274,48 @@ def process_game(self, game): pp_strength = self.get_nested(linescore, 'powerPlayStrength') for team in ('away', 'home'): - team_data = self.get_nested(game, 'teams:%s' % team, default={}) + team_data = self.get_nested(game, f'teams:{team}', default={}) if team == 'home': ret['venue'] = self.get_nested(team_data, 'venue:name') - ret['%s_score' % team] = self.get_nested( + ret[f'{team}_score'] = self.get_nested( team_data, 'score', - callback=self.force_int, + callback=self.zero_fallback, default=0) - ret['%s_wins' % team] = self.get_nested( + ret[f'{team}_wins'] = self.get_nested( team_data, 'leagueRecord:wins', - callback=self.force_int, + callback=self.zero_fallback, default=0) - ret['%s_losses' % team] = self.get_nested( + ret[f'{team}_losses'] = self.get_nested( team_data, 'leagueRecord:losses', - callback=self.force_int, + callback=self.zero_fallback, default=0) - ret['%s_otl' % team] = self.get_nested( + ret[f'{team}_otl'] = self.get_nested( team_data, 'leagueRecord:ot', - callback=self.force_int, + callback=self.zero_fallback, default=0) - ret['%s_city' % team] = self.get_nested( + ret[f'{team}_city'] = self.get_nested( team_data, 'team:shortName') - ret['%s_name' % team] = self.get_nested( + ret[f'{team}_name'] = self.get_nested( team_data, 'team:teamName') - ret['%s_abbrev' % team] = self.get_nested( + ret[f'{team}_abbreviation'] = self.get_nested( team_data, 'team:abbreviation') - ret['%s_power_play' % team] = self.get_nested( + ret[f'{team}_power_play'] = self.get_nested( linescore, - 'teams:%s:powerPlay' % team, + f'teams:{team}:powerPlay', callback=lambda x: pp_strength if x and pp_strength != 'Even' else '') - ret['%s_empty_net' % team] = self.get_nested( + ret[f'{team}_empty_net'] = self.get_nested( linescore, - 'teams:%s:goaliePulled' % team, + f'teams:{team}:goaliePulled', callback=lambda x: self.empty_net if x else '') if game.get('gameType') == 'P':