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
This commit is contained in:
0x5c 2020-01-27 00:37:52 -05:00
parent 9113638b67
commit 976b3e8bf3
No known key found for this signature in database
GPG Key ID: 82039FC95E3FE970
9 changed files with 54 additions and 86 deletions

View File

@ -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. - All currently-available pools can now be accessed by the `hamstudy` command.
- The `hamstudy` command now uses the syntax `?hamstudy <country> <pool>`. - The `hamstudy` command now uses the syntax `?hamstudy <country> <pool>`.
- Replaced `hamstudyanswer` command with answering by reaction. - Replaced `hamstudyanswer` command with answering by reaction.
- Removed all generic error handling from commands.
### Fixed ### Fixed
- Fixed ditto marks (") appearing in the ae7q call command. - Fixed ditto marks (") appearing in the ae7q call command.
- Fixed issue where incorrect table was parsed in ae7q call command. - Fixed issue where incorrect table was parsed in ae7q call command.

View File

@ -16,6 +16,8 @@ from datetime import datetime
from pathlib import Path from pathlib import Path
from types import SimpleNamespace from types import SimpleNamespace
import aiohttp
import discord import discord
import discord.ext.commands as commands import discord.ext.commands as commands
@ -95,6 +97,18 @@ class ImagesGroup(collections.abc.Mapping):
return str(self._images) 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 --- # --- Converters ---
class GlobalChannelConverter(commands.IDConverter): class GlobalChannelConverter(commands.IDConverter):

View File

@ -44,11 +44,7 @@ class AE7QCog(commands.Cog):
async with self.session.get(base_url + callsign) as resp: async with self.session.get(base_url + callsign) as resp:
if resp.status != 200: if resp.status != 200:
embed.title = "Error in AE7Q call command" raise cmn.BotHTTPError(resp)
embed.description = 'Could not load AE7Q'
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
page = await resp.text() page = await resp.text()
soup = BeautifulSoup(page, features="html.parser") soup = BeautifulSoup(page, features="html.parser")
@ -114,11 +110,7 @@ class AE7QCog(commands.Cog):
async with self.session.get(base_url + callsign) as resp: async with self.session.get(base_url + callsign) as resp:
if resp.status != 200: if resp.status != 200:
embed.title = "Error in AE7Q trustee command" raise cmn.BotHTTPError(resp)
embed.description = 'Could not load AE7Q'
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
page = await resp.text() page = await resp.text()
soup = BeautifulSoup(page, features="html.parser") soup = BeautifulSoup(page, features="html.parser")
@ -186,11 +178,7 @@ class AE7QCog(commands.Cog):
async with self.session.get(base_url + callsign) as resp: async with self.session.get(base_url + callsign) as resp:
if resp.status != 200: if resp.status != 200:
embed.title = "Error in AE7Q applications command" raise cmn.BotHTTPError(resp)
embed.description = 'Could not load AE7Q'
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
page = await resp.text() page = await resp.text()
soup = BeautifulSoup(page, features="html.parser") soup = BeautifulSoup(page, features="html.parser")
@ -245,7 +233,8 @@ class AE7QCog(commands.Cog):
await ctx.send(embed=embed) 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) @_ae7q_lookup.command(name="frn", aliases=["f"], category=cmn.cat.lookup)
async def _ae7q_frn(self, ctx: commands.Context, frn: str): 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: async with self.session.get(base_url + frn) as resp:
if resp.status != 200: if resp.status != 200:
embed.title = "Error in AE7Q frn command" raise cmn.BotHTTPError(resp)
embed.description = 'Could not load AE7Q'
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
page = await resp.text() page = await resp.text()
soup = BeautifulSoup(page, features="html.parser") 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: async with self.session.get(base_url + licensee_id) as resp:
if resp.status != 200: if resp.status != 200:
embed.title = "Error in AE7Q licensee command" raise cmn.BotHTTPError(resp)
embed.description = 'Could not load AE7Q'
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
page = await resp.text() page = await resp.text()
soup = BeautifulSoup(page, features="html.parser") soup = BeautifulSoup(page, features="html.parser")

View File

@ -24,7 +24,6 @@ class GridCog(commands.Cog):
with negative being latitude South and longitude West.''' with negative being latitude South and longitude West.'''
with ctx.typing(): with ctx.typing():
grid = "**" grid = "**"
try:
latf = float(lat) + 90 latf = float(lat) + 90
lonf = float(lon) + 180 lonf = float(lon) + 180
if 0 <= latf <= 180 and 0 <= lonf <= 360: if 0 <= latf <= 180 and 0 <= lonf <= 360:
@ -40,11 +39,12 @@ with negative being latitude South and longitude West.'''
embed.description = grid embed.description = grid
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
else: else:
raise ValueError('Out of range.')
except ValueError as err:
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Error generating grid square for {lat}, {lon}.' 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 embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)

View File

@ -90,10 +90,7 @@ class ImageCog(commands.Cog):
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
async with self.session.get(self.gl_url) as resp: async with self.session.get(self.gl_url) as resp:
if resp.status != 200: if resp.status != 200:
embed.description = 'Could not download file...' raise cmn.BotHTTPError(resp)
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
data = io.BytesIO(await resp.read()) data = io.BytesIO(await resp.read())
embed.set_image(url=f'attachment://greyline.jpg') embed.set_image(url=f'attachment://greyline.jpg')
await ctx.send(embed=embed, file=discord.File(data, 'greyline.jpg')) await ctx.send(embed=embed, file=discord.File(data, 'greyline.jpg'))

View File

@ -68,7 +68,7 @@ class MorseCog(commands.Cog):
weight += len(cw_char) * 2 + 2 weight += len(cw_char) * 2 + 2
except KeyError: except KeyError:
embed.title = 'Error in calculation of CW weight' 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 embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return

View File

@ -110,11 +110,7 @@ class StudyCog(commands.Cog):
async with self.session.get(f'https://hamstudy.org/pools/{pool}') as resp: async with self.session.get(f'https://hamstudy.org/pools/{pool}') as resp:
if resp.status != 200: if resp.status != 200:
embed.title = 'Error in HamStudy command' raise cmn.BotHTTPError(resp)
embed.description = 'Could not load questions'
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
pool = json.loads(await resp.read())['pool'] pool = json.loads(await resp.read())['pool']
# Select a question # Select a question
@ -172,7 +168,7 @@ class StudyCog(commands.Cog):
async def hamstudy_get_pools(self): async def hamstudy_get_pools(self):
async with self.session.get('https://hamstudy.org/pools/') as resp: async with self.session.get('https://hamstudy.org/pools/') as resp:
if resp.status != 200: if resp.status != 200:
raise ConnectionError raise cmn.BotHTTPError(resp)
else: else:
pools_dict = json.loads(await resp.read()) pools_dict = json.loads(await resp.read())

View File

@ -34,10 +34,7 @@ class WeatherCog(commands.Cog):
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
async with self.session.get('http://www.hamqsl.com/solarsun.php') as resp: async with self.session.get('http://www.hamqsl.com/solarsun.php') as resp:
if resp.status != 200: if resp.status != 200:
embed.description = 'Could not download file...' raise cmn.BotHTTPError(resp)
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
data = io.BytesIO(await resp.read()) data = io.BytesIO(await resp.read())
embed.set_image(url=f'attachment://condx.png') embed.set_image(url=f'attachment://condx.png')
await ctx.send(embed=embed, file=discord.File(data, '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(' ', '+') loc = loc.replace(' ', '+')
async with self.session.get(f'http://wttr.in/{loc}_{units}pnFQ.png') as resp: async with self.session.get(f'http://wttr.in/{loc}_{units}pnFQ.png') as resp:
if resp.status != 200: if resp.status != 200:
embed.description = 'Could not download file...' raise cmn.BotHTTPError(resp)
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
data = io.BytesIO(await resp.read()) data = io.BytesIO(await resp.read())
embed.set_image(url=f'attachment://wttr_forecast.png') embed.set_image(url=f'attachment://wttr_forecast.png')
await ctx.send(embed=embed, file=discord.File(data, '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(' ', '+') loc = loc.replace(' ', '+')
async with self.session.get(f'http://wttr.in/{loc}_0{units}pnFQ.png') as resp: async with self.session.get(f'http://wttr.in/{loc}_0{units}pnFQ.png') as resp:
if resp.status != 200: if resp.status != 200:
embed.description = 'Could not download file...' raise cmn.BotHTTPError(resp)
embed.colour = cmn.colours.bad
await ctx.send(embed=embed)
return
data = io.BytesIO(await resp.read()) data = io.BytesIO(await resp.read())
embed.set_image(url=f'attachment://wttr_now.png') embed.set_image(url=f'attachment://wttr_now.png')
await ctx.send(embed=embed, file=discord.File(data, 'wttr_now.png')) await ctx.send(embed=embed, file=discord.File(data, 'wttr_now.png'))

12
main.py
View File

@ -103,12 +103,8 @@ async def _extctl_list(ctx: commands.Context):
@_extctl.command(name="load", aliases=["ld"]) @_extctl.command(name="load", aliases=["ld"])
async def _extctl_load(ctx: commands.Context, extension: str): async def _extctl_load(ctx: commands.Context, extension: str):
try:
bot.load_extension(ext_dir + "." + extension) bot.load_extension(ext_dir + "." + extension)
await cmn.add_react(ctx.message, cmn.emojis.check_mark) 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)
@_extctl.command(name="reload", aliases=["rl", "r", "relaod"]) @_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) pika = bot.get_emoji(opt.pika)
if pika: if pika:
await cmn.add_react(ctx.message, pika) await cmn.add_react(ctx.message, pika)
try:
bot.reload_extension(ext_dir + "." + extension) bot.reload_extension(ext_dir + "." + extension)
await cmn.add_react(ctx.message, cmn.emojis.check_mark) 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)
@_extctl.command(name="unload", aliases=["ul"]) @_extctl.command(name="unload", aliases=["ul"])
async def _extctl_unload(ctx: commands.Context, extension: str): async def _extctl_unload(ctx: commands.Context, extension: str):
try:
bot.unload_extension(ext_dir + "." + extension) bot.unload_extension(ext_dir + "." + extension)
await cmn.add_react(ctx.message, cmn.emojis.check_mark) 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)
# --- Events --- # --- Events ---