Skip to content

Commit 7c26803

Browse files
committed
rabbithole of type checker appeasement
1 parent c50bed6 commit 7c26803

11 files changed

Lines changed: 72 additions & 57 deletions

File tree

fred/cogs/crashes.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ async def make_sml_version_message(self, game_version: int = 0, sml: str = "", *
7878
if latest_compatible_sml != sml_versions[0]:
7979
msg += "\nAlso, your game itself may need an update!"
8080
return CrashResponse("Outdated SML!", msg, inline=True)
81-
else:
82-
return None
81+
return None
8382

8483
# fmt: off
8584
_QUERY_TEMPLATE: Final[str] = """
@@ -406,8 +405,7 @@ async def process_message(self, message: Message) -> bool:
406405
embed = createembed.crashes(filtered_responses)
407406
embed.set_author(
408407
name=f"Automated responses for {message.author.global_name or message.author.display_name} ({message.author.id})",
409-
icon_url=message.author.avatar and message.author.avatar.url,
410-
# defaults to None if no avatar, like mircea
408+
icon_url=message.author.display_avatar.url,
411409
)
412410
await self.bot.reply_to_msg(message, embed=embed, propagate_reply=False, files=resp_files)
413411
return True
@@ -519,19 +517,19 @@ def update_from_fg_log(self, log_file: IO[bytes]):
519517

520518
info = self._get_fg_log_details(log_file)
521519

522-
if sml_version := info.get("sml"):
520+
if sml_version := info.get("sml", ""):
523521
if self.sml_version and self.sml_version != sml_version:
524522
self.mismatches.append(f"SML Version ({sml_version})")
525523
else:
526524
self.sml_version = sml_version
527525

528-
if game_version := info.get("game_version"):
526+
if game_version := info.get("game_version", ""):
529527
if self.game_version and int(float(self.game_version)) != int(float(game_version)):
530528
self.mismatches.append(f"Game Version ({game_version})")
531529
else:
532530
self.game_version = game_version
533531

534-
if path := info.get("path"):
532+
if path := info.get("path", ""):
535533
if self.game_path:
536534
p1 = path.replace("\\", "/")
537535
p2 = self.game_path.replace("\\", "/")
@@ -543,13 +541,13 @@ def update_from_fg_log(self, log_file: IO[bytes]):
543541
else:
544542
self.game_path = path
545543

546-
if launcher := info.get("launcher"):
544+
if launcher := info.get("launcher", ""):
547545
if self.game_launcher_id and self.game_launcher_id.lower() != launcher.lower():
548546
self.mismatches.append(f"Launcher ID: {launcher}")
549547
else:
550548
self.game_launcher_id = launcher
551549

552-
if cli := info.get("cli"):
550+
if cli := info.get("cli", ""):
553551
if self.game_command_line:
554552
self.game_command_line += cli
555553

@@ -591,10 +589,10 @@ def _get_fg_log_details(log_file: IO[bytes]):
591589
info |= match.groupdict()
592590
break
593591

594-
if cl := info.get("game_version"):
592+
if cl := info.get("game_version", ""):
595593
info["game_version"] = int(cl)
596594

597-
if cli := info.get("cli"):
595+
if cli := info.get("cli", ""):
598596
info["cli"] = filter_epic_commandline(cli)
599597

600598
return info

fred/cogs/levelling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from __future__ import annotations
22

3+
import math
34
from datetime import *
45

5-
import math
66
from nextcord import DMChannel, Message, Guild
77

88
from .. import config

fred/cogs/welcome.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from nextcord import Member
1+
from nextcord import Member, User
22

33
from .. import config
44
from ..libraries import common
@@ -12,7 +12,7 @@ async def on_member_join(self, member: Member):
1212

1313
await self.send_welcome_message(member)
1414

15-
async def send_welcome_message(self, member: Member):
15+
async def send_welcome_message(self, member: Member | User):
1616
if welcome := config.Misc.fetch("welcome_message"):
1717
self.logger.info("Sending the welcome message to a new member", extra=common.user_info(member))
1818
await self.bot.send_safe_direct_message(member, welcome)

fred/config.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import os
44
import pathlib
55
from numbers import Number
6-
from typing import Optional, Any
6+
from typing import Optional, Any, TypedDict
77

88
import nextcord
99
from sqlobject import SQLObject, IntCol, BoolCol, JSONCol, BigIntCol, StringCol, FloatCol, sqlhub
@@ -84,7 +84,7 @@ def fetch(user_id: int) -> Users:
8484
return Users.selectBy(user_id=user_id).getOne(None)
8585

8686
@staticmethod
87-
def create_if_missing(user: nextcord.User) -> Users:
87+
def create_if_missing(user: nextcord.User | nextcord.Member) -> Users:
8888
return Users.selectBy(user_id=user.id).getOne(False) or Users(user_id=user.id)
8989

9090

@@ -112,26 +112,34 @@ def check(channel_id: int) -> bool:
112112
return bool(MediaOnlyChannels.selectBy(channel_id=channel_id).getOne(False))
113113

114114

115-
type CommandsOrCrashesDict = dict[str, str | StringCol]
115+
class CommandsDict(TypedDict):
116+
name: str
117+
content: str
118+
attachment: str | None
119+
120+
121+
type CrashesDict = dict[str, str]
116122

117123

118124
class Commands(SQLObject):
119125
name = StringCol()
120126
content = StringCol()
121127
attachment = StringCol(default=None)
122128

123-
def as_dict(self) -> CommandsOrCrashesDict:
124-
return dict(name=self.name, content=self.content, attachment=self.attachment)
129+
def as_dict(self) -> CommandsDict:
130+
return dict(
131+
name=str(self.name), content=str(self.content), attachment=str(self.attachment) if self.attachment else None
132+
)
125133

126134
@staticmethod
127-
def fetch(name: str) -> Optional[CommandsOrCrashesDict]:
135+
def fetch(name: str) -> Optional[CommandsDict]:
128136
query: Optional[Commands]
129137
if query := Commands.selectBy(name=name.lower()).getOne(None):
130138
return query.as_dict()
131139
return None
132140

133141
@classmethod
134-
def fetch_by(cls, col: str, val: str) -> Optional[CommandsOrCrashesDict]:
142+
def fetch_by(cls, col: str, val: str) -> Optional[CommandsDict]:
135143
# used by the search command to get a specific value if possible
136144
col, val = col.lower(), val.lower()
137145
if not isinstance(getattr(cls, col, None), property):
@@ -143,7 +151,7 @@ def fetch_by(cls, col: str, val: str) -> Optional[CommandsOrCrashesDict]:
143151
return query.as_dict()
144152

145153
@staticmethod
146-
def fetch_all() -> list[CommandsOrCrashesDict]:
154+
def fetch_all() -> list[CommandsDict]:
147155
query = Commands.selectBy()
148156
return [cmd.as_dict() for cmd in query.lazyIter()]
149157

@@ -153,18 +161,18 @@ class Crashes(SQLObject):
153161
crash = StringCol()
154162
response = StringCol()
155163

156-
def as_dict(self) -> CommandsOrCrashesDict:
157-
return dict(name=self.name, response=self.response, crash=self.crash)
164+
def as_dict(self) -> CrashesDict:
165+
return dict(name=str(self.name), response=str(self.response), crash=str(self.crash))
158166

159167
@staticmethod
160-
def fetch(name: str) -> Optional[CommandsOrCrashesDict]:
168+
def fetch(name: str) -> Optional[CrashesDict]:
161169
query: Optional[Crashes]
162170
if (query := Crashes.selectBy(name=name.lower()).getOne(None)) is not None:
163171
return query.as_dict()
164172
return None
165173

166174
@classmethod
167-
def fetch_by(cls, col: str, val: str) -> Optional[CommandsOrCrashesDict]:
175+
def fetch_by(cls, col: str, val: str) -> Optional[CrashesDict]:
168176
col, val = col.lower(), val.lower()
169177
if not isinstance(getattr(cls, col), property):
170178
raise KeyError("This is not a valid column!")
@@ -175,7 +183,7 @@ def fetch_by(cls, col: str, val: str) -> Optional[CommandsOrCrashesDict]:
175183
return query.as_dict()
176184

177185
@staticmethod
178-
def fetch_all() -> list[CommandsOrCrashesDict]:
186+
def fetch_all() -> list[CrashesDict]:
179187
query = Crashes.selectBy()
180188
return [crash.as_dict() for crash in query.lazyIter()]
181189

fred/fred.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ def __init__(self, *args, **kwargs):
5353
self.setup_cogs()
5454
FredHelpEmbed.setup()
5555
self.owo = False
56-
self.web_session: aiohttp.ClientSession = ...
56+
self.web_session: aiohttp.ClientSession = ... # type: ignore
5757
self.loop = asyncio.get_event_loop()
5858
self.executor = ThreadPoolExecutor()
59-
self.error_channel = int(chan) if (chan := config.Misc.fetch("error_channel")) else 748229790825185311
59+
self.error_channel: int = int(config.Misc.fetch("error_channel")) or 748229790825185311 # type: ignore
6060

6161
async def start(self, *args, **kwargs):
6262
async with aiohttp.ClientSession() as session:
@@ -146,7 +146,10 @@ async def on_error(self, event_method: str, *args, **kwargs):
146146
# error_embed = nextcord.Embed(colour=nextcord.Colour.red(), title=error_meta, description=full_error)
147147
# error_embed.set_author(name=fred_str)
148148

149-
await self.get_channel(self.error_channel).send(f"**{fred_str}**\n{error_meta}\n```py\n{full_error}```")
149+
error_channel = self.get_partial_messageable(self.error_channel)
150+
if error_channel is None:
151+
raise RuntimeError("Error channel unreachable! Value: " + str(self.error_channel))
152+
await error_channel.send(f"**{fred_str}**\n{error_meta}\n```py\n{full_error}```")
150153

151154
async def githook_send(self, data: dict):
152155
self.logger.info("Handling GitHub payload", extra={"data": data})
@@ -156,7 +159,7 @@ async def githook_send(self, data: dict):
156159
self.logger.info("Non-supported Payload received")
157160
else:
158161
self.logger.info("GitHub payload was supported, sending an embed")
159-
channel = self.get_channel(config.Misc.fetch("githook_channel"))
162+
channel = self.get_partial_messageable(config.Misc.fetch("githook_channel")) # type: ignore
160163
await channel.send(content=None, embed=embed)
161164

162165
async def _send_safe_direct_message_internal(
@@ -189,21 +192,19 @@ async def _send_safe_direct_message_internal(
189192
return False
190193

191194
try:
195+
dm_channel = user.dm_channel or await user.create_dm()
192196

193-
if not user.dm_channel:
194-
await user.create_dm()
195-
196-
if not embed:
197+
if not embed and content is not None:
197198
embed = createembed.DM(content)
198199
content = None
199200

200-
await self.safe_send(user.dm_channel, content, embed=embed, **kwargs)
201+
await self.safe_send(dm_channel, content, embed=embed, **kwargs)
201202
return True
202203
except Exception: # noqa
203204
self.logger.error(f"DMs: Failed to DM, reason: \n{traceback.format_exc()}")
204205
return False
205206

206-
async def send_safe_direct_message(self, user: nextcord.User, content=None, **kwargs) -> bool:
207+
async def send_safe_direct_message(self, user: nextcord.User | nextcord.Member, content=None, **kwargs) -> bool:
207208
user_meta = config.Users.create_if_missing(user)
208209
try:
209210
return await self._send_safe_direct_message_internal(user, content, user_meta=user_meta, **kwargs)
@@ -213,18 +214,18 @@ async def send_safe_direct_message(self, user: nextcord.User, content=None, **kw
213214

214215
@staticmethod
215216
async def safe_send(
216-
chan: nextcord.TextChannel | nextcord.DMChannel,
217+
to: nextcord.PartialMessageable | nextcord.abc.Messageable,
217218
content: Optional[str],
218219
*,
219220
files: Optional[list[nextcord.File]] = None,
220221
**kwargs,
221222
) -> nextcord.Message:
222223
if content is not None and len(content) > 2000:
223-
files = files or []
224+
files: list[nextcord.File] = files or []
224225
files.append(text2file(content, filename="long-message.txt"))
225226
content = "Message too long, converted to text file!"
226227

227-
return await chan.send(content, files=files, **kwargs)
228+
return await to.send(content=content, files=files, **kwargs)
228229

229230
async def reply_to_msg(
230231
self,
@@ -268,7 +269,8 @@ def check(message2: nextcord.Message):
268269
return (message2.author == message.author) and (message2.channel == message.channel)
269270

270271
try:
271-
response: nextcord.Message = await self.wait_for("message", timeout=120.0, check=check)
272+
maybe_response = self.wait_for("message", timeout=120.0, check=check)
273+
response: nextcord.Message = await maybe_response
272274
except asyncio.TimeoutError:
273275
await self.reply_to_msg(message, "Timed out and aborted after 120 seconds.")
274276
raise asyncio.TimeoutError
@@ -317,7 +319,7 @@ async def on_message(self, message: nextcord.Message):
317319
if not removed:
318320
before, space, after = message.content.partition(" ")
319321
# if the prefix is the only thing before the space then this isn't a command
320-
if before.startswith(self.command_prefix) and len(before) > 1:
322+
if before.startswith(str(self.command_prefix)) and len(before) > 1:
321323
self.logger.info("Processing commands")
322324
await self.process_commands(message)
323325
else:

fred/fred_commands/_command_utils.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from regex import ENHANCEMATCH, escape, search as re_search
44

5-
from ..config import Commands, Crashes, Misc
5+
from ..config import Commands, Crashes, Misc, CommandsDict, CrashesDict
66
from ..libraries.common import new_logger
77

88
logger = new_logger("[Command/Crash Search]")
@@ -16,8 +16,12 @@ def search(
1616
if column not in dir(table):
1717
raise KeyError(f"`{column}` is not a column in the {table.__name__} table!")
1818

19+
if column == "attachment":
20+
raise KeyError(f"You cannot search for attachments!")
21+
1922
if not force_fuzzy and (exact_match := table.fetch_by(column, pattern)):
20-
return exact_match[column], True
23+
res: str = exact_match.get(column) or ""
24+
return res, True
2125

2226
if len(pattern) < 2:
2327
raise KeyError("Search pattern must be at least 2 characters long for fuzzy searching!")
@@ -28,7 +32,8 @@ def search(
2832

2933
scored_results: list[tuple[int, str]] = []
3034
for item in table.fetch_all():
31-
value = item.get(column)
35+
item: CommandsDict | CrashesDict
36+
value = item.get(column) or ""
3237

3338
# Filter non matching strings
3439
if not isinstance(value, str):

fred/fred_commands/crashes.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,24 +65,24 @@ async def modify_crash(
6565
await ctx.send(f"Could not find a crash with name '{name}'. Aborting")
6666
return
6767

68+
checked_crash = new_crash or str(crash.crash)
69+
checked_response = new_response or str(crash.response)
70+
6871
try:
69-
if change_crash := await self.bot.reply_yes_or_no(ctx.message, "Do you want to change the crash to match?"):
70-
new_crash, _ = await self.bot.reply_question(
72+
if await self.bot.reply_yes_or_no(ctx.message, "Do you want to change the crash to match?"):
73+
checked_crash, _ = await self.bot.reply_question(
7174
ctx.message, "What is the regular expression to match in the logs?"
7275
)
7376

74-
if change_response := await self.bot.reply_yes_or_no(ctx.message, "Do you want to change the response?"):
75-
new_response, _ = await self.bot.reply_question(
77+
if await self.bot.reply_yes_or_no(ctx.message, "Do you want to change the response?"):
78+
checked_response, _ = await self.bot.reply_question(
7679
ctx.message,
7780
f"What response do you want it to provide? Responding with `{self.bot.command_prefix}command_name`"
7881
"will use the response of that command.",
7982
)
8083
except ValueError:
8184
return
8285

83-
checked_crash = new_crash if change_crash else crash.crash
84-
checked_response = new_response if change_response else crash.response
85-
8686
issue = validate_crash(checked_crash, checked_response)
8787
if issue:
8888
await self.bot.reply_to_msg(ctx.message, issue)

fred/fred_commands/dbcommands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ async def rename_alias(self, ctx: commands.Context, name: str.lower, *, new_name
236236
"""Usage: `rename alias (name) (new name)`
237237
Purpose: Renames an alias.
238238
Notes: If response is not supplied you will be prompted for one with a timeout"""
239-
await self.rename_command(ctx, name, new_name)
239+
await self.rename_command(ctx, name, new_name=new_name)
240240

241241
@BaseCmds.search.command(name="commands")
242242
async def search_commands(self, ctx: commands.Context, pattern: str, *, flags: SearchFlags) -> None:

fred/fred_commands/help.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def get_shift(index: int, field_number: int) -> int:
157157
@lru_cache
158158
def get_field_indices(index: int, field_number: int) -> str:
159159
start = 1 + FredHelpEmbed.get_shift(index, field_number)
160-
end = field_size + FredHelpEmbed.get_shift(index, field_number)
160+
end = page_size + FredHelpEmbed.get_shift(index, field_number)
161161
return f"{start}-{end}"
162162

163163
@classmethod

0 commit comments

Comments
 (0)