mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[V3 Fuzzy search] fix several issues with this feature (#1788)
* [V3 Fuzzy search] fix several issues with this feature * Make it check if parent commands are hidden * Check if compiler available in setup.py * Let's just compile a dummy C file to check compiler availability * Add a missing import + remove unneeded code
This commit is contained in:
parent
db5d4d5158
commit
0b78664792
@ -50,6 +50,7 @@ class RedBase(BotBase):
|
||||
locale="en",
|
||||
embeds=True,
|
||||
color=15158332,
|
||||
fuzzy=False,
|
||||
help__page_char_limit=1000,
|
||||
help__max_pages_in_guild=2,
|
||||
help__tagline="",
|
||||
@ -63,6 +64,7 @@ class RedBase(BotBase):
|
||||
mod_role=None,
|
||||
embeds=None,
|
||||
use_bot_color=False,
|
||||
fuzzy=False,
|
||||
)
|
||||
|
||||
self.db.register_user(embeds=None)
|
||||
|
||||
@ -48,6 +48,21 @@ class Command(commands.Command):
|
||||
# We don't want our help property to be overwritten, namely by super()
|
||||
pass
|
||||
|
||||
@property
|
||||
def parents(self):
|
||||
"""
|
||||
Returns all parent commands of this command.
|
||||
|
||||
This is a list, sorted by the length of :attr:`.qualified_name` from highest to lowest.
|
||||
If the command has no parents, this will be an empty list.
|
||||
"""
|
||||
cmd = self.parent
|
||||
entries = []
|
||||
while cmd is not None:
|
||||
entries.append(cmd)
|
||||
cmd = cmd.parent
|
||||
return sorted(entries, key=lambda x: len(x.qualified_name), reverse=True)
|
||||
|
||||
def command(self, cls=None, *args, **kwargs):
|
||||
"""A shortcut decorator that invokes :func:`.command` and adds it to
|
||||
the internal command list via :meth:`~.GroupMixin.add_command`.
|
||||
|
||||
@ -653,6 +653,39 @@ class Core(CoreLogic):
|
||||
)
|
||||
)
|
||||
|
||||
@_set.command()
|
||||
@checks.guildowner()
|
||||
@commands.guild_only()
|
||||
async def serverfuzzy(self, ctx):
|
||||
"""
|
||||
Toggle whether to enable fuzzy command search for the server.
|
||||
|
||||
Default is for fuzzy command search to be disabled.
|
||||
"""
|
||||
current_setting = await ctx.bot.db.guild(ctx.guild).fuzzy()
|
||||
await ctx.bot.db.guild(ctx.guild).fuzzy.set(not current_setting)
|
||||
await ctx.send(
|
||||
_("Fuzzy command search has been {} for this server.").format(
|
||||
_("disabled") if current_setting else _("enabled")
|
||||
)
|
||||
)
|
||||
|
||||
@_set.command()
|
||||
@checks.is_owner()
|
||||
async def fuzzy(self, ctx):
|
||||
"""
|
||||
Toggle whether to enable fuzzy command search in DMs.
|
||||
|
||||
Default is for fuzzy command search to be disabled.
|
||||
"""
|
||||
current_setting = await ctx.bot.db.fuzzy()
|
||||
await ctx.bot.db.fuzzy.set(not current_setting)
|
||||
await ctx.send(
|
||||
_("Fuzzy command search has been {} in DMs.").format(
|
||||
_("disabled") if current_setting else _("enabled")
|
||||
)
|
||||
)
|
||||
|
||||
@_set.command(aliases=["color"])
|
||||
@checks.is_owner()
|
||||
async def colour(self, ctx, *, colour: discord.Colour = None):
|
||||
|
||||
@ -225,7 +225,9 @@ def init_events(bot, cli_flags):
|
||||
term = ctx.invoked_with + " "
|
||||
if len(ctx.args) > 1:
|
||||
term += " ".join(ctx.args[1:])
|
||||
await ctx.maybe_send_embed(fuzzy_command_search(ctx, ctx.invoked_with))
|
||||
fuzzy_result = await fuzzy_command_search(ctx, ctx.invoked_with)
|
||||
if fuzzy_result is not None:
|
||||
await ctx.maybe_send_embed(fuzzy_result)
|
||||
elif isinstance(error, commands.CheckFailure):
|
||||
pass
|
||||
elif isinstance(error, commands.NoPrivateMessage):
|
||||
|
||||
@ -281,11 +281,10 @@ class Help(formatter.HelpFormatter):
|
||||
embed.set_author(**self.author)
|
||||
return embed
|
||||
|
||||
async def cmd_not_found(self, ctx, cmd, color=None):
|
||||
async def cmd_not_found(self, ctx, cmd, description=None, color=None):
|
||||
# Shortcut for a shortcut. Sue me
|
||||
out = fuzzy_command_search(ctx, " ".join(ctx.args[1:]))
|
||||
embed = await self.simple_embed(
|
||||
ctx, title="Command {} not found.".format(cmd), description=out, color=color
|
||||
ctx, title="Command {} not found.".format(cmd), description=description, color=color
|
||||
)
|
||||
return embed
|
||||
|
||||
@ -326,11 +325,19 @@ async def help(ctx, *cmds: str):
|
||||
command = ctx.bot.all_commands.get(name)
|
||||
if command is None:
|
||||
if use_embeds:
|
||||
await destination.send(embed=await ctx.bot.formatter.cmd_not_found(ctx, name))
|
||||
fuzzy_result = await fuzzy_command_search(ctx, name)
|
||||
if fuzzy_result is not None:
|
||||
await destination.send(
|
||||
embed=await ctx.bot.formatter.cmd_not_found(
|
||||
ctx, name, description=fuzzy_result
|
||||
)
|
||||
)
|
||||
else:
|
||||
await destination.send(
|
||||
ctx.bot.command_not_found.format(name, fuzzy_command_search(ctx, name))
|
||||
)
|
||||
fuzzy_result = await fuzzy_command_search(ctx, name)
|
||||
if fuzzy_result is not None:
|
||||
await destination.send(
|
||||
ctx.bot.command_not_found.format(name, fuzzy_result)
|
||||
)
|
||||
return
|
||||
if use_embeds:
|
||||
embeds = await ctx.bot.formatter.format_help_for(ctx, command)
|
||||
@ -341,11 +348,17 @@ async def help(ctx, *cmds: str):
|
||||
command = ctx.bot.all_commands.get(name)
|
||||
if command is None:
|
||||
if use_embeds:
|
||||
await destination.send(embed=await ctx.bot.formatter.cmd_not_found(ctx, name))
|
||||
fuzzy_result = await fuzzy_command_search(ctx, name)
|
||||
if fuzzy_result is not None:
|
||||
await destination.send(
|
||||
embed=await ctx.bot.formatter.cmd_not_found(
|
||||
ctx, name, description=fuzzy_result
|
||||
)
|
||||
)
|
||||
else:
|
||||
await destination.send(
|
||||
ctx.bot.command_not_found.format(name, fuzzy_command_search(ctx, name))
|
||||
)
|
||||
fuzzy_result = await fuzzy_command_search(ctx, name)
|
||||
if fuzzy_result is not None:
|
||||
await destination.send(ctx.bot.command_not_found.format(name, fuzzy_result))
|
||||
return
|
||||
|
||||
for key in cmds[1:]:
|
||||
@ -354,13 +367,19 @@ async def help(ctx, *cmds: str):
|
||||
command = command.all_commands.get(key)
|
||||
if command is None:
|
||||
if use_embeds:
|
||||
await destination.send(
|
||||
embed=await ctx.bot.formatter.cmd_not_found(ctx, key)
|
||||
)
|
||||
fuzzy_result = await fuzzy_command_search(ctx, name)
|
||||
if fuzzy_result is not None:
|
||||
await destination.send(
|
||||
embed=await ctx.bot.formatter.cmd_not_found(
|
||||
ctx, name, description=fuzzy_result
|
||||
)
|
||||
)
|
||||
else:
|
||||
await destination.send(
|
||||
ctx.bot.command_not_found.format(key, fuzzy_command_search(ctx, name))
|
||||
)
|
||||
fuzzy_result = await fuzzy_command_search(ctx, name)
|
||||
if fuzzy_result is not None:
|
||||
await destination.send(
|
||||
ctx.bot.command_not_found.format(name, fuzzy_result)
|
||||
)
|
||||
return
|
||||
except AttributeError:
|
||||
if use_embeds:
|
||||
|
||||
@ -3,11 +3,19 @@ __all__ = ["safe_delete", "fuzzy_command_search"]
|
||||
from pathlib import Path
|
||||
import os
|
||||
import shutil
|
||||
import logging
|
||||
from redbot.core import commands
|
||||
from fuzzywuzzy import process
|
||||
from .chat_formatting import box
|
||||
|
||||
|
||||
def fuzzy_filter(record):
|
||||
return record.funcName != "extractWithoutOrder"
|
||||
|
||||
|
||||
logging.getLogger().addFilter(fuzzy_filter)
|
||||
|
||||
|
||||
def safe_delete(pth: Path):
|
||||
if pth.exists():
|
||||
for root, dirs, files in os.walk(str(pth)):
|
||||
@ -19,9 +27,49 @@ def safe_delete(pth: Path):
|
||||
shutil.rmtree(str(pth), ignore_errors=True)
|
||||
|
||||
|
||||
def fuzzy_command_search(ctx: commands.Context, term: str):
|
||||
async def filter_commands(ctx: commands.Context, extracted: list):
|
||||
return [
|
||||
i
|
||||
for i in extracted
|
||||
if i[1] >= 90
|
||||
and not i[0].hidden
|
||||
and await i[0].can_run(ctx)
|
||||
and all([await p.can_run(ctx) for p in i[0].parents])
|
||||
and not any([p.hidden for p in i[0].parents])
|
||||
]
|
||||
|
||||
|
||||
async def fuzzy_command_search(ctx: commands.Context, term: str):
|
||||
out = ""
|
||||
for pos, extracted in enumerate(process.extract(term, ctx.bot.walk_commands(), limit=5), 1):
|
||||
if ctx.guild is not None:
|
||||
enabled = await ctx.bot.db.guild(ctx.guild).fuzzy()
|
||||
else:
|
||||
enabled = await ctx.bot.db.fuzzy()
|
||||
if not enabled:
|
||||
return None
|
||||
alias_cog = ctx.bot.get_cog("Alias")
|
||||
if alias_cog is not None:
|
||||
is_alias, alias = await alias_cog.is_alias(ctx.guild, term)
|
||||
if is_alias:
|
||||
return None
|
||||
|
||||
customcom_cog = ctx.bot.get_cog("CustomCommands")
|
||||
if customcom_cog is not None:
|
||||
cmd_obj = customcom_cog.commandobj
|
||||
try:
|
||||
ccinfo = await cmd_obj.get(ctx.message, term)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
return None
|
||||
extracted_cmds = await filter_commands(
|
||||
ctx, process.extract(term, ctx.bot.walk_commands(), limit=5)
|
||||
)
|
||||
|
||||
if not extracted_cmds:
|
||||
return None
|
||||
|
||||
for pos, extracted in enumerate(extracted_cmds, 1):
|
||||
out += "{0}. {1.prefix}{2.qualified_name}{3}\n".format(
|
||||
pos,
|
||||
ctx,
|
||||
|
||||
21
setup.py
21
setup.py
@ -1,6 +1,10 @@
|
||||
from distutils.core import setup
|
||||
from distutils import ccompiler
|
||||
from distutils.errors import CCompilerError
|
||||
from pathlib import Path
|
||||
import re
|
||||
import importlib
|
||||
import tempfile
|
||||
|
||||
import os
|
||||
import sys
|
||||
@ -21,6 +25,20 @@ def get_package_list():
|
||||
return core
|
||||
|
||||
|
||||
def check_compiler_available():
|
||||
m = ccompiler.new_compiler()
|
||||
|
||||
with tempfile.TemporaryDirectory() as tdir:
|
||||
with tempfile.NamedTemporaryFile(prefix="dummy", suffix=".c", dir=tdir) as tfile:
|
||||
tfile.write(b"int main(int argc, char** argv) {return 0;}")
|
||||
tfile.seek(0)
|
||||
try:
|
||||
m.compile([tfile.name])
|
||||
except CCompilerError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_requirements():
|
||||
with open("requirements.txt") as f:
|
||||
requirements = f.read().splitlines()
|
||||
@ -31,6 +49,9 @@ def get_requirements():
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if not check_compiler_available(): # Can't compile python-Levensthein, so drop extra
|
||||
requirements.remove("fuzzywuzzy[speedup]<=0.16.0")
|
||||
requirements.append("fuzzywuzzy<=0.16.0")
|
||||
if IS_DEPLOYING or not (IS_TRAVIS or IS_RTD):
|
||||
requirements.append("discord.py>=1.0.0a0")
|
||||
if sys.platform.startswith("linux"):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user