Normalised string quote type

- "" instead of '', except for dictionary lookups in f-strings

Element of #142
New year lint removal
This commit is contained in:
0x5c 2020-01-30 06:15:42 -05:00
parent 29e75c38e1
commit 29d0440d3d
No known key found for this signature in database
GPG Key ID: 82039FC95E3FE970
18 changed files with 491 additions and 491 deletions

View File

@ -34,24 +34,24 @@ colours = SimpleNamespace(good=0x43B581,
neutral=0x7289DA, neutral=0x7289DA,
bad=0xF04747) bad=0xF04747)
# meow # meow
cat = SimpleNamespace(lookup='Information Lookup', cat = SimpleNamespace(lookup="Information Lookup",
fun='Fun', fun="Fun",
maps='Mapping', maps="Mapping",
ref='Reference', ref="Reference",
study='Exam Study', study="Exam Study",
weather='Land and Space Weather', weather="Land and Space Weather",
admin='Bot Control') admin="Bot Control")
emojis = SimpleNamespace(check_mark='', emojis = SimpleNamespace(check_mark="",
x='', x="",
warning='⚠️', warning="⚠️",
question='', question="",
no_entry='', no_entry="",
bangbang='‼️', bangbang="‼️",
a='🇦', a="🇦",
b='🇧', b="🇧",
c='🇨', c="🇨",
d='🇩') d="🇩")
paths = SimpleNamespace(data=Path("./data/"), paths = SimpleNamespace(data=Path("./data/"),
resources=Path("./resources/"), resources=Path("./resources/"),
@ -117,7 +117,7 @@ class GlobalChannelConverter(commands.IDConverter):
async def convert(self, ctx: commands.Context, argument: str): async def convert(self, ctx: commands.Context, argument: str):
bot = ctx.bot bot = ctx.bot
guild = ctx.guild guild = ctx.guild
match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument) match = self._get_id_match(argument) or re.match(r"<#([0-9]+)>$", argument)
result = None result = None
if match is None: if match is None:
# not a mention/ID # not a mention/ID
@ -150,7 +150,7 @@ def error_embed_factory(ctx: commands.Context, exception: Exception, debug_mode:
fmtd_ex = traceback.format_exception_only(exception.__class__, exception) fmtd_ex = traceback.format_exception_only(exception.__class__, exception)
embed = embed_factory(ctx) embed = embed_factory(ctx)
embed.title = "⚠️ Error" embed.title = "⚠️ Error"
embed.description = "```\n" + '\n'.join(fmtd_ex) + "```" embed.description = "```\n" + "\n".join(fmtd_ex) + "```"
embed.colour = colours.bad embed.colour = colours.bad
return embed return embed

View File

@ -29,16 +29,16 @@ class AE7QCog(commands.Cog):
@commands.group(name="ae7q", aliases=["ae"], category=cmn.cat.lookup) @commands.group(name="ae7q", aliases=["ae"], category=cmn.cat.lookup)
async def _ae7q_lookup(self, ctx: commands.Context): async def _ae7q_lookup(self, ctx: commands.Context):
'''Look up a callsign, FRN, or Licensee ID on [ae7q.com](http://ae7q.com/).''' """Look up a callsign, FRN, or Licensee ID on [ae7q.com](http://ae7q.com/)."""
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send_help(ctx.command) await ctx.send_help(ctx.command)
@_ae7q_lookup.command(name="call", aliases=["c"], category=cmn.cat.lookup) @_ae7q_lookup.command(name="call", aliases=["c"], category=cmn.cat.lookup)
async def _ae7q_call(self, ctx: commands.Context, callsign: str): async def _ae7q_call(self, ctx: commands.Context, callsign: str):
'''Look up the history of a callsign on [ae7q.com](http://ae7q.com/).''' """Look up the history of a callsign on [ae7q.com](http://ae7q.com/)."""
with ctx.typing(): with ctx.typing():
callsign = callsign.upper() callsign = callsign.upper()
desc = '' desc = ""
base_url = "http://ae7q.com/query/data/CallHistory.php?CALL=" base_url = "http://ae7q.com/query/data/CallHistory.php?CALL="
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
@ -56,20 +56,20 @@ class AE7QCog(commands.Cog):
if len(table[0]) == 1: if len(table[0]) == 1:
for row in table: for row in table:
desc += " ".join(row.getText().split()) desc += " ".join(row.getText().split())
desc += '\n' desc += "\n"
desc = desc.replace(callsign, f'`{callsign}`') desc = desc.replace(callsign, f"`{callsign}`")
table = tables[1] table = tables[1]
table_headers = table[0].find_all("th") table_headers = table[0].find_all("th")
first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None
# catch if the wrong table was selected # catch if the wrong table was selected
if first_header is None or first_header != 'Entity Name': if first_header is None or first_header != "Entity Name":
embed.title = f"AE7Q History for {callsign}" embed.title = f"AE7Q History for {callsign}"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + callsign embed.url = base_url + callsign
embed.description = desc embed.description = desc
embed.description += f'\nNo records found for `{callsign}`' embed.description += f"\nNo records found for `{callsign}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
@ -82,18 +82,18 @@ class AE7QCog(commands.Cog):
# add the first three rows of the table to the embed # add the first three rows of the table to the embed
for row in table[0:3]: for row in table[0:3]:
header = f'**{row[0]}** ({row[1]})' # **Name** (Applicant Type) header = f"**{row[0]}** ({row[1]})" # **Name** (Applicant Type)
body = (f'Class: *{row[2]}*\n' body = (f"Class: *{row[2]}*\n"
f'Region: *{row[3]}*\n' f"Region: *{row[3]}*\n"
f'Status: *{row[4]}*\n' f"Status: *{row[4]}*\n"
f'Granted: *{row[5]}*\n' f"Granted: *{row[5]}*\n"
f'Effective: *{row[6]}*\n' f"Effective: *{row[6]}*\n"
f'Cancelled: *{row[7]}*\n' f"Cancelled: *{row[7]}*\n"
f'Expires: *{row[8]}*') f"Expires: *{row[8]}*")
embed.add_field(name=header, value=body, inline=False) embed.add_field(name=header, value=body, inline=False)
if len(table) > 3: if len(table) > 3:
desc += f'\nRecords 1 to 3 of {len(table)}. See ae7q.com for more...' desc += f"\nRecords 1 to 3 of {len(table)}. See ae7q.com for more..."
embed.description = desc embed.description = desc
@ -101,10 +101,10 @@ class AE7QCog(commands.Cog):
@_ae7q_lookup.command(name="trustee", aliases=["t"], category=cmn.cat.lookup) @_ae7q_lookup.command(name="trustee", aliases=["t"], category=cmn.cat.lookup)
async def _ae7q_trustee(self, ctx: commands.Context, callsign: str): async def _ae7q_trustee(self, ctx: commands.Context, callsign: str):
'''Look up the licenses for which a licensee is trustee on [ae7q.com](http://ae7q.com/).''' """Look up the licenses for which a licensee is trustee on [ae7q.com](http://ae7q.com/)."""
with ctx.typing(): with ctx.typing():
callsign = callsign.upper() callsign = callsign.upper()
desc = '' desc = ""
base_url = "http://ae7q.com/query/data/CallHistory.php?CALL=" base_url = "http://ae7q.com/query/data/CallHistory.php?CALL="
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
@ -123,12 +123,12 @@ class AE7QCog(commands.Cog):
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + callsign embed.url = base_url + callsign
embed.description = desc embed.description = desc
embed.description += f'\nNo records found for `{callsign}`' embed.description += f"\nNo records found for `{callsign}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
table_headers = table[0].find_all("th") table_headers = table[0].find_all("th")
first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None
# catch if the wrong table was selected # catch if the wrong table was selected
if first_header is None or not first_header.startswith("With"): if first_header is None or not first_header.startswith("With"):
@ -136,7 +136,7 @@ class AE7QCog(commands.Cog):
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + callsign embed.url = base_url + callsign
embed.description = desc embed.description = desc
embed.description += f'\nNo records found for `{callsign}`' embed.description += f"\nNo records found for `{callsign}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
@ -149,18 +149,18 @@ class AE7QCog(commands.Cog):
# add the first three rows of the table to the embed # add the first three rows of the table to the embed
for row in table[0:3]: for row in table[0:3]:
header = f'**{row[0]}** ({row[3]})' # **Name** (Applicant Type) header = f"**{row[0]}** ({row[3]})" # **Name** (Applicant Type)
body = (f'Name: *{row[2]}*\n' body = (f"Name: *{row[2]}*\n"
f'Region: *{row[1]}*\n' f"Region: *{row[1]}*\n"
f'Status: *{row[4]}*\n' f"Status: *{row[4]}*\n"
f'Granted: *{row[5]}*\n' f"Granted: *{row[5]}*\n"
f'Effective: *{row[6]}*\n' f"Effective: *{row[6]}*\n"
f'Cancelled: *{row[7]}*\n' f"Cancelled: *{row[7]}*\n"
f'Expires: *{row[8]}*') f"Expires: *{row[8]}*")
embed.add_field(name=header, value=body, inline=False) embed.add_field(name=header, value=body, inline=False)
if len(table) > 3: if len(table) > 3:
desc += f'\nRecords 1 to 3 of {len(table)}. See ae7q.com for more...' desc += f"\nRecords 1 to 3 of {len(table)}. See ae7q.com for more..."
embed.description = desc embed.description = desc
@ -168,11 +168,11 @@ class AE7QCog(commands.Cog):
@_ae7q_lookup.command(name="applications", aliases=["a"], category=cmn.cat.lookup) @_ae7q_lookup.command(name="applications", aliases=["a"], category=cmn.cat.lookup)
async def _ae7q_applications(self, ctx: commands.Context, callsign: str): async def _ae7q_applications(self, ctx: commands.Context, callsign: str):
'''Look up the application history for a callsign on [ae7q.com](http://ae7q.com/).''' """Look up the application history for a callsign on [ae7q.com](http://ae7q.com/)."""
""" """
with ctx.typing(): with ctx.typing():
callsign = callsign.upper() callsign = callsign.upper()
desc = '' desc = ""
base_url = "http://ae7q.com/query/data/CallHistory.php?CALL=" base_url = "http://ae7q.com/query/data/CallHistory.php?CALL="
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
@ -190,14 +190,14 @@ class AE7QCog(commands.Cog):
if len(table[0]) == 1: if len(table[0]) == 1:
for row in table: for row in table:
desc += " ".join(row.getText().split()) desc += " ".join(row.getText().split())
desc += '\n' desc += "\n"
desc = desc.replace(callsign, f'`{callsign}`') desc = desc.replace(callsign, f"`{callsign}`")
# select the last table to get applications # select the last table to get applications
table = tables[-1] table = tables[-1]
table_headers = table[0].find_all("th") table_headers = table[0].find_all("th")
first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None
# catch if the wrong table was selected # catch if the wrong table was selected
if first_header is None or not first_header.startswith("Receipt"): if first_header is None or not first_header.startswith("Receipt"):
@ -205,7 +205,7 @@ class AE7QCog(commands.Cog):
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + callsign embed.url = base_url + callsign
embed.description = desc embed.description = desc
embed.description += f'\nNo records found for `{callsign}`' embed.description += f"\nNo records found for `{callsign}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
@ -218,16 +218,16 @@ class AE7QCog(commands.Cog):
# add the first three rows of the table to the embed # add the first three rows of the table to the embed
for row in table[0:3]: for row in table[0:3]:
header = f'**{row[1]}** ({row[3]})' # **Name** (Callsign) header = f"**{row[1]}** ({row[3]})" # **Name** (Callsign)
body = (f'Received: *{row[0]}*\n' body = (f"Received: *{row[0]}*\n"
f'Region: *{row[2]}*\n' f"Region: *{row[2]}*\n"
f'Purpose: *{row[5]}*\n' f"Purpose: *{row[5]}*\n"
f'Last Action: *{row[7]}*\n' f"Last Action: *{row[7]}*\n"
f'Application Status: *{row[8]}*\n') f"Application Status: *{row[8]}*\n")
embed.add_field(name=header, value=body, inline=False) embed.add_field(name=header, value=body, inline=False)
if len(table) > 3: if len(table) > 3:
desc += f'\nRecords 1 to 3 of {len(table)}. See ae7q.com for more...' desc += f"\nRecords 1 to 3 of {len(table)}. See ae7q.com for more..."
embed.description = desc embed.description = desc
@ -238,7 +238,7 @@ class AE7QCog(commands.Cog):
@_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):
'''Look up the history of an FRN on [ae7q.com](http://ae7q.com/).''' """Look up the history of an FRN on [ae7q.com](http://ae7q.com/)."""
""" """
NOTES: NOTES:
- 2 tables: callsign history and application history - 2 tables: callsign history and application history
@ -260,21 +260,21 @@ class AE7QCog(commands.Cog):
embed.title = f"AE7Q History for FRN {frn}" embed.title = f"AE7Q History for FRN {frn}"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + frn embed.url = base_url + frn
embed.description = f'No records found for FRN `{frn}`' embed.description = f"No records found for FRN `{frn}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
table = tables[0] table = tables[0]
table_headers = table[0].find_all("th") table_headers = table[0].find_all("th")
first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None
# catch if the wrong table was selected # catch if the wrong table was selected
if first_header is None or not first_header.startswith('With Licensee'): if first_header is None or not first_header.startswith("With Licensee"):
embed.title = f"AE7Q History for FRN {frn}" embed.title = f"AE7Q History for FRN {frn}"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + frn embed.url = base_url + frn
embed.description = f'No records found for FRN `{frn}`' embed.description = f"No records found for FRN `{frn}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
@ -287,25 +287,25 @@ class AE7QCog(commands.Cog):
# add the first three rows of the table to the embed # add the first three rows of the table to the embed
for row in table[0:3]: for row in table[0:3]:
header = f'**{row[0]}** ({row[3]})' # **Callsign** (Applicant Type) header = f"**{row[0]}** ({row[3]})" # **Callsign** (Applicant Type)
body = (f'Name: *{row[2]}*\n' body = (f"Name: *{row[2]}*\n"
f'Class: *{row[4]}*\n' f"Class: *{row[4]}*\n"
f'Region: *{row[1]}*\n' f"Region: *{row[1]}*\n"
f'Status: *{row[5]}*\n' f"Status: *{row[5]}*\n"
f'Granted: *{row[6]}*\n' f"Granted: *{row[6]}*\n"
f'Effective: *{row[7]}*\n' f"Effective: *{row[7]}*\n"
f'Cancelled: *{row[8]}*\n' f"Cancelled: *{row[8]}*\n"
f'Expires: *{row[9]}*') f"Expires: *{row[9]}*")
embed.add_field(name=header, value=body, inline=False) embed.add_field(name=header, value=body, inline=False)
if len(table) > 3: if len(table) > 3:
embed.description = f'Records 1 to 3 of {len(table)}. See ae7q.com for more...' embed.description = f"Records 1 to 3 of {len(table)}. See ae7q.com for more..."
await ctx.send(embed=embed) await ctx.send(embed=embed)
@_ae7q_lookup.command(name="licensee", aliases=["l"], category=cmn.cat.lookup) @_ae7q_lookup.command(name="licensee", aliases=["l"], category=cmn.cat.lookup)
async def _ae7q_licensee(self, ctx: commands.Context, licensee_id: str): async def _ae7q_licensee(self, ctx: commands.Context, licensee_id: str):
'''Look up the history of a licensee ID on [ae7q.com](http://ae7q.com/).''' """Look up the history of a licensee ID on [ae7q.com](http://ae7q.com/)."""
with ctx.typing(): with ctx.typing():
licensee_id = licensee_id.upper() licensee_id = licensee_id.upper()
base_url = "http://ae7q.com/query/data/LicenseeIdHistory.php?ID=" base_url = "http://ae7q.com/query/data/LicenseeIdHistory.php?ID="
@ -323,21 +323,21 @@ class AE7QCog(commands.Cog):
embed.title = f"AE7Q History for Licensee {licensee_id}" embed.title = f"AE7Q History for Licensee {licensee_id}"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + licensee_id embed.url = base_url + licensee_id
embed.description = f'No records found for Licensee `{licensee_id}`' embed.description = f"No records found for Licensee `{licensee_id}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
table = tables[0] table = tables[0]
table_headers = table[0].find_all("th") table_headers = table[0].find_all("th")
first_header = ''.join(table_headers[0].strings) if len(table_headers) > 0 else None first_header = "".join(table_headers[0].strings) if len(table_headers) > 0 else None
# catch if the wrong table was selected # catch if the wrong table was selected
if first_header is None or not first_header.startswith('With FCC'): if first_header is None or not first_header.startswith("With FCC"):
embed.title = f"AE7Q History for Licensee {licensee_id}" embed.title = f"AE7Q History for Licensee {licensee_id}"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.url = base_url + licensee_id embed.url = base_url + licensee_id
embed.description = f'No records found for Licensee `{licensee_id}`' embed.description = f"No records found for Licensee `{licensee_id}`"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
@ -350,19 +350,19 @@ class AE7QCog(commands.Cog):
# add the first three rows of the table to the embed # add the first three rows of the table to the embed
for row in table[0:3]: for row in table[0:3]:
header = f'**{row[0]}** ({row[3]})' # **Callsign** (Applicant Type) header = f"**{row[0]}** ({row[3]})" # **Callsign** (Applicant Type)
body = (f'Name: *{row[2]}*\n' body = (f"Name: *{row[2]}*\n"
f'Class: *{row[4]}*\n' f"Class: *{row[4]}*\n"
f'Region: *{row[1]}*\n' f"Region: *{row[1]}*\n"
f'Status: *{row[5]}*\n' f"Status: *{row[5]}*\n"
f'Granted: *{row[6]}*\n' f"Granted: *{row[6]}*\n"
f'Effective: *{row[7]}*\n' f"Effective: *{row[7]}*\n"
f'Cancelled: *{row[8]}*\n' f"Cancelled: *{row[8]}*\n"
f'Expires: *{row[9]}*') f"Expires: *{row[9]}*")
embed.add_field(name=header, value=body, inline=False) embed.add_field(name=header, value=body, inline=False)
if len(table) > 3: if len(table) > 3:
embed.description = f'Records 1 to 3 of {len(table)}. See ae7q.com for more...' embed.description = f"Records 1 to 3 of {len(table)}. See ae7q.com for more..."
await ctx.send(embed=embed) await ctx.send(embed=embed)
@ -372,13 +372,13 @@ async def process_table(table: list):
table_contents = [] table_contents = []
for tr in table: for tr in table:
row = [] row = []
for td in tr.find_all('td'): for td in tr.find_all("td"):
cell_val = td.getText().strip() cell_val = td.getText().strip()
row.append(cell_val if cell_val else '-') row.append(cell_val if cell_val else "-")
# take care of columns that span multiple rows by copying the contents rightward # take care of columns that span multiple rows by copying the contents rightward
if 'colspan' in td.attrs and int(td.attrs['colspan']) > 1: if "colspan" in td.attrs and int(td.attrs["colspan"]) > 1:
for i in range(int(td.attrs['colspan']) - 1): for i in range(int(td.attrs["colspan"]) - 1):
row.append(row[-1]) row.append(row[-1])
# get rid of ditto marks by copying the contents from the previous row # get rid of ditto marks by copying the contents from the previous row

View File

@ -24,7 +24,7 @@ import data.options as opt
class QrmHelpCommand(commands.HelpCommand): class QrmHelpCommand(commands.HelpCommand):
def __init__(self): def __init__(self):
super().__init__(command_attrs={'help': 'Shows help about qrm or a command', 'aliases': ['h']}) super().__init__(command_attrs={"help": "Shows help about qrm or a command", "aliases": ["h"]})
self.verify_checks = True self.verify_checks = True
async def get_bot_mapping(self): async def get_bot_mapping(self):
@ -32,7 +32,7 @@ class QrmHelpCommand(commands.HelpCommand):
mapping = {} mapping = {}
for cmd in await self.filter_commands(bot.commands, sort=True): for cmd in await self.filter_commands(bot.commands, sort=True):
cat = cmd.__original_kwargs__.get('category', None) cat = cmd.__original_kwargs__.get("category", None)
if cat in mapping: if cat in mapping:
mapping[cat].append(cmd) mapping[cat].append(cmd)
else: else:
@ -42,27 +42,27 @@ class QrmHelpCommand(commands.HelpCommand):
async def get_command_signature(self, command): async def get_command_signature(self, command):
parent = command.full_parent_name parent = command.full_parent_name
if command.aliases != []: if command.aliases != []:
aliases = ', '.join(command.aliases) aliases = ", ".join(command.aliases)
fmt = command.name fmt = command.name
if parent: if parent:
fmt = f'{parent} {fmt}' fmt = f"{parent} {fmt}"
alias = fmt alias = fmt
return f'{opt.prefix}{alias} {command.signature}\n *Aliases:* {aliases}' return f"{opt.prefix}{alias} {command.signature}\n *Aliases:* {aliases}"
alias = command.name if not parent else f'{parent} {command.name}' alias = command.name if not parent else f"{parent} {command.name}"
return f'{opt.prefix}{alias} {command.signature}' return f"{opt.prefix}{alias} {command.signature}"
async def send_error_message(self, error): async def send_error_message(self, error):
embed = cmn.embed_factory(self.context) embed = cmn.embed_factory(self.context)
embed.title = 'qrm Help Error' embed.title = "qrm Help Error"
embed.description = error embed.description = error
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await self.context.send(embed=embed) await self.context.send(embed=embed)
async def send_bot_help(self, mapping): async def send_bot_help(self, mapping):
embed = cmn.embed_factory(self.context) embed = cmn.embed_factory(self.context)
embed.title = 'qrm Help' embed.title = "qrm Help"
embed.description = (f'For command-specific help and usage, use `{opt.prefix}help [command name]`' embed.description = (f"For command-specific help and usage, use `{opt.prefix}help [command name]`."
'. Many commands have shorter aliases.') " Many commands have shorter aliases.")
mapping = await mapping mapping = await mapping
for cat, cmds in mapping.items(): for cat, cmds in mapping.items():
@ -70,9 +70,9 @@ class QrmHelpCommand(commands.HelpCommand):
continue continue
names = sorted([cmd.name for cmd in cmds]) names = sorted([cmd.name for cmd in cmds])
if cat is not None: if cat is not None:
embed.add_field(name=cat.title(), value=', '.join(names), inline=False) embed.add_field(name=cat.title(), value=", ".join(names), inline=False)
else: else:
embed.add_field(name='Other', value=', '.join(names), inline=False) embed.add_field(name="Other", value=", ".join(names), inline=False)
await self.context.send(embed=embed) await self.context.send(embed=embed)
async def send_command_help(self, command): async def send_command_help(self, command):
@ -112,27 +112,27 @@ class BaseCog(commands.Cog):
embed.add_field(name="Authors", value=", ".join(info.authors)) embed.add_field(name="Authors", value=", ".join(info.authors))
embed.add_field(name="License", value=info.license) embed.add_field(name="License", value=info.license)
embed.add_field(name="Version", value=f'v{info.release}') embed.add_field(name="Version", value=f"v{info.release}")
embed.add_field(name="Contributing", value=info.contributing, inline=False) embed.add_field(name="Contributing", value=info.contributing, inline=False)
embed.add_field(name="Official Server", value=info.bot_server, inline=False) embed.add_field(name="Official Server", value=info.bot_server, inline=False)
embed.set_thumbnail(url=str(self.bot.user.avatar_url)) embed.set_thumbnail(url=str(self.bot.user.avatar_url))
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="ping", aliases=['beep']) @commands.command(name="ping", aliases=["beep"])
async def _ping(self, ctx: commands.Context): async def _ping(self, ctx: commands.Context):
"""Show the current latency to the discord endpoint.""" """Show the current latency to the discord endpoint."""
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
content = '' content = ""
if ctx.invoked_with == "beep": if ctx.invoked_with == "beep":
embed.title = "**Boop!**" embed.title = "**Boop!**"
else: else:
content = ctx.message.author.mention if random.random() < 0.05 else '' content = ctx.message.author.mention if random.random() < 0.05 else ""
embed.title = "🏓 **Pong!**" embed.title = "🏓 **Pong!**"
embed.description = f'Current ping is {self.bot.latency*1000:.1f} ms' embed.description = f"Current ping is {self.bot.latency*1000:.1f} ms"
await ctx.send(content, embed=embed) await ctx.send(content, embed=embed)
@commands.command(name="changelog", aliases=["clog"]) @commands.command(name="changelog", aliases=["clog"])
async def _changelog(self, ctx: commands.Context, version: str = 'latest'): async def _changelog(self, ctx: commands.Context, version: str = "latest"):
"""Show what has changed in a bot version.""" """Show what has changed in a bot version."""
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = "qrm Changelog" embed.title = "qrm Changelog"
@ -144,25 +144,25 @@ class BaseCog(commands.Cog):
version = version.lower() version = version.lower()
if version == 'latest': if version == "latest":
version = info.release version = info.release
if version == 'unreleased': if version == "unreleased":
version = 'Unreleased' version = "Unreleased"
try: try:
log = changelog[version] log = changelog[version]
except KeyError: except KeyError:
embed.title += ": Version Not Found" embed.title += ": Version Not Found"
embed.description += '\n\n**Valid versions:** latest, ' embed.description += "\n\n**Valid versions:** latest, "
embed.description += ', '.join(vers) embed.description += ", ".join(vers)
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
if 'date' in log: if "date" in log:
embed.description += f'\n\n**v{version}** ({log["date"]})' embed.description += f"\n\n**v{version}** ({log['date']})"
else: else:
embed.description += f'\n\n**v{version}**' embed.description += f"\n\n**v{version}**"
embed = await format_changelog(log, embed) embed = await format_changelog(log, embed)
await ctx.send(embed=embed) await ctx.send(embed=embed)
@ -190,36 +190,36 @@ class BaseCog(commands.Cog):
def parse_changelog(): def parse_changelog():
changelog = OrderedDict() changelog = OrderedDict()
ver = '' ver = ""
heading = '' heading = ""
with open('CHANGELOG.md') as changelog_file: with open("CHANGELOG.md") as changelog_file:
for line in changelog_file.readlines(): for line in changelog_file.readlines():
if line.strip() == '': if line.strip() == "":
continue continue
if re.match(r'##[^#]', line): if re.match(r"##[^#]", line):
ver_match = re.match(r'\[(.+)\](?: - )?(\d{4}-\d{2}-\d{2})?', line.lstrip('#').strip()) ver_match = re.match(r"\[(.+)\](?: - )?(\d{4}-\d{2}-\d{2})?", line.lstrip("#").strip())
if ver_match is not None: if ver_match is not None:
ver = ver_match.group(1) ver = ver_match.group(1)
changelog[ver] = dict() changelog[ver] = dict()
if ver_match.group(2): if ver_match.group(2):
changelog[ver]['date'] = ver_match.group(2) changelog[ver]["date"] = ver_match.group(2)
elif re.match(r'###[^#]', line): elif re.match(r"###[^#]", line):
heading = line.lstrip('#').strip() heading = line.lstrip("#").strip()
changelog[ver][heading] = [] changelog[ver][heading] = []
elif ver != '' and heading != '': elif ver != "" and heading != "":
if line.startswith('-'): if line.startswith("-"):
changelog[ver][heading].append(line.lstrip('-').strip()) changelog[ver][heading].append(line.lstrip("-").strip())
return changelog return changelog
async def format_changelog(log: dict, embed: discord.Embed): async def format_changelog(log: dict, embed: discord.Embed):
for header, lines in log.items(): for header, lines in log.items():
formatted = '' formatted = ""
if header != 'date': if header != "date":
for line in lines: for line in lines:
formatted += f'- {line}\n' formatted += f"- {line}\n"
embed.add_field(name=f'**{header}**', value=formatted, inline=False) embed.add_field(name=f"**{header}**", value=formatted, inline=False)
return embed return embed

View File

@ -17,37 +17,37 @@ import common as cmn
class FunCog(commands.Cog): class FunCog(commands.Cog):
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
self.bot = bot self.bot = bot
with open('resources/words') as words_file: with open("resources/words") as words_file:
self.words = words_file.read().lower().splitlines() self.words = words_file.read().lower().splitlines()
@commands.command(name="xkcd", aliases=['x'], category=cmn.cat.fun) @commands.command(name="xkcd", aliases=["x"], category=cmn.cat.fun)
async def _xkcd(self, ctx: commands.Context, number: str): async def _xkcd(self, ctx: commands.Context, number: str):
'''Look up an xkcd by number.''' """Look up an xkcd by number."""
await ctx.send('http://xkcd.com/' + number) await ctx.send("http://xkcd.com/" + number)
@commands.command(name="tar", category=cmn.cat.fun) @commands.command(name="tar", category=cmn.cat.fun)
async def _tar(self, ctx: commands.Context): async def _tar(self, ctx: commands.Context):
'''Returns an xkcd about tar.''' """Returns an xkcd about tar."""
await ctx.send('http://xkcd.com/1168') await ctx.send("http://xkcd.com/1168")
@commands.command(name="xd", hidden=True, category=cmn.cat.fun) @commands.command(name="xd", hidden=True, category=cmn.cat.fun)
async def _xd(self, ctx: commands.Context): async def _xd(self, ctx: commands.Context):
'''ecks dee''' """ecks dee"""
await ctx.send('ECKS DEE :smirk:') await ctx.send("ECKS DEE :smirk:")
@commands.command(name="funetics", aliases=['fun'], category=cmn.cat.fun) @commands.command(name="funetics", aliases=["fun"], category=cmn.cat.fun)
async def _funetics_lookup(self, ctx: commands.Context, *, msg: str): async def _funetics_lookup(self, ctx: commands.Context, *, msg: str):
'''Get fun phonetics for a word or phrase.''' """Get fun phonetics for a word or phrase."""
with ctx.typing(): with ctx.typing():
result = '' result = ""
for char in msg.lower(): for char in msg.lower():
if char.isalpha(): if char.isalpha():
result += random.choice([word for word in self.words if word[0] == char]) result += random.choice([word for word in self.words if word[0] == char])
else: else:
result += char result += char
result += ' ' result += " "
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Funetics for {msg}' embed.title = f"Funetics for {msg}"
embed.description = result.title() embed.description = result.title()
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
await ctx.send(embed=embed) await ctx.send(embed=embed)

View File

@ -20,27 +20,27 @@ class GridCog(commands.Cog):
@commands.command(name="grid", category=cmn.cat.maps) @commands.command(name="grid", category=cmn.cat.maps)
async def _grid_sq_lookup(self, ctx: commands.Context, lat: str, lon: str): async def _grid_sq_lookup(self, ctx: commands.Context, lat: str, lon: str):
'''Calculates the grid square for latitude and longitude coordinates, """Calculates the grid square for latitude and longitude coordinates,
with negative being latitude South and longitude West.''' with negative being latitude South and longitude West."""
with ctx.typing(): with ctx.typing():
grid = "**" grid = "**"
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:
grid += chr(ord('A') + int(lonf / 20)) grid += chr(ord("A") + int(lonf / 20))
grid += chr(ord('A') + int(latf / 10)) grid += chr(ord("A") + int(latf / 10))
grid += chr(ord('0') + int((lonf % 20)/2)) grid += chr(ord("0") + int((lonf % 20)/2))
grid += chr(ord('0') + int((latf % 10)/1)) 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((lonf - (int(lonf/2)*2)) / (5/60)))
grid += chr(ord('a') + int((latf - (int(latf/1)*1)) / (2.5/60))) grid += chr(ord("a") + int((latf - (int(latf/1)*1)) / (2.5/60)))
grid += "**" grid += "**"
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Maidenhead Grid Locator for {float(lat):.6f}, {float(lon):.6f}' embed.title = f"Maidenhead Grid Locator for {float(lat):.6f}, {float(lon):.6f}"
embed.description = grid embed.description = grid
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
else: else:
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 = ("Coordinates out of range.\n" embed.description = ("Coordinates out of range.\n"
"The valid ranges are:\n" "The valid ranges are:\n"
"- Latitude: `-90` to `+90`\n" "- Latitude: `-90` to `+90`\n"
@ -48,29 +48,29 @@ with negative being latitude South and longitude West.'''
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="ungrid", aliases=['loc'], category=cmn.cat.maps) @commands.command(name="ungrid", aliases=["loc"], category=cmn.cat.maps)
async def _location_lookup(self, ctx: commands.Context, grid: str, grid2: str = None): async def _location_lookup(self, ctx: commands.Context, grid: str, grid2: str = None):
'''Calculates the latitude and longitude for the center of a grid square. """Calculates the latitude and longitude for the center of a grid square.
If two grid squares are given, the distance and azimuth between them is calculated.''' If two grid squares are given, the distance and azimuth between them is calculated."""
with ctx.typing(): with ctx.typing():
if grid2 is None or grid2 == '': if grid2 is None or grid2 == "":
try: try:
grid = grid.upper() grid = grid.upper()
loc = get_coords(grid) loc = get_coords(grid)
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Latitude and Longitude for {grid}' embed.title = f"Latitude and Longitude for {grid}"
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
if len(grid) >= 6: if len(grid) >= 6:
embed.description = f'**{loc[0]:.5f}, {loc[1]:.5f}**' embed.description = f"**{loc[0]:.5f}, {loc[1]:.5f}**"
embed.url = f'https://www.openstreetmap.org/#map=13/{loc[0]:.5f}/{loc[1]:.5f}' embed.url = f"https://www.openstreetmap.org/#map=13/{loc[0]:.5f}/{loc[1]:.5f}"
else: else:
embed.description = f'**{loc[0]:.1f}, {loc[1]:.1f}**' embed.description = f"**{loc[0]:.1f}, {loc[1]:.1f}**"
embed.url = f'https://www.openstreetmap.org/#map=10/{loc[0]:.1f}/{loc[1]:.1f}' embed.url = f"https://www.openstreetmap.org/#map=10/{loc[0]:.1f}/{loc[1]:.1f}"
except Exception as e: except Exception as e:
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Error generating latitude and longitude for grid {grid}.' embed.title = f"Error generating latitude and longitude for grid {grid}."
embed.description = str(e) embed.description = str(e)
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
else: else:
@ -101,12 +101,12 @@ If two grid squares are given, the distance and azimuth between them is calculat
bearing = (math.degrees(math.atan2(y_dist, x_dist)) + 360) % 360 bearing = (math.degrees(math.atan2(y_dist, x_dist)) + 360) % 360
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Great Circle Distance and Bearing from {grid} to {grid2}' embed.title = f"Great Circle Distance and Bearing from {grid} to {grid2}"
embed.description = f'**Distance:** {d:.1f} km ({d_mi:.1f} mi)\n**Bearing:** {bearing:.1f}°' embed.description = f"**Distance:** {d:.1f} km ({d_mi:.1f} mi)\n**Bearing:** {bearing:.1f}°"
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
except Exception as e: except Exception as e:
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Error generating great circle distance and bearing from {grid} and {grid2}.' embed.title = f"Error generating great circle distance and bearing from {grid} and {grid2}."
embed.description = str(e) embed.description = str(e)
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
@ -114,23 +114,23 @@ If two grid squares are given, the distance and azimuth between them is calculat
def get_coords(grid: str): def get_coords(grid: str):
if len(grid) < 3: if len(grid) < 3:
raise ValueError('The grid locator must be at least 4 characters long.') raise ValueError("The grid locator must be at least 4 characters long.")
if not grid[0:2].isalpha() or not grid[2:4].isdigit(): if not grid[0:2].isalpha() or not grid[2:4].isdigit():
if len(grid) <= 4: if len(grid) <= 4:
raise ValueError('The grid locator must be of the form AA##.') raise ValueError("The grid locator must be of the form AA##.")
if len(grid) >= 6 and not grid[5:7].isalpha(): if len(grid) >= 6 and not grid[5:7].isalpha():
raise ValueError('The grid locator must be of the form AA##AA.') raise ValueError("The grid locator must be of the form AA##AA.")
lon = ((ord(grid[0]) - ord('A')) * 20) - 180 lon = ((ord(grid[0]) - ord("A")) * 20) - 180
lat = ((ord(grid[1]) - ord('A')) * 10) - 90 lat = ((ord(grid[1]) - ord("A")) * 10) - 90
lon += ((ord(grid[2]) - ord('0')) * 2) lon += ((ord(grid[2]) - ord("0")) * 2)
lat += ((ord(grid[3]) - ord('0')) * 1) lat += ((ord(grid[3]) - ord("0")) * 1)
if len(grid) >= 6: if len(grid) >= 6:
# have subsquares # have subsquares
lon += ((ord(grid[4])) - ord('A')) * (5/60) lon += ((ord(grid[4])) - ord("A")) * (5/60)
lat += ((ord(grid[5])) - ord('A')) * (2.5/60) lat += ((ord(grid[5])) - ord("A")) * (2.5/60)
# move to center of subsquare # move to center of subsquare
lon += (2.5/60) lon += (2.5/60)
lat += (1.25/60) lat += (1.25/60)

View File

@ -21,9 +21,9 @@ class HamCog(commands.Cog):
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
self.bot = bot self.bot = bot
@commands.command(name="qcode", aliases=['q'], category=cmn.cat.ref) @commands.command(name="qcode", aliases=["q"], category=cmn.cat.ref)
async def _qcode_lookup(self, ctx: commands.Context, qcode: str): async def _qcode_lookup(self, ctx: commands.Context, qcode: str):
'''Look up a Q Code.''' """Look up a Q Code."""
with ctx.typing(): with ctx.typing():
qcode = qcode.upper() qcode = qcode.upper()
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
@ -32,49 +32,49 @@ class HamCog(commands.Cog):
embed.description = qcodes.qcodes[qcode] embed.description = qcodes.qcodes[qcode]
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
else: else:
embed.title = f'Q Code {qcode} not found' embed.title = f"Q Code {qcode} not found"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="phonetics", aliases=['ph', 'phoneticize', 'phoneticise', 'phone'], category=cmn.cat.ref) @commands.command(name="phonetics", aliases=["ph", "phoneticize", "phoneticise", "phone"], category=cmn.cat.ref)
async def _phonetics_lookup(self, ctx: commands.Context, *, msg: str): async def _phonetics_lookup(self, ctx: commands.Context, *, msg: str):
'''Get phonetics for a word or phrase.''' """Get phonetics for a word or phrase."""
with ctx.typing(): with ctx.typing():
result = '' result = ""
for char in msg.lower(): for char in msg.lower():
if char.isalpha(): if char.isalpha():
result += phonetics.phonetics[char] result += phonetics.phonetics[char]
else: else:
result += char result += char
result += ' ' result += " "
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Phonetics for {msg}' embed.title = f"Phonetics for {msg}"
embed.description = result.title() embed.description = result.title()
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="utc", aliases=['z'], category=cmn.cat.ref) @commands.command(name="utc", aliases=["z"], category=cmn.cat.ref)
async def _utc_lookup(self, ctx: commands.Context): async def _utc_lookup(self, ctx: commands.Context):
'''Gets the current time in UTC.''' """Gets the current time in UTC."""
with ctx.typing(): with ctx.typing():
now = datetime.utcnow() now = datetime.utcnow()
result = '**' + now.strftime('%Y-%m-%d %H:%M') + 'Z**' result = "**" + now.strftime("%Y-%m-%d %H:%M") + "Z**"
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = 'The current time is:' embed.title = "The current time is:"
embed.description = result embed.description = result
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="prefixes", aliases=["vanity", "pfx", "vanities", "prefix"], category=cmn.cat.ref) @commands.command(name="prefixes", aliases=["vanity", "pfx", "vanities", "prefix"], category=cmn.cat.ref)
async def _vanity_prefixes(self, ctx: commands.Context, country: str = None): async def _vanity_prefixes(self, ctx: commands.Context, country: str = None):
'''Lists valid prefixes for countries.''' """Lists valid prefixes for countries."""
if country is None: if country is None:
await ctx.send_help(ctx.command) await ctx.send_help(ctx.command)
return return
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
if country.lower() not in callsign_info.options: if country.lower() not in callsign_info.options:
embed.title = f'{country} not found!', embed.title = f"{country} not found!",
embed.description = f'Valid countries: {", ".join(callsign_info.options.keys())}', embed.description = f"Valid countries: {', '.join(callsign_info.options.keys())}",
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
else: else:
embed.title = callsign_info.options[country.lower()][0] embed.title = callsign_info.options[country.lower()][0]

View File

@ -18,8 +18,8 @@ import common as cmn
class ImageCog(commands.Cog): class ImageCog(commands.Cog):
gl_url = ('http://www.fourmilab.ch/cgi-bin/uncgi/Earth?img=NOAAtopo.evif' gl_url = ("http://www.fourmilab.ch/cgi-bin/uncgi/Earth?img=NOAAtopo.evif"
'&imgsize=320&dynimg=y&opt=-p&lat=&lon=&alt=&tle=&date=0&utc=&jd=') "&imgsize=320&dynimg=y&opt=-p&lat=&lon=&alt=&tle=&date=0&utc=&jd=")
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
self.bot = bot self.bot = bot
@ -27,17 +27,17 @@ class ImageCog(commands.Cog):
self.maps = cmn.ImagesGroup(cmn.paths.maps / "meta.json") self.maps = cmn.ImagesGroup(cmn.paths.maps / "meta.json")
self.session = aiohttp.ClientSession(connector=bot.qrm.connector) self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
@commands.command(name="bandplan", aliases=['plan', 'bands'], category=cmn.cat.ref) @commands.command(name="bandplan", aliases=["plan", "bands"], category=cmn.cat.ref)
async def _bandplan(self, ctx: commands.Context, region: str = ''): async def _bandplan(self, ctx: commands.Context, region: str = ""):
'''Posts an image of Frequency Allocations.''' """Posts an image of Frequency Allocations."""
async with ctx.typing(): async with ctx.typing():
arg = region.lower() arg = region.lower()
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
if arg not in self.bandcharts: if arg not in self.bandcharts:
desc = 'Possible arguments are:\n' desc = "Possible arguments are:\n"
for key, img in self.bandcharts.items(): for key, img in self.bandcharts.items():
desc += f'`{key}`: {img.name}{(" " + img.emoji if img.emoji else "")}\n' desc += f"`{key}`: {img.name}{(' ' + img.emoji if img.emoji else '')}\n"
embed.title = f'Bandplan Not Found!' embed.title = f"Bandplan Not Found!"
embed.description = desc embed.description = desc
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
@ -51,20 +51,20 @@ class ImageCog(commands.Cog):
embed.add_field(name="Source", value=metadata.source) embed.add_field(name="Source", value=metadata.source)
embed.title = metadata.long_name + (" " + metadata.emoji if metadata.emoji else "") embed.title = metadata.long_name + (" " + metadata.emoji if metadata.emoji else "")
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
embed.set_image(url='attachment://' + metadata.filename) embed.set_image(url="attachment://" + metadata.filename)
await ctx.send(embed=embed, file=img) await ctx.send(embed=embed, file=img)
@commands.command(name="map", category=cmn.cat.maps) @commands.command(name="map", category=cmn.cat.maps)
async def _map(self, ctx: commands.Context, map_id: str = ''): async def _map(self, ctx: commands.Context, map_id: str = ""):
'''Posts an image of a ham-relevant map.''' """Posts an image of a ham-relevant map."""
async with ctx.typing(): async with ctx.typing():
arg = map_id.lower() arg = map_id.lower()
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
if arg not in self.maps: if arg not in self.maps:
desc = 'Possible arguments are:\n' desc = "Possible arguments are:\n"
for key, img in self.maps.items(): for key, img in self.maps.items():
desc += f'`{key}`: {img.name}{(" " + img.emoji if img.emoji else "")}\n' desc += f"`{key}`: {img.name}{(' ' + img.emoji if img.emoji else '')}\n"
embed.title = 'Map Not Found!' embed.title = "Map Not Found!"
embed.description = desc embed.description = desc
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)
@ -78,22 +78,22 @@ class ImageCog(commands.Cog):
embed.add_field(name="Source", value=metadata.source) embed.add_field(name="Source", value=metadata.source)
embed.title = metadata.long_name + (" " + metadata.emoji if metadata.emoji else "") embed.title = metadata.long_name + (" " + metadata.emoji if metadata.emoji else "")
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
embed.set_image(url='attachment://' + metadata.filename) embed.set_image(url="attachment://" + metadata.filename)
await ctx.send(embed=embed, file=img) await ctx.send(embed=embed, file=img)
@commands.command(name="grayline", aliases=['greyline', 'grey', 'gray', 'gl'], category=cmn.cat.maps) @commands.command(name="grayline", aliases=["greyline", "grey", "gray", "gl"], category=cmn.cat.maps)
async def _grayline(self, ctx: commands.Context): async def _grayline(self, ctx: commands.Context):
'''Posts a map of the current greyline, where HF propagation is the best.''' """Posts a map of the current greyline, where HF propagation is the best."""
async with ctx.typing(): async with ctx.typing():
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = 'Current Greyline Conditions' embed.title = "Current Greyline Conditions"
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:
raise cmn.BotHTTPError(resp) raise cmn.BotHTTPError(resp)
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"))
def setup(bot: commands.Bot): def setup(bot: commands.Bot):

View File

@ -19,48 +19,48 @@ class LookupCog(commands.Cog):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
try: try:
self.cty = BigCty('./data/cty.json') self.cty = BigCty("./data/cty.json")
except OSError: except OSError:
self.cty = BigCty() self.cty = BigCty()
# TODO: See #107 # TODO: See #107
# @commands.command(name="sat", category=cmn.cat.lookup) # @commands.command(name="sat", category=cmn.cat.lookup)
# async def _sat_lookup(self, ctx: commands.Context, sat_name: str, grid1: str, grid2: str = None): # async def _sat_lookup(self, ctx: commands.Context, sat_name: str, grid1: str, grid2: str = None):
# '''Links to info about satellite passes on satmatch.com.''' # """Links to info about satellite passes on satmatch.com."""
# now = datetime.utcnow().strftime('%Y-%m-%d%%20%H:%M') # now = datetime.utcnow().strftime("%Y-%m-%d%%20%H:%M")
# if grid2 is None or grid2 == '': # if grid2 is None or grid2 == "":
# await ctx.send(f'http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}' # await ctx.send(f"http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}"
# f'?search_start_time={now}&duration_hrs=24') # f"?search_start_time={now}&duration_hrs=24")
# else: # else:
# await ctx.send(f'http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}' # await ctx.send(f"http://www.satmatch.com/satellite/{sat_name}/obs1/{grid1}"
# f'/obs2/{grid2}?search_start_time={now}&duration_hrs=24') # f"/obs2/{grid2}?search_start_time={now}&duration_hrs=24")
@commands.command(name="dxcc", aliases=['dx'], category=cmn.cat.lookup) @commands.command(name="dxcc", aliases=["dx"], category=cmn.cat.lookup)
async def _dxcc_lookup(self, ctx: commands.Context, query: str): async def _dxcc_lookup(self, ctx: commands.Context, query: str):
'''Gets info about a DXCC prefix.''' """Gets info about a DXCC prefix."""
with ctx.typing(): with ctx.typing():
query = query.upper() query = query.upper()
full_query = query full_query = query
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'DXCC Info for ' embed.title = f"DXCC Info for "
embed.description = f'*Last Updated: {self.cty.formatted_version}*' embed.description = f"*Last Updated: {self.cty.formatted_version}*"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
while query: while query:
if query in self.cty.keys(): if query in self.cty.keys():
data = self.cty[query] data = self.cty[query]
embed.add_field(name="Entity", value=data['entity']) embed.add_field(name="Entity", value=data["entity"])
embed.add_field(name="CQ Zone", value=data['cq']) embed.add_field(name="CQ Zone", value=data["cq"])
embed.add_field(name="ITU Zone", value=data['itu']) embed.add_field(name="ITU Zone", value=data["itu"])
embed.add_field(name="Continent", value=data['continent']) embed.add_field(name="Continent", value=data["continent"])
embed.add_field(name="Time Zone", embed.add_field(name="Time Zone",
value=f'+{data["tz"]}' if data['tz'] > 0 else str(data['tz'])) value=f"+{data['tz']}" if data["tz"] > 0 else str(data["tz"]))
embed.title += query embed.title += query
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
break break
else: else:
query = query[:-1] query = query[:-1]
else: else:
embed.title += full_query + ' not found' embed.title += full_query + " not found"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
await ctx.send(embed=embed) await ctx.send(embed=embed)

View File

@ -17,63 +17,63 @@ class MorseCog(commands.Cog):
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
self.bot = bot self.bot = bot
@commands.command(name="morse", aliases=['cw'], category=cmn.cat.ref) @commands.command(name="morse", aliases=["cw"], category=cmn.cat.ref)
async def _morse(self, ctx: commands.Context, *, msg: str): async def _morse(self, ctx: commands.Context, *, msg: str):
"""Converts ASCII to international morse code.""" """Converts ASCII to international morse code."""
with ctx.typing(): with ctx.typing():
result = '' result = ""
for char in msg.upper(): for char in msg.upper():
try: try:
result += morse.morse[char] result += morse.morse[char]
except KeyError: except KeyError:
result += '<?>' result += "<?>"
result += ' ' result += " "
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Morse Code for {msg}' embed.title = f"Morse Code for {msg}"
embed.description = '**' + result + '**' embed.description = "**" + result + "**"
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="unmorse", aliases=['demorse', 'uncw', 'decw'], category=cmn.cat.ref) @commands.command(name="unmorse", aliases=["demorse", "uncw", "decw"], category=cmn.cat.ref)
async def _unmorse(self, ctx: commands.Context, *, msg: str): async def _unmorse(self, ctx: commands.Context, *, msg: str):
'''Converts international morse code to ASCII.''' """Converts international morse code to ASCII."""
with ctx.typing(): with ctx.typing():
result = '' result = ""
msg0 = msg msg0 = msg
msg = msg.split('/') msg = msg.split("/")
msg = [m.split() for m in msg] msg = [m.split() for m in msg]
for word in msg: for word in msg:
for char in word: for char in word:
try: try:
result += morse.ascii[char] result += morse.ascii[char]
except KeyError: except KeyError:
result += '<?>' result += "<?>"
result += ' ' result += " "
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'ASCII for {msg0}' embed.title = f"ASCII for {msg0}"
embed.description = result embed.description = result
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name="cwweight", aliases=["weight", 'cww'], category=cmn.cat.ref) @commands.command(name="cwweight", aliases=["weight", "cww"], category=cmn.cat.ref)
async def _weight(self, ctx: commands.Context, *, msg: str): async def _weight(self, ctx: commands.Context, *, msg: str):
'''Calculates the CW Weight of a callsign or message.''' """Calculates the CW Weight of a callsign or message."""
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
with ctx.typing(): with ctx.typing():
msg = msg.upper() msg = msg.upper()
weight = 0 weight = 0
for char in msg: for char in msg:
try: try:
cw_char = morse.morse[char].replace('-', '==') cw_char = morse.morse[char].replace("-", "==")
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 message' 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
embed.title = f'CW Weight of {msg}' embed.title = f"CW Weight of {msg}"
embed.description = f'The CW weight is **{weight}**' embed.description = f"The CW weight is **{weight}**"
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
await ctx.send(embed=embed) await ctx.send(embed=embed)

View File

@ -26,11 +26,11 @@ class QRZCog(commands.Cog):
@commands.command(name="call", aliases=["qrz"], category=cmn.cat.lookup) @commands.command(name="call", aliases=["qrz"], category=cmn.cat.lookup)
async def _qrz_lookup(self, ctx: commands.Context, callsign: str, *flags): async def _qrz_lookup(self, ctx: commands.Context, callsign: str, *flags):
'''Look up a callsign on [QRZ.com](https://www.qrz.com/). Add `--link` to only link the QRZ page.''' """Look up a callsign on [QRZ.com](https://www.qrz.com/). Add `--link` to only link the QRZ page."""
flags = [f.lower() for f in flags] flags = [f.lower() for f in flags]
if keys.qrz_user == '' or keys.qrz_pass == '' or '--link' in flags: if keys.qrz_user == "" or keys.qrz_pass == "" or "--link" in flags:
await ctx.send(f'http://qrz.com/db/{callsign}') await ctx.send(f"http://qrz.com/db/{callsign}")
return return
try: try:
@ -38,38 +38,38 @@ class QRZCog(commands.Cog):
except ConnectionError: except ConnectionError:
await self.get_session() await self.get_session()
url = f'http://xmldata.qrz.com/xml/current/?s={self.key};callsign={callsign}' url = f"http://xmldata.qrz.com/xml/current/?s={self.key};callsign={callsign}"
async with self.session.get(url) as resp: async with self.session.get(url) as resp:
if resp.status != 200: if resp.status != 200:
raise ConnectionError(f'Unable to connect to QRZ (HTTP Error {resp.status})') raise ConnectionError(f"Unable to connect to QRZ (HTTP Error {resp.status})")
with BytesIO(await resp.read()) as resp_file: with BytesIO(await resp.read()) as resp_file:
resp_xml = etree.parse(resp_file).getroot() resp_xml = etree.parse(resp_file).getroot()
resp_xml_session = resp_xml.xpath('/x:QRZDatabase/x:Session', namespaces={'x': 'http://xmldata.qrz.com'}) resp_xml_session = resp_xml.xpath("/x:QRZDatabase/x:Session", namespaces={"x": "http://xmldata.qrz.com"})
resp_session = {el.tag.split('}')[1]: el.text for el in resp_xml_session[0].getiterator()} resp_session = {el.tag.split("}")[1]: el.text for el in resp_xml_session[0].getiterator()}
if 'Error' in resp_session: if "Error" in resp_session:
if 'Session Timeout' in resp_session['Error']: if "Session Timeout" in resp_session["Error"]:
await self.get_session() await self.get_session()
await self._qrz_lookup(ctx, callsign) await self._qrz_lookup(ctx, callsign)
return return
if 'Not found' in resp_session['Error']: if "Not found" in resp_session["Error"]:
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f"QRZ Data for {callsign.upper()}" embed.title = f"QRZ Data for {callsign.upper()}"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
embed.description = 'No data found!' embed.description = "No data found!"
await ctx.send(embed=embed) await ctx.send(embed=embed)
return return
raise ValueError(resp_session['Error']) raise ValueError(resp_session["Error"])
resp_xml_data = resp_xml.xpath('/x:QRZDatabase/x:Callsign', namespaces={'x': 'http://xmldata.qrz.com'}) resp_xml_data = resp_xml.xpath("/x:QRZDatabase/x:Callsign", namespaces={"x": "http://xmldata.qrz.com"})
resp_data = {el.tag.split('}')[1]: el.text for el in resp_xml_data[0].getiterator()} resp_data = {el.tag.split("}")[1]: el.text for el in resp_xml_data[0].getiterator()}
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f"QRZ Data for {resp_data['call']}" embed.title = f"QRZ Data for {resp_data['call']}"
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
embed.url = f'http://www.qrz.com/db/{resp_data["call"]}' embed.url = f"http://www.qrz.com/db/{resp_data['call']}"
if 'image' in resp_data: if "image" in resp_data:
embed.set_thumbnail(url=resp_data['image']) embed.set_thumbnail(url=resp_data["image"])
data = qrz_process_info(resp_data) data = qrz_process_info(resp_data)
@ -81,14 +81,14 @@ class QRZCog(commands.Cog):
async def get_session(self): async def get_session(self):
"""Session creation and caching.""" """Session creation and caching."""
self.key = await qrz_login(keys.qrz_user, keys.qrz_pass, self.session) self.key = await qrz_login(keys.qrz_user, keys.qrz_pass, self.session)
with open('data/qrz_session', 'w') as qrz_file: with open("data/qrz_session", "w") as qrz_file:
qrz_file.write(self.key) qrz_file.write(self.key)
@tasks.loop(count=1) @tasks.loop(count=1)
async def _qrz_session_init(self): async def _qrz_session_init(self):
"""Helper task to allow obtaining a session at cog instantiation.""" """Helper task to allow obtaining a session at cog instantiation."""
try: try:
with open('data/qrz_session') as qrz_file: with open("data/qrz_session") as qrz_file:
self.key = qrz_file.readline().strip() self.key = qrz_file.readline().strip()
await qrz_test_session(self.key, self.session) await qrz_test_session(self.key, self.session)
except (FileNotFoundError, ConnectionError): except (FileNotFoundError, ConnectionError):
@ -96,86 +96,86 @@ class QRZCog(commands.Cog):
async def qrz_login(user: str, passwd: str, session: aiohttp.ClientSession): async def qrz_login(user: str, passwd: str, session: aiohttp.ClientSession):
url = f'http://xmldata.qrz.com/xml/current/?username={user};password={passwd};agent=discord-qrm2' url = f"http://xmldata.qrz.com/xml/current/?username={user};password={passwd};agent=discord-qrm2"
async with session.get(url) as resp: async with session.get(url) as resp:
if resp.status != 200: if resp.status != 200:
raise ConnectionError(f'Unable to connect to QRZ (HTTP Error {resp.status})') raise ConnectionError(f"Unable to connect to QRZ (HTTP Error {resp.status})")
with BytesIO(await resp.read()) as resp_file: with BytesIO(await resp.read()) as resp_file:
resp_xml = etree.parse(resp_file).getroot() resp_xml = etree.parse(resp_file).getroot()
resp_xml_session = resp_xml.xpath('/x:QRZDatabase/x:Session', namespaces={'x': 'http://xmldata.qrz.com'}) resp_xml_session = resp_xml.xpath("/x:QRZDatabase/x:Session", namespaces={"x": "http://xmldata.qrz.com"})
resp_session = {el.tag.split('}')[1]: el.text for el in resp_xml_session[0].getiterator()} resp_session = {el.tag.split("}")[1]: el.text for el in resp_xml_session[0].getiterator()}
if 'Error' in resp_session: if "Error" in resp_session:
raise ConnectionError(resp_session['Error']) raise ConnectionError(resp_session["Error"])
if resp_session['SubExp'] == 'non-subscriber': if resp_session["SubExp"] == "non-subscriber":
raise ConnectionError('Invalid QRZ Subscription') raise ConnectionError("Invalid QRZ Subscription")
return resp_session['Key'] return resp_session["Key"]
async def qrz_test_session(key: str, session: aiohttp.ClientSession): async def qrz_test_session(key: str, session: aiohttp.ClientSession):
url = f'http://xmldata.qrz.com/xml/current/?s={key}' url = f"http://xmldata.qrz.com/xml/current/?s={key}"
async with session.get(url) as resp: async with session.get(url) as resp:
if resp.status != 200: if resp.status != 200:
raise ConnectionError(f'Unable to connect to QRZ (HTTP Error {resp.status})') raise ConnectionError(f"Unable to connect to QRZ (HTTP Error {resp.status})")
with BytesIO(await resp.read()) as resp_file: with BytesIO(await resp.read()) as resp_file:
resp_xml = etree.parse(resp_file).getroot() resp_xml = etree.parse(resp_file).getroot()
resp_xml_session = resp_xml.xpath('/x:QRZDatabase/x:Session', namespaces={'x': 'http://xmldata.qrz.com'}) resp_xml_session = resp_xml.xpath("/x:QRZDatabase/x:Session", namespaces={"x": "http://xmldata.qrz.com"})
resp_session = {el.tag.split('}')[1]: el.text for el in resp_xml_session[0].getiterator()} resp_session = {el.tag.split("}")[1]: el.text for el in resp_xml_session[0].getiterator()}
if 'Error' in resp_session: if "Error" in resp_session:
raise ConnectionError(resp_session['Error']) raise ConnectionError(resp_session["Error"])
def qrz_process_info(data: dict): def qrz_process_info(data: dict):
if 'name' in data: if "name" in data:
if 'fname' in data: if "fname" in data:
name = data['fname'] + ' ' + data['name'] name = data["fname"] + " " + data["name"]
else: else:
name = data['name'] name = data["name"]
else: else:
name = None name = None
if 'state' in data: if "state" in data:
state = f', {data["state"]}' state = f", {data['state']}"
else: else:
state = '' state = ""
address = data.get('addr1', '') + '\n' + data.get('addr2', '') + state + ' ' + data.get('zip', '') address = data.get("addr1", "") + "\n" + data.get("addr2", "") + state + " " + data.get("zip", "")
address = address.strip() address = address.strip()
if address == '': if address == "":
address = None address = None
if 'eqsl' in data: if "eqsl" in data:
eqsl = 'Yes' if data['eqsl'] == 1 else 'No' eqsl = "Yes" if data["eqsl"] == 1 else "No"
else: else:
eqsl = 'Unknown' eqsl = "Unknown"
if 'mqsl' in data: if "mqsl" in data:
mqsl = 'Yes' if data['mqsl'] == 1 else 'No' mqsl = "Yes" if data["mqsl"] == 1 else "No"
else: else:
mqsl = 'Unknown' mqsl = "Unknown"
if 'lotw' in data: if "lotw" in data:
lotw = 'Yes' if data['lotw'] == 1 else 'No' lotw = "Yes" if data["lotw"] == 1 else "No"
else: else:
lotw = 'Unknown' lotw = "Unknown"
return OrderedDict([('Name', name), return OrderedDict([("Name", name),
('Country', data.get('country', None)), ("Country", data.get("country", None)),
('Address', address), ("Address", address),
('Grid Square', data.get('grid', None)), ("Grid Square", data.get("grid", None)),
('County', data.get('county', None)), ("County", data.get("county", None)),
('CQ Zone', data.get('cqzone', None)), ("CQ Zone", data.get("cqzone", None)),
('ITU Zone', data.get('ituzone', None)), ("ITU Zone", data.get("ituzone", None)),
('IOTA Designator', data.get('iota', None)), ("IOTA Designator", data.get("iota", None)),
('Expires', data.get('expdate', None)), ("Expires", data.get("expdate", None)),
('Aliases', data.get('aliases', None)), ("Aliases", data.get("aliases", None)),
('Previous Callsign', data.get('p_call', None)), ("Previous Callsign", data.get("p_call", None)),
('License Class', data.get('class', None)), ("License Class", data.get("class", None)),
('Trustee', data.get('trustee', None)), ("Trustee", data.get("trustee", None)),
('eQSL?', eqsl), ("eQSL?", eqsl),
('Paper QSL?', mqsl), ("Paper QSL?", mqsl),
('LotW?', lotw), ("LotW?", lotw),
('QSL Info', data.get('qslmgr', None)), ("QSL Info", data.get("qslmgr", None)),
('CQ Zone', data.get('cqzone', None)), ("CQ Zone", data.get("cqzone", None)),
('ITU Zone', data.get('ituzone', None)), ("ITU Zone", data.get("ituzone", None)),
('IOTA Designator', data.get('iota', None)), ("IOTA Designator", data.get("iota", None)),
('Born', data.get('born', None))]) ("Born", data.get("born", None))])
def setup(bot): def setup(bot):

View File

@ -21,17 +21,17 @@ from resources import study
class StudyCog(commands.Cog): class StudyCog(commands.Cog):
choices = {cmn.emojis.a: 'A', cmn.emojis.b: 'B', cmn.emojis.c: 'C', cmn.emojis.d: 'D'} choices = {cmn.emojis.a: "A", cmn.emojis.b: "B", cmn.emojis.c: "C", cmn.emojis.d: "D"}
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
self.bot = bot self.bot = bot
self.lastq = dict() self.lastq = dict()
self.source = 'Data courtesy of [HamStudy.org](https://hamstudy.org/)' self.source = "Data courtesy of [HamStudy.org](https://hamstudy.org/)"
self.session = aiohttp.ClientSession(connector=bot.qrm.connector) self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
@commands.command(name="hamstudy", aliases=['rq', 'randomquestion', 'randomq'], category=cmn.cat.study) @commands.command(name="hamstudy", aliases=["rq", "randomquestion", "randomq"], category=cmn.cat.study)
async def _random_question(self, ctx: commands.Context, country: str = '', level: str = ''): async def _random_question(self, ctx: commands.Context, country: str = "", level: str = ""):
'''Gets a random question from [HamStudy's](https://hamstudy.org) question pools.''' """Gets a random question from [HamStudy's](https://hamstudy.org) question pools."""
with ctx.typing(): with ctx.typing():
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
@ -52,7 +52,7 @@ class StudyCog(commands.Cog):
embed.description = "Possible arguments are:" embed.description = "Possible arguments are:"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
for cty in study.pool_names: for cty in study.pool_names:
levels = '`, `'.join(study.pool_names[cty].keys()) levels = "`, `".join(study.pool_names[cty].keys())
embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**", embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**",
value=f"Levels: `{levels}`", inline=False) value=f"Levels: `{levels}`", inline=False)
embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`") embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`")
@ -70,7 +70,7 @@ class StudyCog(commands.Cog):
embed.description = "Possible arguments are:" embed.description = "Possible arguments are:"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
for cty in study.pool_names: for cty in study.pool_names:
levels = '`, `'.join(study.pool_names[cty].keys()) levels = "`, `".join(study.pool_names[cty].keys())
embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**", embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**",
value=f"Levels: `{levels}`", inline=False) value=f"Levels: `{levels}`", inline=False)
embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`") embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`")
@ -99,7 +99,7 @@ class StudyCog(commands.Cog):
embed.description = "Possible arguments are:" embed.description = "Possible arguments are:"
embed.colour = cmn.colours.bad embed.colour = cmn.colours.bad
for cty in study.pool_names: for cty in study.pool_names:
levels = '`, `'.join(study.pool_names[cty].keys()) levels = "`, `".join(study.pool_names[cty].keys())
embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**", embed.add_field(name=f"**Country: `{cty}` {study.pool_emojis[cty]}**",
value=f"Levels: `{levels}`", inline=False) value=f"Levels: `{levels}`", inline=False)
embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`") embed.add_field(name="**Random**", value="To select a random pool or country, use `random` or `r`")
@ -108,31 +108,31 @@ class StudyCog(commands.Cog):
pool_meta = pools[pool] pool_meta = pools[pool]
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:
raise cmn.BotHTTPError(resp) raise cmn.BotHTTPError(resp)
pool = json.loads(await resp.read())['pool'] pool = json.loads(await resp.read())["pool"]
# Select a question # Select a question
pool_section = random.choice(pool)['sections'] pool_section = random.choice(pool)["sections"]
pool_questions = random.choice(pool_section)['questions'] pool_questions = random.choice(pool_section)["questions"]
question = random.choice(pool_questions) question = random.choice(pool_questions)
embed.title = f"{study.pool_emojis[country]} {pool_meta['class']} {question['id']}" embed.title = f"{study.pool_emojis[country]} {pool_meta['class']} {question['id']}"
embed.description = self.source embed.description = self.source
embed.add_field(name='Question:', value=question['text'], inline=False) embed.add_field(name="Question:", value=question["text"], inline=False)
embed.add_field(name='Answers:', embed.add_field(name="Answers:",
value=(f"**{cmn.emojis.a}** {question['answers']['A']}" value=(f"**{cmn.emojis.a}** {question['answers']['A']}"
f"\n**{cmn.emojis.b}** {question['answers']['B']}" f"\n**{cmn.emojis.b}** {question['answers']['B']}"
f"\n**{cmn.emojis.c}** {question['answers']['C']}" f"\n**{cmn.emojis.c}** {question['answers']['C']}"
f"\n**{cmn.emojis.d}** {question['answers']['D']}"), f"\n**{cmn.emojis.d}** {question['answers']['D']}"),
inline=False) inline=False)
embed.add_field(name='To Answer:', embed.add_field(name="To Answer:",
value=('Answer with reactions below. If not answered within 10 minutes,' value=("Answer with reactions below. If not answered within 10 minutes,"
' the answer will be revealed.'), " the answer will be revealed."),
inline=False) inline=False)
if 'image' in question: if "image" in question:
image_url = f'https://hamstudy.org/_1330011/images/{pool.split("_",1)[1]}/{question["image"]}' image_url = f"https://hamstudy.org/_1330011/images/{pool.split('_',1)[1]}/{question['image']}"
embed.set_image(url=image_url) embed.set_image(url=image_url)
q_msg = await ctx.send(embed=embed) q_msg = await ctx.send(embed=embed)
@ -148,13 +148,13 @@ class StudyCog(commands.Cog):
and str(reaction.emoji) in self.choices.keys()) and str(reaction.emoji) in self.choices.keys())
try: try:
reaction, user = await self.bot.wait_for('reaction_add', timeout=600.0, check=check) reaction, user = await self.bot.wait_for("reaction_add", timeout=600.0, check=check)
except asyncio.TimeoutError: except asyncio.TimeoutError:
embed.remove_field(2) embed.remove_field(2)
embed.add_field(name="Answer:", value=f"Timed out! The correct answer was **{question['answer']}**.") embed.add_field(name="Answer:", value=f"Timed out! The correct answer was **{question['answer']}**.")
await q_msg.edit(embed=embed) await q_msg.edit(embed=embed)
else: else:
if self.choices[str(reaction.emoji)] == question['answer']: if self.choices[str(reaction.emoji)] == question["answer"]:
embed.remove_field(2) embed.remove_field(2)
embed.add_field(name="Answer:", value=f"Correct! The answer was **{question['answer']}**.") embed.add_field(name="Answer:", value=f"Correct! The answer was **{question['answer']}**.")
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
@ -166,7 +166,7 @@ class StudyCog(commands.Cog):
await q_msg.edit(embed=embed) await q_msg.edit(embed=embed)
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 cmn.BotHTTPError(resp) raise cmn.BotHTTPError(resp)
else: else:

View File

@ -25,23 +25,23 @@ class WeatherCog(commands.Cog):
self.bot = bot self.bot = bot
self.session = aiohttp.ClientSession(connector=bot.qrm.connector) self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
@commands.command(name="bandconditions", aliases=['cond', 'condx', 'conditions'], category=cmn.cat.weather) @commands.command(name="bandconditions", aliases=["cond", "condx", "conditions"], category=cmn.cat.weather)
async def _band_conditions(self, ctx: commands.Context): async def _band_conditions(self, ctx: commands.Context):
'''Posts an image of HF Band Conditions.''' """Posts an image of HF Band Conditions."""
async with ctx.typing(): async with ctx.typing():
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = 'Current Solar Conditions' embed.title = "Current Solar Conditions"
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:
raise cmn.BotHTTPError(resp) raise cmn.BotHTTPError(resp)
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"))
@commands.group(name="weather", aliases=['wttr'], category=cmn.cat.weather) @commands.group(name="weather", aliases=["wttr"], category=cmn.cat.weather)
async def _weather_conditions(self, ctx: commands.Context): async def _weather_conditions(self, ctx: commands.Context):
'''Posts an image of Local Weather Conditions from [wttr.in](http://wttr.in/). """Posts an image of Local Weather Conditions from [wttr.in](http://wttr.in/).
*Supported location types:* *Supported location types:*
city name: `paris` city name: `paris`
@ -51,71 +51,71 @@ class WeatherCog(commands.Cog):
domain name `@stackoverflow.com` domain name `@stackoverflow.com`
area codes: `12345` area codes: `12345`
GPS coordinates: `-78.46,106.79` GPS coordinates: `-78.46,106.79`
''' """
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send_help(ctx.command) await ctx.send_help(ctx.command)
@_weather_conditions.command(name='forecast', aliases=['fc', 'future'], category=cmn.cat.weather) @_weather_conditions.command(name="forecast", aliases=["fc", "future"], category=cmn.cat.weather)
async def _weather_conditions_forecast(self, ctx: commands.Context, *, location: str): async def _weather_conditions_forecast(self, ctx: commands.Context, *, location: str):
'''Posts an image of Local Weather Conditions for the next three days from [wttr.in](http://wttr.in/). """Posts an image of Local Weather Conditions for the next three days from [wttr.in](http://wttr.in/).
See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit.''' See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit."""
async with ctx.typing(): async with ctx.typing():
try: try:
units_arg = re.search(self.wttr_units_regex, location).group(1) units_arg = re.search(self.wttr_units_regex, location).group(1)
except AttributeError: except AttributeError:
units_arg = '' units_arg = ""
if units_arg.lower() == 'f': if units_arg.lower() == "f":
units = 'u' units = "u"
elif units_arg.lower() == 'c': elif units_arg.lower() == "c":
units = 'm' units = "m"
else: else:
units = '' units = ""
loc = self.wttr_units_regex.sub('', location).strip() loc = self.wttr_units_regex.sub("", location).strip()
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Weather Forecast for {loc}' embed.title = f"Weather Forecast for {loc}"
embed.description = 'Data from [wttr.in](http://wttr.in/).' embed.description = "Data from [wttr.in](http://wttr.in/)."
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
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:
raise cmn.BotHTTPError(resp) raise cmn.BotHTTPError(resp)
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"))
@_weather_conditions.command(name='now', aliases=['n'], category=cmn.cat.weather) @_weather_conditions.command(name="now", aliases=["n"], category=cmn.cat.weather)
async def _weather_conditions_now(self, ctx: commands.Context, *, location: str): async def _weather_conditions_now(self, ctx: commands.Context, *, location: str):
'''Posts an image of current Local Weather Conditions from [wttr.in](http://wttr.in/). """Posts an image of current Local Weather Conditions from [wttr.in](http://wttr.in/).
See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit.''' See help for weather command for possible location types. Add a `-c` or `-f` to use Celcius or Fahrenheit."""
async with ctx.typing(): async with ctx.typing():
try: try:
units_arg = re.search(self.wttr_units_regex, location).group(1) units_arg = re.search(self.wttr_units_regex, location).group(1)
except AttributeError: except AttributeError:
units_arg = '' units_arg = ""
if units_arg.lower() == 'f': if units_arg.lower() == "f":
units = 'u' units = "u"
elif units_arg.lower() == 'c': elif units_arg.lower() == "c":
units = 'm' units = "m"
else: else:
units = '' units = ""
loc = self.wttr_units_regex.sub('', location).strip() loc = self.wttr_units_regex.sub("", location).strip()
embed = cmn.embed_factory(ctx) embed = cmn.embed_factory(ctx)
embed.title = f'Current Weather for {loc}' embed.title = f"Current Weather for {loc}"
embed.description = 'Data from [wttr.in](http://wttr.in/).' embed.description = "Data from [wttr.in](http://wttr.in/)."
embed.colour = cmn.colours.good embed.colour = cmn.colours.good
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:
raise cmn.BotHTTPError(resp) raise cmn.BotHTTPError(resp)
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"))
def setup(bot: commands.Bot): def setup(bot: commands.Bot):

View File

@ -24,5 +24,5 @@ authors = ("@ClassAbbyAmplifier#2229", "@0x5c#0639")
description = """A bot with various useful ham radio-related functions, written in Python.""" description = """A bot with various useful ham radio-related functions, written in Python."""
license = "Released under the GNU General Public License v2" license = "Released under the GNU General Public License v2"
contributing = "Check out the source on GitHub, contributions welcome: https://github.com/classabbyamp/discord-qrm2" contributing = "Check out the source on GitHub, contributions welcome: https://github.com/classabbyamp/discord-qrm2"
release = '2.1.0' release = "2.1.0"
bot_server = 'https://discord.gg/Ntbg3J4' bot_server = "https://discord.gg/Ntbg3J4"

View File

@ -167,7 +167,7 @@ async def on_command_error(ctx: commands.Context, err: commands.CommandError):
await cmn.add_react(ctx.message, cmn.emojis.bangbang) await cmn.add_react(ctx.message, cmn.emojis.bangbang)
elif isinstance(err, (commands.CommandInvokeError, commands.ConversionError)): elif isinstance(err, (commands.CommandInvokeError, commands.ConversionError)):
# Emulating discord.py's default beaviour. # Emulating discord.py's default beaviour.
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) print("Ignoring exception in command {}:".format(ctx.command), file=sys.stderr)
traceback.print_exception(type(err), err, err.__traceback__, 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 = cmn.error_embed_factory(ctx, err.original, bot.qrm.debug_mode)
@ -176,7 +176,7 @@ async def on_command_error(ctx: commands.Context, err: commands.CommandError):
await ctx.send(embed=embed) await ctx.send(embed=embed)
else: else:
# Emulating discord.py's default beaviour. (safest bet) # Emulating discord.py's default beaviour. (safest bet)
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) print("Ignoring exception in command {}:".format(ctx.command), file=sys.stderr)
traceback.print_exception(type(err), err, err.__traceback__, file=sys.stderr) traceback.print_exception(type(err), err, err.__traceback__, file=sys.stderr)
await cmn.add_react(ctx.message, cmn.emojis.warning) await cmn.add_react(ctx.message, cmn.emojis.warning)
@ -221,7 +221,7 @@ async def _ensure_activity_fixed():
# --- Run --- # --- Run ---
for ext in opt.exts: for ext in opt.exts:
bot.load_extension(ext_dir + '.' + ext) bot.load_extension(ext_dir + "." + ext)
try: try:

View File

@ -11,45 +11,45 @@ from collections import OrderedDict
us_calls_title = "Valid US Vanity Callsigns" us_calls_title = "Valid US Vanity Callsigns"
us_calls_desc = ('#x# is the number of letters in the prefix and suffix of a callsign. ' us_calls_desc = ("#x# is the number of letters in the prefix and suffix of a callsign. "
'E.g., WY4RC would be a 2x2 callsign, with prefix WY and suffix RC.') "E.g., WY4RC would be a 2x2 callsign, with prefix WY and suffix RC.")
us_calls = OrderedDict([('**Group A** (Extra Only)', ('**Any:** K, N, W (1x2)\n' us_calls = OrderedDict([("**Group A** (Extra Only)", ("**Any:** K, N, W (1x2)\n"
' AA-AL, KA-KZ, NA-NZ, WA-WZ (2x1)\n' " AA-AL, KA-KZ, NA-NZ, WA-WZ (2x1)\n"
' AA-AL (2x2)\n' " AA-AL (2x2)\n"
'*Except*\n' "*Except*\n"
'**Alaska:** AL, KL, NL, WL (2x1)\n' "**Alaska:** AL, KL, NL, WL (2x1)\n"
'**Caribbean:** KP, NP, WP (2x1)\n' "**Caribbean:** KP, NP, WP (2x1)\n"
'**Pacific:** AH, KH, NH, WH (2x1)')), "**Pacific:** AH, KH, NH, WH (2x1)")),
('**Group B** (Advanced and Extra Only)', ('**Any:** KA-KZ, NA-NZ, WA-WZ (2x2)\n' ("**Group B** (Advanced and Extra Only)", ("**Any:** KA-KZ, NA-NZ, WA-WZ (2x2)\n"
'*Except*\n' "*Except*\n"
'**Alaska:** AL (2x2)\n' "**Alaska:** AL (2x2)\n"
'**Caribbean:** KP (2x2)\n' "**Caribbean:** KP (2x2)\n"
'**Pacific:** AH (2x2)')), "**Pacific:** AH (2x2)")),
('**Group C** (Technician, General, Advanced, Extra Only)', ('**Any Region:** K, N, W (1x3)\n' ("**Group C** (Technician, General, Advanced, Extra Only)", ("**Any Region:** K, N, W (1x3)\n"
'*Except*\n' "*Except*\n"
'**Alaska:** KL, NL, WL (2x2)\n' "**Alaska:** KL, NL, WL (2x2)\n"
'**Caribbean:** NP, WP (2x2)\n' "**Caribbean:** NP, WP (2x2)\n"
'**Pacific:** KH, NH, WH (2x2)')), "**Pacific:** KH, NH, WH (2x2)")),
('**Group D** (Any License Class)', ('**Any Region:** KA-KZ, WA-WZ (2x3)\n' ("**Group D** (Any License Class)", ("**Any Region:** KA-KZ, WA-WZ (2x3)\n"
'*Except*\n' "*Except*\n"
'**Alaska:** KL, WL (2x3)\n' "**Alaska:** KL, WL (2x3)\n"
'**Caribbean:** KP, WP (2x3)\n' "**Caribbean:** KP, WP (2x3)\n"
'**Pacific:** KH, WH (2x3)')), "**Pacific:** KH, WH (2x3)")),
('**Unavailable**', ('- KA2AA-KA9ZZ: US Army in Japan\n' ("**Unavailable**", ("- KA2AA-KA9ZZ: US Army in Japan\n"
'- KC4AAA-KC4AAF: NSF in Antartica\n' "- KC4AAA-KC4AAF: NSF in Antartica\n"
'- KC4USA-KC4USZ: US Navy in Antartica\n' "- KC4USA-KC4USZ: US Navy in Antartica\n"
'- KG4AA-KG4ZZ: US Navy in Guantanamo Bay\n' "- KG4AA-KG4ZZ: US Navy in Guantanamo Bay\n"
'- KL9KAA-KL9KHZ: US military in Korea\n' "- KL9KAA-KL9KHZ: US military in Korea\n"
'- KC6AA-KC6ZZ: Former US (Eastern and Western Caroline Islands), ' "- KC6AA-KC6ZZ: Former US (Eastern and Western Caroline Islands), "
'now Federated States of Micronesia (V6) and Republic of Palau (T8)\n' "now Federated States of Micronesia (V6) and Republic of Palau (T8)\n"
'- KX6AA-KX6ZZ: Former US (Marshall Islands), ' "- KX6AA-KX6ZZ: Former US (Marshall Islands), "
'now Republic of the Marshall Islands (V73)\n' "now Republic of the Marshall Islands (V73)\n"
'- Any suffix SOS or QRA-QUZ\n' "- Any suffix SOS or QRA-QUZ\n"
'- Any 2x3 with X as the first suffix letter\n' "- Any 2x3 with X as the first suffix letter\n"
'- Any 2x3 with AF, KF, NF, or WF prefix and suffix EMA: FEMA\n' "- Any 2x3 with AF, KF, NF, or WF prefix and suffix EMA: FEMA\n"
'- Any 2x3 with AA-AL, NA-NZ, WC, WK, WM, WR, or WT prefix: "Group X"\n' "- Any 2x3 with AA-AL, NA-NZ, WC, WK, WM, WR, or WT prefix: \"Group X\"\n"
'- Any 2x1, 2x2, or 2x3 with KP, NP, WP prefix and 0, 6, 7, 8, 9 number\n' "- Any 2x1, 2x2, or 2x3 with KP, NP, WP prefix and 0, 6, 7, 8, 9 number\n"
'- Any 1x1 callsign: Special Event'))]) "- Any 1x1 callsign: Special Event"))])
# format: country: (title, description, text) # format: country: (title, description, text)
options = {'us': (us_calls_title, us_calls_desc, us_calls)} options = {"us": (us_calls_title, us_calls_desc, us_calls)}

View File

@ -7,8 +7,8 @@ This file is part of discord-qrmbot and is released under the terms of the GNU
General Public License, version 2. General Public License, version 2.
""" """
phonetics = {'a': 'alfa', 'b': 'bravo', 'c': 'charlie', 'd': 'delta', 'e': 'echo', 'f': 'foxtrot', phonetics = {"a": "alfa", "b": "bravo", "c": "charlie", "d": "delta", "e": "echo", "f": "foxtrot",
'g': 'golf', 'h': 'hotel', 'i': 'india', 'j': 'juliett', 'k': 'kilo', 'l': 'lima', "g": "golf", "h": "hotel", "i": "india", "j": "juliett", "k": "kilo", "l": "lima",
'm': 'mike', 'n': 'november', 'o': 'oscar', 'p': 'papa', 'q': 'quebec', 'r': 'romeo', "m": "mike", "n": "november", "o": "oscar", "p": "papa", "q": "quebec", "r": "romeo",
's': 'sierra', 't': 'tango', 'u': 'uniform', 'v': 'victor', 'w': 'whiskey', 'x': 'x-ray', "s": "sierra", "t": "tango", "u": "uniform", "v": "victor", "w": "whiskey", "x": "x-ray",
'y': 'yankee', 'z': 'zulu'} "y": "yankee", "z": "zulu"}

View File

@ -7,43 +7,43 @@ This file is part of discord-qrmbot and is released under the terms of the GNU
General Public License, version 2. General Public License, version 2.
""" """
pool_names = {'us': {'technician': 'E2', pool_names = {"us": {"technician": "E2",
'tech': 'E2', "tech": "E2",
't': 'E2', "t": "E2",
'general': 'E3', "general": "E3",
'gen': 'E3', "gen": "E3",
'g': 'E3', "g": "E3",
'extra': 'E4', "extra": "E4",
'e': 'E4'}, "e": "E4"},
'ca': {'basic': 'CA_B', "ca": {"basic": "CA_B",
'b': 'CA_B', "b": "CA_B",
'advanced': 'CA_A', "advanced": "CA_A",
'adv': 'CA_A', "adv": "CA_A",
'a': 'CA_A', "a": "CA_A",
'basic_fr': 'CA_FB', "basic_fr": "CA_FB",
'b_fr': 'CA_FB', "b_fr": "CA_FB",
'base': 'CA_FB', "base": "CA_FB",
'advanced_fr': 'CA_FS', "advanced_fr": "CA_FS",
'adv_fr': 'CA_FS', "adv_fr": "CA_FS",
'a_fr': 'CA_FS', "a_fr": "CA_FS",
'supérieure': 'CA_FS', "supérieure": "CA_FS",
'superieure': 'CA_FS', "superieure": "CA_FS",
's': 'CA_FS'}, "s": "CA_FS"},
'us_c': {'c1': 'C1', "us_c": {"c1": "C1",
'comm1': 'C1', "comm1": "C1",
'c3': 'C3', "c3": "C3",
'comm3': 'C3', "comm3": "C3",
'c6': 'C6', "c6": "C6",
'comm6': 'C6', "comm6": "C6",
'c7': 'C7', "c7": "C7",
'comm7': 'C7', "comm7": "C7",
'c7r': 'C7R', "c7r": "C7R",
'comm7r': 'C7R', "comm7r": "C7R",
'c8': 'C8', "c8": "C8",
'comm8': 'C8', "comm8": "C8",
'c9': 'C9', "c9": "C9",
'comm9': 'C9'}} "comm9": "C9"}}
pool_emojis = {'us': '🇺🇸', pool_emojis = {"us": "🇺🇸",
'ca': '🇨🇦', "ca": "🇨🇦",
'us_c': '🇺🇸 🏢'} "us_c": "🇺🇸 🏢"}

View File

@ -27,7 +27,7 @@ debug = False
owners_uids = (200102491231092736,) owners_uids = (200102491231092736,)
# The extensions to load when running the bot. # The extensions to load when running the bot.
exts = ['ae7q', 'base', 'fun', 'grid', 'ham', 'image', 'lookup', 'morse', 'qrz', 'study', 'weather'] exts = ["ae7q", "base", "fun", "grid", "ham", "image", "lookup", "morse", "qrz", "study", "weather"]
# Either "time", "random", or "fixed" (first item in statuses) # Either "time", "random", or "fixed" (first item in statuses)
status_mode = "fixed" status_mode = "fixed"
@ -37,17 +37,17 @@ statuses = ["with lids on the air", "with fire"]
# Timezone for the status (string) # Timezone for the status (string)
# See https://pythonhosted.org/pytz/ for more info # See https://pythonhosted.org/pytz/ for more info
status_tz = 'US/Eastern' status_tz = "US/Eastern"
# The text to put in the "playing" status, with start and stop times # The text to put in the "playing" status, with start and stop times
time_statuses = [('with lids on 3.840', (00, 00), (6, 00)), time_statuses = [("with lids on 3.840", (00, 00), (6, 00)),
('with lids on 7.200', (6, 00), (10, 00)), ("with lids on 7.200", (6, 00), (10, 00)),
('with lids on 14.313', (10, 00), (18, 00)), ("with lids on 14.313", (10, 00), (18, 00)),
('with lids on 7.200', (18, 00), (20, 00)), ("with lids on 7.200", (18, 00), (20, 00)),
('with lids on 3.840', (20, 00), (23, 59))] ("with lids on 3.840", (20, 00), (23, 59))]
# Emoji IDs and keywords for emoji reactions # Emoji IDs and keywords for emoji reactions
# Use the format {emoji_id (int): ('tuple', 'of', 'lowercase', 'keywords')} # Use the format {emoji_id (int): ("tuple", "of", "lowercase", "keywords")}
msg_reacts = {} msg_reacts = {}
# A :pika: emote's ID, None for no emote :c # A :pika: emote's ID, None for no emote :c