Skip to content

Commit 0dff97b

Browse files
committed
Added abc for thread, thread manager, config, clients, and bot
This will make debugging future code easier as it introduced deeper type hints and more static types
1 parent 6ba1711 commit 0dff97b

File tree

11 files changed

+659
-198
lines changed

11 files changed

+659
-198
lines changed

bot.py

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from core.thread import ThreadManager
4747
from core.config import ConfigManager
4848
from core.changelog import ChangeLog
49+
from core.objects import Bot
4950

5051

5152
colorama.init()
@@ -54,33 +55,65 @@
5455
Style.RESET_ALL
5556

5657

57-
class ModmailBot(commands.Bot):
58+
class ModmailBot(Bot):
5859

5960
def __init__(self):
6061
super().__init__(command_prefix=None) # implemented in `get_prefix`
61-
self.version = __version__
62-
self.start_time = datetime.utcnow()
63-
self.threads = ThreadManager(self)
64-
self.session = ClientSession(loop=self.loop)
65-
self.config = ConfigManager(self)
66-
self.self_hosted = bool(self.config.get('mongo_uri', ''))
62+
self._threads = None
63+
self._session = None
64+
self._config = None
6765
self._connected = Event()
66+
self._db = None
6867

6968
if self.self_hosted:
70-
self.db = AsyncIOMotorClient(self.config.mongo_uri).modmail_bot
71-
self.modmail_api = SelfHostedClient(self)
69+
self._db = AsyncIOMotorClient(self.config.mongo_uri).modmail_bot
70+
self._api = SelfHostedClient(self)
7271
else:
73-
self.modmail_api = ModmailApiClient(self)
72+
self._api = ModmailApiClient(self)
7473

7574
self.data_task = self.loop.create_task(self.data_loop())
7675
self.autoupdate_task = self.loop.create_task(self.autoupdate_loop())
77-
self._add_commands()
76+
self._load_extensions()
7877
self.owner = None
7978

79+
@property
80+
def version(self):
81+
return __version__
82+
83+
@property
84+
def db(self):
85+
return self._db
86+
87+
@property
88+
def self_hosted(self):
89+
return bool(self.config.get('mongo_uri', ''))
90+
91+
@property
92+
def api(self):
93+
return self._api
94+
95+
@property
96+
def config(self):
97+
if self._config is None:
98+
self._config = ConfigManager(self)
99+
return self._config
100+
101+
@property
102+
def session(self):
103+
if self._session is None:
104+
self._session = ClientSession(loop=self.loop)
105+
return self._session
106+
107+
@property
108+
def threads(self):
109+
if self._threads is None:
110+
self._threads = ThreadManager(self)
111+
return self._threads
112+
80113
async def get_prefix(self, message=None):
81114
return [self.prefix, f'<@{self.user.id}> ', f'<@!{self.user.id}> ']
82115

83-
def _add_commands(self):
116+
def _load_extensions(self):
84117
"""Adds commands automatically"""
85118
self.remove_command('help')
86119

@@ -397,7 +430,7 @@ async def on_message(self, message):
397430

398431
thread = await self.threads.find(channel=ctx.channel)
399432
if thread is not None:
400-
await self.modmail_api.append_log(message, type_='internal')
433+
await self.api.append_log(message, type_='internal')
401434

402435
async def on_guild_channel_delete(self, channel):
403436
if channel.guild != self.modmail_guild:
@@ -454,7 +487,8 @@ async def on_command_error(self, ctx, error):
454487
else:
455488
raise error
456489

457-
def overwrites(self, ctx): # TODO: can this be static?
490+
@staticmethod
491+
def overwrites(ctx):
458492
"""Permission overwrites for the guild."""
459493
overwrites = {
460494
ctx.guild.default_role: discord.PermissionOverwrite(
@@ -486,14 +520,14 @@ async def validate_api_token(self):
486520
'if you are self-hosting logs.')
487521
return await self.logout()
488522
else:
489-
valid = await self.modmail_api.validate_token()
523+
valid = await self.api.validate_token()
490524
if not valid:
491525
print(Fore.RED, end='')
492526
print('Invalid MODMAIL_API_TOKEN - get one '
493527
'from https://dashboard.modmail.tk')
494528
return await self.logout()
495529

496-
user = await self.modmail_api.get_user_info()
530+
user = await self.api.get_user_info()
497531
username = user['user']['username']
498532
print(Style.RESET_ALL + Fore.CYAN + 'Validated token.')
499533
print('GitHub user: ' + username + Style.RESET_ALL)
@@ -533,7 +567,7 @@ async def data_loop(self):
533567
"last_updated": str(datetime.utcnow())
534568
}
535569

536-
await self.modmail_api.post_metadata(data)
570+
await self.api.post_metadata(data)
537571
await sleep(3600)
538572

539573
async def autoupdate_loop(self):
@@ -551,10 +585,10 @@ async def autoupdate_loop(self):
551585
return
552586

553587
while True:
554-
metadata = await self.modmail_api.get_metadata()
588+
metadata = await self.api.get_metadata()
555589

556590
if metadata['latest_version'] != self.version:
557-
data = await self.modmail_api.update_repository()
591+
data = await self.api.update_repository()
558592

559593
embed = discord.Embed(color=discord.Color.green())
560594

@@ -598,20 +632,6 @@ async def get_latest_updates(self, limit=3):
598632

599633
return latest_commits
600634

601-
@property
602-
def uptime(self):
603-
now = datetime.utcnow()
604-
delta = now - self.start_time
605-
hours, remainder = divmod(int(delta.total_seconds()), 3600)
606-
minutes, seconds = divmod(remainder, 60)
607-
days, hours = divmod(hours, 24)
608-
609-
fmt = '{h}h {m}m {s}s'
610-
if days:
611-
fmt = '{d}d ' + fmt
612-
613-
return fmt.format(d=days, h=hours, m=minutes, s=seconds)
614-
615635

616636
if __name__ == '__main__':
617637
uvloop.install()

cogs/modmail.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
from core.decorators import trigger_typing
1010
from core.paginator import PaginatorSession
1111
from core.time import UserFriendlyTime, human_timedelta
12-
from core.utils import User, truncate
12+
from core.utils import truncate, User
13+
from core.objects import Bot
1314

1415

1516
class Modmail:
1617
"""Commands directly related to Modmail functionality."""
1718

18-
def __init__(self, bot):
19+
def __init__(self, bot: Bot):
1920
self.bot = bot
2021

2122
@commands.command()
@@ -140,7 +141,8 @@ async def move(self, ctx, *, category: discord.CategoryChannel):
140141
await thread.channel.edit(category=category, sync_permissions=True)
141142
await ctx.message.add_reaction('✅')
142143

143-
async def send_scheduled_close_message(self, ctx, after, silent=False):
144+
@staticmethod
145+
async def send_scheduled_close_message(ctx, after, silent=False):
144146
human_delta = human_timedelta(after.dt)
145147

146148
silent = '*silently* ' if silent else ''
@@ -354,7 +356,7 @@ async def logs(self, ctx, *, member: User = None):
354356
icon_url = getattr(user, 'avatar_url', default_avatar)
355357
username = str(user) if hasattr(user, 'name') else str(user.id)
356358

357-
logs = await self.bot.modmail_api.get_user_logs(user.id)
359+
logs = await self.bot.api.get_user_logs(user.id)
358360

359361
if not any(not log['open'] for log in logs):
360362
embed = discord.Embed(color=discord.Color.red(),

cogs/utility.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
from core.decorators import auth_required, owner_only, trigger_typing
1919
from core.changelog import ChangeLog
2020
from core.utils import cleanup_code
21+
from core.objects import Bot
2122

2223

2324
class Utility:
2425
"""General commands that provide utility"""
2526

26-
def __init__(self, bot):
27+
def __init__(self, bot: Bot):
2728
self.bot = bot
2829

2930
def format_cog_help(self, ctx, cog):
@@ -57,7 +58,7 @@ def format_cog_help(self, ctx, cog):
5758
embeds.append(embed)
5859
return embeds
5960

60-
def format_command_help(self, ctx, cmd):
61+
def format_command_help(self, cmd):
6162
"""Formats command help."""
6263
prefix = self.bot.prefix
6364
embed = Embed(
@@ -114,7 +115,7 @@ async def help(self, ctx, *, command: str = None):
114115
cmd = self.bot.get_command(command)
115116
cog = self.bot.cogs.get(command)
116117
if cmd is not None:
117-
embeds = [self.format_command_help(ctx, cmd)]
118+
embeds = [self.format_command_help(cmd)]
118119
elif cog is not None:
119120
embeds = self.format_cog_help(ctx, cog)
120121
else:
@@ -198,7 +199,7 @@ async def github(self, ctx):
198199
if ctx.invoked_subcommand:
199200
return
200201

201-
data = await self.bot.modmail_api.get_user_info()
202+
data = await self.bot.api.get_user_info()
202203

203204
embed = Embed(
204205
title='Github',
@@ -218,7 +219,8 @@ async def github(self, ctx):
218219
@trigger_typing
219220
async def update(self, ctx):
220221
"""Updates the bot, this only works with heroku users."""
221-
metadata = await self.bot.modmail_api.get_metadata()
222+
# TODO: Should return if user is self hosting
223+
metadata = await self.bot.api.get_metadata()
222224

223225
desc = (f'The latest version is [`{self.bot.version}`]'
224226
'(https://github.com/kyb3r/modmail/blob/master/bot.py#L25)')
@@ -230,14 +232,14 @@ async def update(self, ctx):
230232
)
231233

232234
if metadata['latest_version'] == self.bot.version:
233-
data = await self.bot.modmail_api.get_user_info()
235+
data = await self.bot.api.get_user_info()
234236
if not data.get('error'):
235237
user = data['user']
236238
embed.set_author(name=user['username'],
237239
icon_url=user['avatar_url'],
238240
url=user['url'])
239241
else:
240-
data = await self.bot.modmail_api.update_repository()
242+
data = await self.bot.api.update_repository()
241243

242244
commit_data = data['data']
243245
user = data['user']

core/changelog.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
from typing import List
55
from collections import defaultdict
66

7+
from core.objects import Bot
8+
79

810
class Version:
9-
def __init__(self, bot, version: str, lines: str):
11+
def __init__(self, bot: Bot, version: str, lines: str):
1012
self.bot = bot
1113
self.version = version
1214
self.lines = [x for x in lines.splitlines() if x]
@@ -49,7 +51,7 @@ class ChangeLog:
4951
'kyb3r/modmail/master/CHANGELOG.md')
5052
regex = re.compile(r'# (v\d+\.\d+\.\d+)([\S\s]*?(?=# v|$))')
5153

52-
def __init__(self, bot, text: str):
54+
def __init__(self, bot: Bot, text: str):
5355
self.bot = bot
5456
self.text = text
5557
self.versions = [Version(bot, *m) for m in self.regex.findall(text)]
@@ -63,7 +65,7 @@ def embeds(self) -> List[Embed]:
6365
return [v.embed for v in self.versions]
6466

6567
@classmethod
66-
async def from_repo(cls, bot, url: str = ''):
68+
async def from_repo(cls, bot, url: str = '') -> 'ChangeLog':
6769
url = url or cls.changelog_url
6870
resp = await bot.session.get(url)
6971
return cls(bot, await resp.text())

0 commit comments

Comments
 (0)