mirror of
https://github.com/miaowware/qrm2.git
synced 2024-09-29 23:36:36 -04:00
Merge pull request #147 from classabbyamp/error-handling
Better command error handling
This commit is contained in:
commit
e1d4b2eab5
@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
### Added
|
||||
- Flag emojis to commands with countries.
|
||||
- Image attribution and description to "image" commands.
|
||||
- Better user-facing command error handling.
|
||||
- New key in options.py: pika.
|
||||
|
||||
|
||||
|
13
common.py
13
common.py
@ -42,8 +42,12 @@ cat = SimpleNamespace(lookup='Information Lookup',
|
||||
study='Exam Study',
|
||||
weather='Land and Space Weather')
|
||||
|
||||
emojis = SimpleNamespace(good='✅',
|
||||
bad='❌')
|
||||
emojis = SimpleNamespace(check_mark='✅',
|
||||
x='❌',
|
||||
warning='⚠️',
|
||||
question='❓',
|
||||
no_entry='⛔',
|
||||
bangbang='‼️')
|
||||
|
||||
paths = SimpleNamespace(data=Path("./data/"),
|
||||
resources=Path("./resources/"),
|
||||
@ -106,7 +110,7 @@ def error_embed_factory(ctx: commands.Context, exception: Exception, debug_mode:
|
||||
else:
|
||||
fmtd_ex = traceback.format_exception_only(exception.__class__, exception)
|
||||
embed = embed_factory(ctx)
|
||||
embed.title = "Error"
|
||||
embed.title = "⚠️ Error"
|
||||
embed.description = "```\n" + '\n'.join(fmtd_ex) + "```"
|
||||
embed.colour = colours.bad
|
||||
return embed
|
||||
@ -124,5 +128,4 @@ async def add_react(msg: discord.Message, react: str):
|
||||
async def check_if_owner(ctx: commands.Context):
|
||||
if ctx.author.id in opt.owners_uids:
|
||||
return True
|
||||
await add_react(ctx.message, emojis.bad)
|
||||
return False
|
||||
raise commands.NotOwner
|
||||
|
26
exts/base.py
26
exts/base.py
@ -106,14 +106,18 @@ class BaseCog(commands.Cog):
|
||||
embed.set_thumbnail(url=str(self.bot.user.avatar_url))
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="ping")
|
||||
@commands.command(name="ping", aliases=['beep'])
|
||||
async def _ping(self, ctx: commands.Context):
|
||||
"""Show the current latency to the discord endpoint."""
|
||||
content = ctx.message.author.mention if random.random() < 0.05 else ''
|
||||
embed = cmn.embed_factory(ctx)
|
||||
embed.title = "**Pong!**"
|
||||
content = ''
|
||||
if ctx.invoked_with == "beep":
|
||||
embed.title = "**Boop!**"
|
||||
else:
|
||||
content = ctx.message.author.mention if random.random() < 0.05 else ''
|
||||
embed.title = "🏓 **Pong!**"
|
||||
embed.description = f'Current ping is {self.bot.latency*1000:.1f} ms'
|
||||
await ctx.send(content=content, embed=embed)
|
||||
await ctx.send(content, embed=embed)
|
||||
|
||||
@commands.command(name="changelog", aliases=["clog"])
|
||||
async def _changelog(self, ctx: commands.Context):
|
||||
@ -138,6 +142,20 @@ class BaseCog(commands.Cog):
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="issue")
|
||||
async def _issue(self, ctx: commands.Context):
|
||||
"""Shows how to create an issue for the bot."""
|
||||
embed = cmn.embed_factory(ctx)
|
||||
embed.title = "Found a bug? Have a feature request?"
|
||||
embed.description = ("Submit an issue on the [issue tracker]"
|
||||
"(https://github.com/classabbyamp/discord-qrm2/issues)!")
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command(name="bruce", hidden=True)
|
||||
async def _b_issue(self, ctx: commands.Context):
|
||||
"""Shows how to create an issue for the bot."""
|
||||
await ctx.invoke(self._issue)
|
||||
|
||||
@commands.command(name="echo", aliases=["e"], hidden=True)
|
||||
@commands.check(cmn.check_if_owner)
|
||||
async def _echo(self, ctx: commands.Context, channel: commands.TextChannelConverter, *, msg: str):
|
||||
|
58
main.py
58
main.py
@ -8,6 +8,9 @@ This file is part of discord-qrm2 and is released under the terms of the GNU
|
||||
General Public License, version 2.
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
from datetime import time, datetime
|
||||
import random
|
||||
from types import SimpleNamespace
|
||||
@ -42,6 +45,8 @@ bot = commands.Bot(command_prefix=opt.prefix,
|
||||
bot.qrm = SimpleNamespace()
|
||||
bot.qrm.session = aiohttp.ClientSession(headers={'User-Agent': f'discord-qrm2/{info.release}'})
|
||||
|
||||
bot.qrm.debug_mode = debug_mode
|
||||
|
||||
|
||||
# --- Commands ---
|
||||
|
||||
@ -51,7 +56,7 @@ async def _restart_bot(ctx: commands.Context):
|
||||
"""Restarts the bot."""
|
||||
await bot.qrm.session.close()
|
||||
global exit_code
|
||||
await cmn.add_react(ctx.message, cmn.emojis.good)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.check_mark)
|
||||
print(f"[**] Restarting! Requested by {ctx.author}.")
|
||||
exit_code = 42 # Signals to the wrapper script that the bot needs to be restarted.
|
||||
await bot.logout()
|
||||
@ -63,7 +68,7 @@ async def _shutdown_bot(ctx: commands.Context):
|
||||
"""Shuts down the bot."""
|
||||
await bot.qrm.session.close()
|
||||
global exit_code
|
||||
await cmn.add_react(ctx.message, cmn.emojis.good)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.check_mark)
|
||||
print(f"[**] Shutting down! Requested by {ctx.author}.")
|
||||
exit_code = 0 # Signals to the wrapper script that the bot should not be restarted.
|
||||
await bot.logout()
|
||||
@ -92,9 +97,9 @@ async def _extctl_list(ctx: commands.Context):
|
||||
async def _extctl_load(ctx: commands.Context, extension: str):
|
||||
try:
|
||||
bot.load_extension(ext_dir + "." + extension)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.good)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.check_mark)
|
||||
except commands.ExtensionError as ex:
|
||||
embed = cmn.error_embed_factory(ctx, ex, debug_mode)
|
||||
embed = cmn.error_embed_factory(ctx, ex, bot.qrm.debug_mode)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
@ -106,9 +111,9 @@ async def _extctl_reload(ctx: commands.Context, extension: str):
|
||||
await cmn.add_react(ctx.message, pika)
|
||||
try:
|
||||
bot.reload_extension(ext_dir + "." + extension)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.good)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.check_mark)
|
||||
except commands.ExtensionError as ex:
|
||||
embed = cmn.error_embed_factory(ctx, ex, debug_mode)
|
||||
embed = cmn.error_embed_factory(ctx, ex, bot.qrm.debug_mode)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
@ -116,9 +121,9 @@ async def _extctl_reload(ctx: commands.Context, extension: str):
|
||||
async def _extctl_unload(ctx: commands.Context, extension: str):
|
||||
try:
|
||||
bot.unload_extension(ext_dir + "." + extension)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.good)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.check_mark)
|
||||
except commands.ExtensionError as ex:
|
||||
embed = cmn.error_embed_factory(ctx, ex, debug_mode)
|
||||
embed = cmn.error_embed_factory(ctx, ex, bot.qrm.debug_mode)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
@ -146,6 +151,37 @@ async def on_message(message):
|
||||
await bot.process_commands(message)
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_command_error(ctx: commands.Context, err: commands.CommandError):
|
||||
if isinstance(err, commands.UserInputError):
|
||||
await cmn.add_react(ctx.message, cmn.emojis.warning)
|
||||
await ctx.send_help(ctx.command)
|
||||
elif isinstance(err, commands.CommandNotFound) and not ctx.invoked_with.startswith("?"):
|
||||
await cmn.add_react(ctx.message, cmn.emojis.question)
|
||||
elif isinstance(err, commands.CheckFailure):
|
||||
# Add handling of other subclasses of CheckFailure as needed.
|
||||
if isinstance(err, commands.NotOwner):
|
||||
await cmn.add_react(ctx.message, cmn.emojis.no_entry)
|
||||
else:
|
||||
await cmn.add_react(ctx.message, cmn.emojis.x)
|
||||
elif isinstance(err, commands.DisabledCommand):
|
||||
await cmn.add_react(ctx.message, cmn.emojis.bangbang)
|
||||
elif isinstance(err, (commands.CommandInvokeError, commands.ConversionError)):
|
||||
# Emulating discord.py's default beaviour.
|
||||
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
|
||||
traceback.print_exception(type(err), err, err.__traceback__, file=sys.stderr)
|
||||
|
||||
embed = cmn.error_embed_factory(ctx, err.original, bot.qrm.debug_mode)
|
||||
embed.description += f"\n`{type(err).__name__}`"
|
||||
await cmn.add_react(ctx.message, cmn.emojis.warning)
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
# Emulating discord.py's default beaviour. (safest bet)
|
||||
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
|
||||
traceback.print_exception(type(err), err, err.__traceback__, file=sys.stderr)
|
||||
await cmn.add_react(ctx.message, cmn.emojis.warning)
|
||||
|
||||
|
||||
# --- Tasks ---
|
||||
|
||||
@tasks.loop(minutes=5)
|
||||
@ -194,19 +230,19 @@ try:
|
||||
|
||||
except discord.LoginFailure as ex:
|
||||
# Miscellaneous authentications errors: borked token and co
|
||||
if debug_mode:
|
||||
if bot.qrm.debug_mode:
|
||||
raise
|
||||
raise SystemExit("Error: Failed to authenticate: {}".format(ex))
|
||||
|
||||
except discord.ConnectionClosed as ex:
|
||||
# When the connection to the gateway (websocket) is closed
|
||||
if debug_mode:
|
||||
if bot.qrm.debug_mode:
|
||||
raise
|
||||
raise SystemExit("Error: Discord gateway connection closed: [Code {}] {}".format(ex.code, ex.reason))
|
||||
|
||||
except ConnectionResetError as ex:
|
||||
# More generic connection reset error
|
||||
if debug_mode:
|
||||
if bot.qrm.debug_mode:
|
||||
raise
|
||||
raise SystemExit("ConnectionResetError: {}".format(ex))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user