3
3
import json
4
4
from contextlib import suppress
5
5
from pathlib import Path
6
- from typing import Literal , NamedTuple , NotRequired , TypedDict
6
+ from typing import Literal , NotRequired , TypedDict
7
7
8
8
from discord import Embed , HTTPException , Message , Reaction , User
9
9
from discord .ext import commands
10
- from discord .ext .commands import Cog as DiscordCog , Command , Context
10
+ from discord .ext .commands import Cog as DiscordCog , Context
11
11
from pydis_core .utils .logging import get_logger
12
12
13
13
from bot import constants
14
14
from bot .bot import Bot
15
15
16
-
17
- class Cog (NamedTuple ):
18
- """Show information about a Cog's name, description and commands."""
19
-
20
- name : str
21
- description : str
22
- commands : list [Command ]
23
-
24
-
25
16
log = get_logger (__name__ )
26
17
27
-
28
18
class GameInfo (TypedDict ):
29
19
"""A dictionary containing the game information. Used in `available_games.json`."""
30
20
@@ -116,8 +106,8 @@ def __init__(
116
106
self .game_info = None
117
107
if game_code_or_index :
118
108
self .game_code = self ._parse_game_code (game_code_or_index )
119
- self .game_data = self ._get_game_data ()
120
109
self .game_info = self ._get_game_info ()
110
+ self .game_data = self ._get_game_data ()
121
111
122
112
# store relevant discord info
123
113
self .author = ctx .author
@@ -142,10 +132,13 @@ def _parse_game_code(self, game_code_or_index: str) -> str:
142
132
# sanitize the game code to prevent directory traversal attacks.
143
133
game_code = Path (game_code_or_index ).name
144
134
145
- # convert index to game code if it's a number
135
+ # convert index to game code if it's a valid number that is in range.
136
+ # otherwise, return the game code as is, assuming it's a valid game code.
137
+ # if game code is not valid, errors will be raised later when trying to load the game info.
146
138
try :
147
139
index = int (game_code_or_index )
148
- game_code = AVAILABLE_GAMES [index - 1 ]["id" ]
140
+ if 1 <= index <= len (AVAILABLE_GAMES ):
141
+ game_code = AVAILABLE_GAMES [index - 1 ]["id" ]
149
142
except (ValueError , IndexError ):
150
143
pass
151
144
@@ -162,7 +155,11 @@ def _get_game_data(self) -> GameData | None:
162
155
)
163
156
return game_data
164
157
except FileNotFoundError :
165
- raise GameCodeNotFoundError (f'Game code "{ game_code } " not found.' )
158
+ log .error (
159
+ "Game located in `available_games.json`, but game data not found. Game code: %s" ,
160
+ game_code
161
+ )
162
+ raise GameCodeNotFoundError (f"Game code `{ game_code } ` not found." )
166
163
167
164
def _get_game_info (self ) -> GameInfo :
168
165
"""Returns the game info for the given game code."""
@@ -171,10 +168,7 @@ def _get_game_info(self) -> GameInfo:
171
168
try :
172
169
return AVAILABLE_GAMES_DICT [game_code ]
173
170
except KeyError :
174
- log .error (
175
- "Game data retrieved, but game info not found. Did you forget to add it to `available_games.json`?"
176
- )
177
- raise GameCodeNotFoundError (f'Game code "{ game_code } " not found.' )
171
+ raise GameCodeNotFoundError (f"Game code `{ game_code } ` not found." )
178
172
179
173
async def notify_timeout (self ) -> None :
180
174
"""Notifies the user that the session has timed out."""
@@ -260,15 +254,15 @@ async def prepare(self) -> None:
260
254
await self .send_available_game_codes ()
261
255
262
256
263
- def add_reactions (self ) -> None :
257
+ async def add_reactions (self ) -> None :
264
258
"""Adds the relevant reactions to the message based on if options are available in the current room."""
265
259
if self .is_in_ending_room :
266
260
return
267
261
268
262
pickable_emojis = [option ["emoji" ] for option in self .available_options ]
269
263
270
264
for reaction in pickable_emojis :
271
- self ._bot . loop . create_task ( self . message .add_reaction (reaction ) )
265
+ await self .message .add_reaction (reaction )
272
266
273
267
def _format_room_data (self , room_data : RoomData ) -> str :
274
268
"""Formats the room data into a string for the embed description."""
@@ -315,7 +309,7 @@ async def update_message(self, room_id: str) -> None:
315
309
if self .is_in_ending_room :
316
310
await self .stop ()
317
311
else :
318
- self .add_reactions ()
312
+ await self .add_reactions ()
319
313
320
314
@classmethod
321
315
async def start (cls , ctx : Context , game_code_or_index : str | None = None ) -> "GameSession" :
0 commit comments