From 976b3e8bf3e735ebf79e721d64714c7f9acc8bdf Mon Sep 17 00:00:00 2001 From: 0x5c Date: Mon, 27 Jan 2020 00:37:52 -0500 Subject: [PATCH] Improved error handling in commands - Changed all "status != 200" to raise a custom exception - Raise appropriate exceptions in 'grid' - Removed command-specific error handling in 'extctl' commands Fixes #146 --- CHANGELOG.md | 1 + common.py | 14 ++++++++++++++ exts/ae7q.py | 33 +++++++-------------------------- exts/grid.py | 38 +++++++++++++++++++------------------- exts/image.py | 5 +---- exts/morse.py | 2 +- exts/study.py | 8 ++------ exts/weather.py | 15 +++------------ main.py | 24 ++++++------------------ 9 files changed, 54 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d25fbdd..775b6c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - All currently-available pools can now be accessed by the `hamstudy` command. - The `hamstudy` command now uses the syntax `?hamstudy `. - Replaced `hamstudyanswer` command with answering by reaction. +- Removed all generic error handling from commands. ### Fixed - Fixed ditto marks (") appearing in the ae7q call command. - Fixed issue where incorrect table was parsed in ae7q call command. diff --git a/common.py b/common.py index 1795850..e9a5494 100644 --- a/common.py +++ b/common.py @@ -16,6 +16,8 @@ from datetime import datetime from pathlib import Path from types import SimpleNamespace +import aiohttp + import discord import discord.ext.commands as commands @@ -95,6 +97,18 @@ class ImagesGroup(collections.abc.Mapping): return str(self._images) +# --- Exceptions --- + +class BotHTTPError(Exception): + """Raised whan a requests fails (status != 200) in a command.""" + def __init__(self, response: aiohttp.ClientResponse): + msg = f"Request failed: {response.status} {response.reason}" + super().__init__(msg) + self.response = response + self.status = response.status + self.reason = response.reason + + # --- Converters --- class GlobalChannelConverter(commands.IDConverter): diff --git a/exts/ae7q.py b/exts/ae7q.py index bfcbcb6..51b3c6c 100644 --- a/exts/ae7q.py +++ b/exts/ae7q.py @@ -44,11 +44,7 @@ class AE7QCog(commands.Cog): async with self.session.get(base_url + callsign) as resp: if resp.status != 200: - embed.title = "Error in AE7Q call command" - embed.description = 'Could not load AE7Q' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) page = await resp.text() soup = BeautifulSoup(page, features="html.parser") @@ -114,11 +110,7 @@ class AE7QCog(commands.Cog): async with self.session.get(base_url + callsign) as resp: if resp.status != 200: - embed.title = "Error in AE7Q trustee command" - embed.description = 'Could not load AE7Q' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) page = await resp.text() soup = BeautifulSoup(page, features="html.parser") @@ -186,11 +178,7 @@ class AE7QCog(commands.Cog): async with self.session.get(base_url + callsign) as resp: if resp.status != 200: - embed.title = "Error in AE7Q applications command" - embed.description = 'Could not load AE7Q' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) page = await resp.text() soup = BeautifulSoup(page, features="html.parser") @@ -245,7 +233,8 @@ class AE7QCog(commands.Cog): await ctx.send(embed=embed) """ - pass + raise NotImplementedError("Application history lookup not yet supported. " + "Check back in a later version of the bot.") @_ae7q_lookup.command(name="frn", aliases=["f"], category=cmn.cat.lookup) async def _ae7q_frn(self, ctx: commands.Context, frn: str): @@ -261,11 +250,7 @@ class AE7QCog(commands.Cog): async with self.session.get(base_url + frn) as resp: if resp.status != 200: - embed.title = "Error in AE7Q frn command" - embed.description = 'Could not load AE7Q' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) page = await resp.text() soup = BeautifulSoup(page, features="html.parser") @@ -328,11 +313,7 @@ class AE7QCog(commands.Cog): async with self.session.get(base_url + licensee_id) as resp: if resp.status != 200: - embed.title = "Error in AE7Q licensee command" - embed.description = 'Could not load AE7Q' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) page = await resp.text() soup = BeautifulSoup(page, features="html.parser") diff --git a/exts/grid.py b/exts/grid.py index e8774ec..3abd6ef 100644 --- a/exts/grid.py +++ b/exts/grid.py @@ -24,27 +24,27 @@ class GridCog(commands.Cog): with negative being latitude South and longitude West.''' with ctx.typing(): grid = "**" - try: - latf = float(lat) + 90 - lonf = float(lon) + 180 - if 0 <= latf <= 180 and 0 <= lonf <= 360: - grid += chr(ord('A') + int(lonf / 20)) - grid += chr(ord('A') + int(latf / 10)) - grid += chr(ord('0') + int((lonf % 20)/2)) - grid += chr(ord('0') + int((latf % 10)/1)) - grid += chr(ord('a') + int((lonf - (int(lonf/2)*2)) / (5/60))) - grid += chr(ord('a') + int((latf - (int(latf/1)*1)) / (2.5/60))) - grid += "**" - embed = cmn.embed_factory(ctx) - embed.title = f'Maidenhead Grid Locator for {float(lat):.6f}, {float(lon):.6f}' - embed.description = grid - embed.colour = cmn.colours.good - else: - raise ValueError('Out of range.') - except ValueError as err: + latf = float(lat) + 90 + lonf = float(lon) + 180 + if 0 <= latf <= 180 and 0 <= lonf <= 360: + grid += chr(ord('A') + int(lonf / 20)) + grid += chr(ord('A') + int(latf / 10)) + grid += chr(ord('0') + int((lonf % 20)/2)) + grid += chr(ord('0') + int((latf % 10)/1)) + grid += chr(ord('a') + int((lonf - (int(lonf/2)*2)) / (5/60))) + grid += chr(ord('a') + int((latf - (int(latf/1)*1)) / (2.5/60))) + grid += "**" + embed = cmn.embed_factory(ctx) + embed.title = f'Maidenhead Grid Locator for {float(lat):.6f}, {float(lon):.6f}' + embed.description = grid + embed.colour = cmn.colours.good + else: embed = cmn.embed_factory(ctx) embed.title = f'Error generating grid square for {lat}, {lon}.' - embed.description = str(err) + embed.description = ("Coordinates out of range.\n" + "The valid ranges are:\n" + "- Latitude: `-90` to `+90`\n" + "- Longitude: `-180` to `+180`") embed.colour = cmn.colours.bad await ctx.send(embed=embed) diff --git a/exts/image.py b/exts/image.py index b5448d0..0388a32 100644 --- a/exts/image.py +++ b/exts/image.py @@ -90,10 +90,7 @@ class ImageCog(commands.Cog): embed.colour = cmn.colours.good async with self.session.get(self.gl_url) as resp: if resp.status != 200: - embed.description = 'Could not download file...' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) data = io.BytesIO(await resp.read()) embed.set_image(url=f'attachment://greyline.jpg') await ctx.send(embed=embed, file=discord.File(data, 'greyline.jpg')) diff --git a/exts/morse.py b/exts/morse.py index 0f61650..4d0671a 100644 --- a/exts/morse.py +++ b/exts/morse.py @@ -68,7 +68,7 @@ class MorseCog(commands.Cog): weight += len(cw_char) * 2 + 2 except KeyError: embed.title = 'Error in calculation of CW weight' - embed.description = f'Unknown character {char} in callsign' + embed.description = f'Unknown character `{char}` in message' embed.colour = cmn.colours.bad await ctx.send(embed=embed) return diff --git a/exts/study.py b/exts/study.py index b6e11c8..5180704 100644 --- a/exts/study.py +++ b/exts/study.py @@ -110,11 +110,7 @@ class StudyCog(commands.Cog): async with self.session.get(f'https://hamstudy.org/pools/{pool}') as resp: if resp.status != 200: - embed.title = 'Error in HamStudy command' - embed.description = 'Could not load questions' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) pool = json.loads(await resp.read())['pool'] # Select a question @@ -172,7 +168,7 @@ class StudyCog(commands.Cog): async def hamstudy_get_pools(self): async with self.session.get('https://hamstudy.org/pools/') as resp: if resp.status != 200: - raise ConnectionError + raise cmn.BotHTTPError(resp) else: pools_dict = json.loads(await resp.read()) diff --git a/exts/weather.py b/exts/weather.py index e877a02..92dd09d 100644 --- a/exts/weather.py +++ b/exts/weather.py @@ -34,10 +34,7 @@ class WeatherCog(commands.Cog): embed.colour = cmn.colours.good async with self.session.get('http://www.hamqsl.com/solarsun.php') as resp: if resp.status != 200: - embed.description = 'Could not download file...' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) data = io.BytesIO(await resp.read()) embed.set_image(url=f'attachment://condx.png') await ctx.send(embed=embed, file=discord.File(data, 'condx.png')) @@ -84,10 +81,7 @@ See help for weather command for possible location types. Add a `-c` or `-f` to loc = loc.replace(' ', '+') async with self.session.get(f'http://wttr.in/{loc}_{units}pnFQ.png') as resp: if resp.status != 200: - embed.description = 'Could not download file...' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) data = io.BytesIO(await resp.read()) embed.set_image(url=f'attachment://wttr_forecast.png') await ctx.send(embed=embed, file=discord.File(data, 'wttr_forecast.png')) @@ -118,10 +112,7 @@ See help for weather command for possible location types. Add a `-c` or `-f` to loc = loc.replace(' ', '+') async with self.session.get(f'http://wttr.in/{loc}_0{units}pnFQ.png') as resp: if resp.status != 200: - embed.description = 'Could not download file...' - embed.colour = cmn.colours.bad - await ctx.send(embed=embed) - return + raise cmn.BotHTTPError(resp) data = io.BytesIO(await resp.read()) embed.set_image(url=f'attachment://wttr_now.png') await ctx.send(embed=embed, file=discord.File(data, 'wttr_now.png')) diff --git a/main.py b/main.py index 01ddb0b..c93210d 100644 --- a/main.py +++ b/main.py @@ -103,12 +103,8 @@ async def _extctl_list(ctx: commands.Context): @_extctl.command(name="load", aliases=["ld"]) async def _extctl_load(ctx: commands.Context, extension: str): - try: - bot.load_extension(ext_dir + "." + extension) - await cmn.add_react(ctx.message, cmn.emojis.check_mark) - except commands.ExtensionError as ex: - embed = cmn.error_embed_factory(ctx, ex, bot.qrm.debug_mode) - await ctx.send(embed=embed) + bot.load_extension(ext_dir + "." + extension) + await cmn.add_react(ctx.message, cmn.emojis.check_mark) @_extctl.command(name="reload", aliases=["rl", "r", "relaod"]) @@ -117,22 +113,14 @@ async def _extctl_reload(ctx: commands.Context, extension: str): pika = bot.get_emoji(opt.pika) if pika: await cmn.add_react(ctx.message, pika) - try: - bot.reload_extension(ext_dir + "." + extension) - await cmn.add_react(ctx.message, cmn.emojis.check_mark) - except commands.ExtensionError as ex: - embed = cmn.error_embed_factory(ctx, ex, bot.qrm.debug_mode) - await ctx.send(embed=embed) + bot.reload_extension(ext_dir + "." + extension) + await cmn.add_react(ctx.message, cmn.emojis.check_mark) @_extctl.command(name="unload", aliases=["ul"]) async def _extctl_unload(ctx: commands.Context, extension: str): - try: - bot.unload_extension(ext_dir + "." + extension) - await cmn.add_react(ctx.message, cmn.emojis.check_mark) - except commands.ExtensionError as ex: - embed = cmn.error_embed_factory(ctx, ex, bot.qrm.debug_mode) - await ctx.send(embed=embed) + bot.unload_extension(ext_dir + "." + extension) + await cmn.add_react(ctx.message, cmn.emojis.check_mark) # --- Events ---