From f3bbfdc64d3021f03da84f999e5cdcaebd7f6687 Mon Sep 17 00:00:00 2001 From: Toby Harradine Date: Fri, 28 Jun 2019 03:31:44 +1000 Subject: [PATCH] Fix duplicate commands in fuzzy help (#2798) * Fix duplicate commands in fuzzy help Signed-off-by: Toby Harradine * Use help command's filter for all fuzzy Signed-off-by: Toby Harradine --- redbot/core/commands/help.py | 5 +++-- redbot/core/events.py | 8 +++++++- redbot/core/utils/__init__.py | 26 +++++++++++++++----------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/redbot/core/commands/help.py b/redbot/core/commands/help.py index 615cd8e03..befd8d97e 100644 --- a/redbot/core/commands/help.py +++ b/redbot/core/commands/help.py @@ -417,8 +417,9 @@ class RedHelpFormatter: pages = [box(p) for p in pagify(to_page)] await self.send_pages(ctx, pages, embed=False) + @staticmethod async def help_filter_func( - self, ctx, objects: Iterable[SupportsCanSee], bypass_hidden=False + ctx, objects: Iterable[SupportsCanSee], bypass_hidden=False ) -> AsyncIterator[SupportsCanSee]: """ This does most of actual filtering. @@ -450,7 +451,7 @@ class RedHelpFormatter: """ 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())} fuzzy_commands = await fuzzy_command_search(ctx, help_for, commands=coms, min_score=75) use_embeds = await ctx.embed_requested() if fuzzy_commands: diff --git a/redbot/core/events.py b/redbot/core/events.py index bd0bff3cd..33f025789 100644 --- a/redbot/core/events.py +++ b/redbot/core/events.py @@ -13,6 +13,7 @@ import pkg_resources from colorama import Fore, Style, init from pkg_resources import DistributionNotFound +from redbot.core.commands import RedHelpFormatter from .. import __version__ as red_version, version_info as red_version_info, VersionInfo from . import commands from .config import get_latest_confs @@ -201,7 +202,12 @@ def init_events(bot, cli_flags): bot._last_exception = exception_log await ctx.send(inline(message)) elif isinstance(error, commands.CommandNotFound): - fuzzy_commands = await fuzzy_command_search(ctx) + fuzzy_commands = await fuzzy_command_search( + ctx, + commands={ + c async for c in RedHelpFormatter.help_filter_func(ctx, bot.walk_commands()) + }, + ) if not fuzzy_commands: pass elif await ctx.embed_requested(): diff --git a/redbot/core/utils/__init__.py b/redbot/core/utils/__init__.py index dc4d2fa8a..00a87d299 100644 --- a/redbot/core/utils/__init__.py +++ b/redbot/core/utils/__init__.py @@ -19,14 +19,18 @@ from typing import ( Tuple, TypeVar, Union, + Set, + TYPE_CHECKING, ) import discord from fuzzywuzzy import fuzz, process -from redbot.core import commands from .chat_formatting import box +if TYPE_CHECKING: + from ..commands import Command, Context + __all__ = [ "bounded_gather", "safe_delete", @@ -180,12 +184,12 @@ async def async_enumerate( async def fuzzy_command_search( - ctx: commands.Context, + ctx: "Context", term: Optional[str] = None, *, - commands: Optional[list] = None, + commands: Optional[Set["Command"]] = None, min_score: int = 80, -) -> Optional[List[commands.Command]]: +) -> Optional[List["Command"]]: """Search for commands which are similar in name to the one invoked. Returns a maximum of 5 commands which must all be at least matched @@ -196,8 +200,11 @@ async def fuzzy_command_search( ctx : `commands.Context ` The command invocation context. term : Optional[str] - The name of the invoked command. If ``None``, `Context.invoked_with` - will be used instead. + The name of the invoked command. If ``None``, + `Context.invoked_with` will be used instead. + commands : Optional[Set[commands.Command]] + The commands available to choose from when doing a fuzzy match. + When omitted, `Bot.walk_commands` will be used instead. min_score : int The minimum score for matched commands to reach. Defaults to 80. @@ -239,7 +246,7 @@ async def fuzzy_command_search( # Do the scoring. `extracted` is a list of tuples in the form `(command, score)` extracted = process.extract( - term, (commands or ctx.bot.walk_commands()), limit=5, scorer=fuzz.QRatio + term, (commands or set(ctx.bot.walk_commands())), limit=5, scorer=fuzz.QRatio ) if not extracted: return @@ -257,10 +264,7 @@ async def fuzzy_command_search( async def format_fuzzy_results( - ctx: commands.Context, - matched_commands: List[commands.Command], - *, - embed: Optional[bool] = None, + ctx: "Context", matched_commands: List["Command"], *, embed: Optional[bool] = None ) -> Union[str, discord.Embed]: """Format the result of a fuzzy command search.