From f59e77002b33677b078a427b72acd5beb1598d24 Mon Sep 17 00:00:00 2001 From: Draper <27962761+Drapersniper@users.noreply.github.com> Date: Mon, 20 Apr 2020 18:29:36 +0100 Subject: [PATCH] Optimize config calls in few places (#3766) * Just a tiny PR improving config call in a lot of places (Specially events and Help) Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> * missed this one Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> * welp Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> * welp Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> * welp Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> * jack Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> * Update redbot/cogs/mod/kickban.py Co-Authored-By: jack1142 <6032823+jack1142@users.noreply.github.com> * jack Signed-off-by: Drapersniper <27962761+drapersniper@users.noreply.github.com> Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com> --- redbot/cogs/bank/bank.py | 15 ++-- redbot/cogs/downloader/downloader.py | 54 ++++++----- redbot/cogs/filter/filter.py | 49 +++++----- redbot/cogs/mod/kickban.py | 5 +- redbot/core/commands/help.py | 128 ++++++++++++++++----------- redbot/core/core_commands.py | 10 ++- redbot/core/events.py | 8 +- 7 files changed, 153 insertions(+), 116 deletions(-) diff --git a/redbot/cogs/bank/bank.py b/redbot/cogs/bank/bank.py index c2a317c6c..42607b2bd 100644 --- a/redbot/cogs/bank/bank.py +++ b/redbot/cogs/bank/bank.py @@ -48,15 +48,16 @@ class Bank(commands.Cog): """Base command for bank settings.""" if ctx.invoked_subcommand is None: if await bank.is_global(): - bank_name = await bank._config.bank_name() - currency_name = await bank._config.currency() - default_balance = await bank._config.default_balance() + group = bank._config else: if not ctx.guild: return - bank_name = await bank._config.guild(ctx.guild).bank_name() - currency_name = await bank._config.guild(ctx.guild).currency() - default_balance = await bank._config.guild(ctx.guild).default_balance() + group = bank._config.guild(ctx.guild) + group_data = await group.all() + bank_name = group_data["bank_name"] + currency_name = group_data["currency"] + default_balance = group_data["default_balance"] + max_balance = group_data["max_balance"] settings = _( "Bank settings:\n\nBank name: {bank_name}\nCurrency: {currency_name}\n" @@ -65,7 +66,7 @@ class Bank(commands.Cog): bank_name=bank_name, currency_name=currency_name, default_balance=humanize_number(default_balance), - maximum_bal=humanize_number(await bank.get_max_balance(ctx.guild)), + maximum_bal=humanize_number(max_balance), ) await ctx.send(box(settings)) diff --git a/redbot/cogs/downloader/downloader.py b/redbot/cogs/downloader/downloader.py index 50f5bdde8..9c5ae61c0 100644 --- a/redbot/cogs/downloader/downloader.py +++ b/redbot/cogs/downloader/downloader.py @@ -195,21 +195,19 @@ class Downloader(commands.Cog): The modules to check off. """ - installed_cogs = await self.config.installed_cogs() - installed_libraries = await self.config.installed_libraries() - for module in modules: - if module.type == InstallableType.COG: - installed = installed_cogs - elif module.type == InstallableType.SHARED_LIBRARY: - installed = installed_libraries - else: - continue - module_json = module.to_json() - repo_json = installed.setdefault(module.repo_name, {}) - repo_json[module.name] = module_json - - await self.config.installed_cogs.set(installed_cogs) - await self.config.installed_libraries.set(installed_libraries) + async with self.config.all() as global_data: + installed_cogs = global_data["installed_cogs"] + installed_libraries = global_data["installed_libraries"] + for module in modules: + if module.type == InstallableType.COG: + installed = installed_cogs + elif module.type == InstallableType.SHARED_LIBRARY: + installed = installed_libraries + else: + continue + module_json = module.to_json() + repo_json = installed.setdefault(module.repo_name, {}) + repo_json[module.name] = module_json async def _remove_from_installed(self, modules: Iterable[InstalledModule]) -> None: """Remove modules from the saved list @@ -221,20 +219,18 @@ class Downloader(commands.Cog): The modules to remove. """ - installed_cogs = await self.config.installed_cogs() - installed_libraries = await self.config.installed_libraries() - for module in modules: - if module.type == InstallableType.COG: - installed = installed_cogs - elif module.type == InstallableType.SHARED_LIBRARY: - installed = installed_libraries - else: - continue - with contextlib.suppress(KeyError): - installed[module._json_repo_name].pop(module.name) - - await self.config.installed_cogs.set(installed_cogs) - await self.config.installed_libraries.set(installed_libraries) + async with self.config.all() as global_data: + installed_cogs = global_data["installed_cogs"] + installed_libraries = global_data["installed_libraries"] + for module in modules: + if module.type == InstallableType.COG: + installed = installed_cogs + elif module.type == InstallableType.SHARED_LIBRARY: + installed = installed_libraries + else: + continue + with contextlib.suppress(KeyError): + installed[module._json_repo_name].pop(module.name) async def _shared_lib_load_check(self, cog_name: str) -> Optional[Repo]: # remove in Red 3.4 diff --git a/redbot/cogs/filter/filter.py b/redbot/cogs/filter/filter.py index 42e66bc51..3b4d15cab 100644 --- a/redbot/cogs/filter/filter.py +++ b/redbot/cogs/filter/filter.py @@ -83,12 +83,14 @@ class Filter(commands.Cog): ) return elif count == 0 and timeframe == 0: - await self.config.guild(ctx.guild).filterban_count.set(0) - await self.config.guild(ctx.guild).filterban_time.set(0) + async with self.config.guild(ctx.guild).all() as guild_data: + guild_data["filterban_count"] = 0 + guild_data["filterban_time"] = 0 await ctx.send(_("Autoban disabled.")) else: - await self.config.guild(ctx.guild).filterban_count.set(count) - await self.config.guild(ctx.guild).filterban_time.set(timeframe) + async with self.config.guild(ctx.guild).all() as guild_data: + guild_data["filterban_count"] = count + guild_data["filterban_time"] = timeframe await ctx.send(_("Count and time have been set.")) @commands.group(name="filter") @@ -276,8 +278,10 @@ class Filter(commands.Cog): This is disabled by default. """ guild = ctx.guild - current_setting = await self.config.guild(guild).filter_names() - await self.config.guild(guild).filter_names.set(not current_setting) + + async with self.config.guild(guild).all() as guild_data: + current_setting = guild_data["filter_names"] + guild_data["filter_names"] = not current_setting if current_setting: await ctx.send(_("Names and nicknames will no longer be filtered.")) else: @@ -365,21 +369,23 @@ class Filter(commands.Cog): return hits async def check_filter(self, message: discord.Message): - server = message.guild + guild = message.guild author = message.author - - filter_count = await self.config.guild(server).filterban_count() - filter_time = await self.config.guild(server).filterban_time() - user_count = await self.config.member(author).filter_count() - next_reset_time = await self.config.member(author).next_reset_time() + guild_data = await self.config.guild(guild).all() + member_data = await self.config.member(author).all() + filter_count = guild_data["filterban_count"] + filter_time = guild_data["filterban_time"] + user_count = member_data["filter_count"] + next_reset_time = member_data["next_reset_time"] if filter_count > 0 and filter_time > 0: if message.created_at.timestamp() >= next_reset_time: next_reset_time = message.created_at.timestamp() + filter_time - await self.config.member(author).next_reset_time.set(next_reset_time) - if user_count > 0: - user_count = 0 - await self.config.member(author).filter_count.set(user_count) + async with self.config.member(author).all() as member_data: + member_data["next_reset_time"] = next_reset_time + if user_count > 0: + user_count = 0 + member_data["filter_count"] = user_count hits = await self.filter_hits(message.content, message.channel) @@ -399,17 +405,17 @@ class Filter(commands.Cog): ): reason = _("Autoban (too many filtered messages.)") try: - await server.ban(author, reason=reason) + await guild.ban(author, reason=reason) except discord.HTTPException: pass else: await modlog.create_case( self.bot, - server, + guild, message.created_at, "filterban", author, - server.me, + guild.me, reason, ) @@ -449,12 +455,13 @@ class Filter(commands.Cog): return # Discord Hierarchy applies to nicks if await self.bot.is_automod_immune(member): return - if not await self.config.guild(member.guild).filter_names(): + guild_data = await self.config.guild(member.guild).all() + if not guild_data["filter_names"]: return if await self.filter_hits(member.display_name, member.guild): - name_to_use = await self.config.guild(member.guild).filter_default_name() + name_to_use = guild_data["filter_default_name"] reason = _("Filtered nickname") if member.nick else _("Filtered name") try: await member.edit(nick=name_to_use, reason=reason) diff --git a/redbot/cogs/mod/kickban.py b/redbot/cogs/mod/kickban.py index 02ebab6d8..0bfe08c9d 100644 --- a/redbot/cogs/mod/kickban.py +++ b/redbot/cogs/mod/kickban.py @@ -410,9 +410,8 @@ class KickBanMixin(MixinMeta): queue_entry = (guild.id, user.id) await self.config.member(user).banned_until.set(unban_time.timestamp()) - cur_tbans = await self.config.guild(guild).current_tempbans() - cur_tbans.append(user.id) - await self.config.guild(guild).current_tempbans.set(cur_tbans) + async with self.config.guild(guild).current_tempbans() as current_tempbans: + current_tempbans.append(user.id) with contextlib.suppress(discord.HTTPException): # We don't want blocked DMs preventing us from banning diff --git a/redbot/core/commands/help.py b/redbot/core/commands/help.py index 34d3a3700..c47eb21df 100644 --- a/redbot/core/commands/help.py +++ b/redbot/core/commands/help.py @@ -74,6 +74,7 @@ class HelpSettings: verify_checks: bool = True verify_exists: bool = False tagline: str = "" + delete_delay: int = 0 # Contrib Note: This is intentional to not accept the bot object # There are plans to allow guild and user specific help settings @@ -123,40 +124,55 @@ class RedHelpFormatter: For most cases, you should use this and only this directly. """ + + help_settings = await HelpSettings.from_context(ctx) + if help_for is None or isinstance(help_for, dpy_commands.bot.BotBase): - await self.format_bot_help(ctx) + await self.format_bot_help(ctx, help_settings=help_settings) return if isinstance(help_for, str): try: help_for = self.parse_command(ctx, help_for) except NoCommand: - await self.command_not_found(ctx, help_for) + await self.command_not_found(ctx, help_for, help_settings=help_settings) return except NoSubCommand as exc: - if await ctx.bot._config.help.verify_exists(): - await self.subcommand_not_found(ctx, exc.last, exc.not_found) + if help_settings.verify_exists: + await self.subcommand_not_found( + ctx, exc.last, exc.not_found, help_settings=help_settings + ) return help_for = exc.last if isinstance(help_for, commands.Cog): - await self.format_cog_help(ctx, help_for) + await self.format_cog_help(ctx, help_for, help_settings=help_settings) else: - await self.format_command_help(ctx, help_for) + await self.format_command_help(ctx, help_for, help_settings=help_settings) - async def get_cog_help_mapping(self, ctx: Context, obj: commands.Cog): + async def get_cog_help_mapping( + self, ctx: Context, obj: commands.Cog, help_settings: HelpSettings + ): iterator = filter(lambda c: c.parent is None and c.cog is obj, ctx.bot.commands) - return {com.name: com async for com in self.help_filter_func(ctx, iterator)} - - async def get_group_help_mapping(self, ctx: Context, obj: commands.Group): return { - com.name: com async for com in self.help_filter_func(ctx, obj.all_commands.values()) + com.name: com + async for com in self.help_filter_func(ctx, iterator, help_settings=help_settings) } - async def get_bot_help_mapping(self, ctx): + async def get_group_help_mapping( + self, ctx: Context, obj: commands.Group, help_settings: HelpSettings + ): + return { + com.name: com + async for com in self.help_filter_func( + ctx, obj.all_commands.values(), help_settings=help_settings + ) + } + + async def get_bot_help_mapping(self, ctx, help_settings: HelpSettings): sorted_iterable = [] for cogname, cog in (*sorted(ctx.bot.cogs.items()), (None, None)): - cm = await self.get_cog_help_mapping(ctx, cog) + cm = await self.get_cog_help_mapping(ctx, cog, help_settings=help_settings) if cm: sorted_iterable.append((cogname, cm)) return sorted_iterable @@ -168,11 +184,15 @@ class RedHelpFormatter: "You can also type {ctx.clean_prefix}help for more info on a category." ).format(ctx=ctx) - async def format_command_help(self, ctx: Context, obj: commands.Command): + async def format_command_help( + self, ctx: Context, obj: commands.Command, help_settings: HelpSettings + ): - send = await ctx.bot._config.help.verify_exists() + send = help_settings.verify_exists if not send: - async for _ in self.help_filter_func(ctx, (obj,), bypass_hidden=True): + async for _ in self.help_filter_func( + ctx, (obj,), bypass_hidden=True, help_settings=help_settings + ): # This is a really lazy option for not # creating a separate single case version. # It is efficient though @@ -187,7 +207,8 @@ class RedHelpFormatter: command = obj description = command.description or "" - tagline = (await ctx.bot._config.help.tagline()) or self.get_default_tagline(ctx) + + tagline = (help_settings.tagline) or self.get_default_tagline(ctx) signature = ( f"`{T_('Syntax')}: {ctx.clean_prefix}{command.qualified_name} {command.signature}`" ) @@ -195,7 +216,7 @@ class RedHelpFormatter: if hasattr(command, "all_commands"): grp = cast(commands.Group, command) - subcommands = await self.get_group_help_mapping(ctx, grp) + subcommands = await self.get_group_help_mapping(ctx, grp, help_settings=help_settings) if await ctx.embed_requested(): emb = {"embed": {"title": "", "description": ""}, "footer": {"text": ""}, "fields": []} @@ -235,7 +256,7 @@ class RedHelpFormatter: field = EmbedField(title, page, False) emb["fields"].append(field) - await self.make_and_send_embeds(ctx, emb) + await self.make_and_send_embeds(ctx, emb, help_settings=help_settings) else: # Code blocks: @@ -272,7 +293,7 @@ class RedHelpFormatter: ) ) pages = [box(p) for p in pagify(to_page)] - await self.send_pages(ctx, pages, embed=False) + await self.send_pages(ctx, pages, embed=False, help_settings=help_settings) @staticmethod def group_embed_fields(fields: List[EmbedField], max_chars=1000): @@ -298,11 +319,11 @@ class RedHelpFormatter: return ret - async def make_and_send_embeds(self, ctx, embed_dict: dict): + async def make_and_send_embeds(self, ctx, embed_dict: dict, help_settings: HelpSettings): pages = [] - page_char_limit = await ctx.bot._config.help.page_char_limit() + page_char_limit = help_settings.page_char_limit page_char_limit = min(page_char_limit, 5500) # Just in case someone was manually... author_info = { @@ -367,16 +388,16 @@ class RedHelpFormatter: pages.append(embed) - await self.send_pages(ctx, pages, embed=True) + await self.send_pages(ctx, pages, embed=True, help_settings=help_settings) - async def format_cog_help(self, ctx: Context, obj: commands.Cog): + async def format_cog_help(self, ctx: Context, obj: commands.Cog, help_settings: HelpSettings): - coms = await self.get_cog_help_mapping(ctx, obj) - if not (coms or await ctx.bot._config.help.verify_exists()): + coms = await self.get_cog_help_mapping(ctx, obj, help_settings=help_settings) + if not (coms or help_settings.verify_exists): return description = obj.format_help_for_context(ctx) - tagline = (await ctx.bot._config.help.tagline()) or self.get_default_tagline(ctx) + tagline = (help_settings.tagline) or self.get_default_tagline(ctx) if await ctx.embed_requested(): emb = {"embed": {"title": "", "description": ""}, "footer": {"text": ""}, "fields": []} @@ -410,7 +431,7 @@ class RedHelpFormatter: field = EmbedField(title, page, False) emb["fields"].append(field) - await self.make_and_send_embeds(ctx, emb) + await self.make_and_send_embeds(ctx, emb, help_settings=help_settings) else: subtext = None @@ -434,16 +455,16 @@ class RedHelpFormatter: to_page = "\n\n".join(filter(None, (description, subtext_header, subtext))) pages = [box(p) for p in pagify(to_page)] - await self.send_pages(ctx, pages, embed=False) + await self.send_pages(ctx, pages, embed=False, help_settings=help_settings) - async def format_bot_help(self, ctx: Context): + async def format_bot_help(self, ctx: Context, help_settings: HelpSettings): - coms = await self.get_bot_help_mapping(ctx) + coms = await self.get_bot_help_mapping(ctx, help_settings=help_settings) if not coms: return description = ctx.bot.description or "" - tagline = (await ctx.bot._config.help.tagline()) or self.get_default_tagline(ctx) + tagline = (help_settings.tagline) or self.get_default_tagline(ctx) if await ctx.embed_requested(): @@ -475,7 +496,7 @@ class RedHelpFormatter: field = EmbedField(title, page, False) emb["fields"].append(field) - await self.make_and_send_embeds(ctx, emb) + await self.make_and_send_embeds(ctx, emb, help_settings=help_settings) else: to_join = [] @@ -510,18 +531,17 @@ class RedHelpFormatter: to_join.append(f"\n{tagline}") to_page = "\n".join(to_join) pages = [box(p) for p in pagify(to_page)] - await self.send_pages(ctx, pages, embed=False) + await self.send_pages(ctx, pages, embed=False, help_settings=help_settings) @staticmethod async def help_filter_func( - ctx, objects: Iterable[SupportsCanSee], bypass_hidden=False + ctx, objects: Iterable[SupportsCanSee], help_settings: HelpSettings, bypass_hidden=False, ) -> AsyncIterator[SupportsCanSee]: """ This does most of actual filtering. """ - - show_hidden = bypass_hidden or await ctx.bot._config.help.show_hidden() - verify_checks = await ctx.bot._config.help.verify_checks() + show_hidden = bypass_hidden or help_settings.show_hidden + verify_checks = help_settings.verify_checks # TODO: Settings for this in core bot db for obj in objects: @@ -542,11 +562,16 @@ class RedHelpFormatter: else: yield obj - async def command_not_found(self, ctx, help_for): + async def command_not_found(self, ctx, help_for, help_settings: HelpSettings): """ Sends an error, fuzzy help, or stays quiet based on settings """ - coms = {c async for c in self.help_filter_func(ctx, ctx.bot.walk_commands())} + coms = { + c + async for c in self.help_filter_func( + ctx, ctx.bot.walk_commands(), help_settings=help_settings + ) + } fuzzy_commands = await fuzzy_command_search(ctx, help_for, commands=coms, min_score=75) use_embeds = await ctx.embed_requested() if fuzzy_commands: @@ -555,25 +580,25 @@ class RedHelpFormatter: ret.set_author( name=f"{ctx.me.display_name} {T_('Help Menu')}", icon_url=ctx.me.avatar_url ) - tagline = (await ctx.bot._config.help.tagline()) or self.get_default_tagline(ctx) + tagline = help_settings.tagline or self.get_default_tagline(ctx) ret.set_footer(text=tagline) await ctx.send(embed=ret) else: await ctx.send(ret) - elif await ctx.bot._config.help.verify_exists(): + elif help_settings.verify_exists: ret = T_("Help topic for *{command_name}* not found.").format(command_name=help_for) if use_embeds: ret = discord.Embed(color=(await ctx.embed_color()), description=ret) ret.set_author( name=f"{ctx.me.display_name} {T_('Help Menu')}", icon_url=ctx.me.avatar_url ) - tagline = (await ctx.bot._config.help.tagline()) or self.get_default_tagline(ctx) + tagline = help_settings.tagline or self.get_default_tagline(ctx) ret.set_footer(text=tagline) await ctx.send(embed=ret) else: await ctx.send(ret) - async def subcommand_not_found(self, ctx, command, not_found): + async def subcommand_not_found(self, ctx, command, not_found, help_settings: HelpSettings): """ Sends an error """ @@ -585,7 +610,7 @@ class RedHelpFormatter: ret.set_author( name=f"{ctx.me.display_name} {T_('Help Menu')}", icon_url=ctx.me.avatar_url ) - tagline = (await ctx.bot._config.help.tagline()) or self.get_default_tagline(ctx) + tagline = help_settings.tagline or self.get_default_tagline(ctx) ret.set_footer(text=tagline) await ctx.send(embed=ret) else: @@ -622,22 +647,25 @@ class RedHelpFormatter: return com async def send_pages( - self, ctx: Context, pages: List[Union[str, discord.Embed]], embed: bool = True + self, + ctx: Context, + pages: List[Union[str, discord.Embed]], + embed: bool = True, + help_settings: HelpSettings = None, ): """ Sends pages based on settings. """ # save on config calls - config_help = await ctx.bot._config.help() channel_permissions = ctx.channel.permissions_for(ctx.me) - if not (channel_permissions.add_reactions and config_help["use_menus"]): + if not (channel_permissions.add_reactions and help_settings.use_menus): - max_pages_in_guild = config_help["max_pages_in_guild"] + max_pages_in_guild = help_settings.max_pages_in_guild use_DMs = len(pages) > max_pages_in_guild destination = ctx.author if use_DMs else ctx.channel - delete_delay = config_help["delete_delay"] + delete_delay = help_settings.delete_delay messages: List[discord.Message] = [] for page in pages: diff --git a/redbot/core/core_commands.py b/redbot/core/core_commands.py index b8d55edde..1e65c9e69 100644 --- a/redbot/core/core_commands.py +++ b/redbot/core/core_commands.py @@ -879,13 +879,14 @@ class Core(commands.Cog, CoreLogic): """Changes [botname]'s settings""" if ctx.invoked_subcommand is None: if ctx.guild: + guild_data = await ctx.bot._config.guild(ctx.guild).all() guild = ctx.guild - admin_role_ids = await ctx.bot._config.guild(ctx.guild).admin_role() + admin_role_ids = guild_data["admin_role"] admin_role_names = [r.name for r in guild.roles if r.id in admin_role_ids] admin_roles_str = ( humanize_list(admin_role_names) if admin_role_names else "Not Set." ) - mod_role_ids = await ctx.bot._config.guild(ctx.guild).mod_role() + mod_role_ids = guild_data["mod_role"] mod_role_names = [r.name for r in guild.roles if r.id in mod_role_ids] mod_roles_str = humanize_list(mod_role_names) if mod_role_names else "Not Set." guild_settings = _("Admin roles: {admin}\nMod roles: {mod}\n").format( @@ -895,8 +896,9 @@ class Core(commands.Cog, CoreLogic): guild_settings = "" prefixes = await ctx.bot._prefix_cache.get_prefixes(ctx.guild) - locale = await ctx.bot._config.locale() - regional_format = await ctx.bot._config.regional_format() or _("Same as bot's locale") + global_data = await ctx.bot._config.all() + locale = global_data["locale"] + regional_format = global_data["regional_format"] or _("Same as bot's locale") prefix_string = " ".join(prefixes) settings = _( diff --git a/redbot/core/events.py b/redbot/core/events.py index 0417b5364..4622aa149 100644 --- a/redbot/core/events.py +++ b/redbot/core/events.py @@ -13,7 +13,7 @@ import pkg_resources from colorama import Fore, Style, init from pkg_resources import DistributionNotFound -from redbot.core.commands import RedHelpFormatter +from redbot.core.commands import RedHelpFormatter, HelpSettings from redbot.core.i18n import Translator from .. import __version__ as red_version, version_info as red_version_info, VersionInfo from . import commands @@ -192,10 +192,14 @@ def init_events(bot, cli_flags): bot._last_exception = exception_log await ctx.send(inline(message)) elif isinstance(error, commands.CommandNotFound): + help_settings = await HelpSettings.from_context(ctx) fuzzy_commands = await fuzzy_command_search( ctx, commands={ - c async for c in RedHelpFormatter.help_filter_func(ctx, bot.walk_commands()) + c + async for c in RedHelpFormatter.help_filter_func( + ctx, bot.walk_commands(), help_settings=help_settings + ) }, ) if not fuzzy_commands: