[Config] Asynchronous getters (#907)

* Make config get async

* Asyncify alias

* Asyncify bank

* Asyncify cog manager

* IT BOOTS

* Asyncify core commands

* Asyncify repo manager

* Asyncify downloader

* Asyncify economy

* Asyncify alias TESTS

* Asyncify economy TESTS

* Asyncify downloader TESTS

* Asyncify config TESTS

* A bank thing

* Asyncify Bank cog

* Warning message in docs

* Update docs with await syntax

* Update docs with await syntax
This commit is contained in:
Will
2017-08-11 21:43:21 -04:00
committed by GitHub
parent cf8e11238c
commit de912a3cfb
18 changed files with 371 additions and 296 deletions

View File

@@ -38,26 +38,26 @@ class Alias:
self._aliases.register_global(**self.default_global_settings)
self._aliases.register_guild(**self.default_guild_settings)
def unloaded_aliases(self, guild: discord.Guild) -> Generator[AliasEntry, None, None]:
return (AliasEntry.from_json(d) for d in self._aliases.guild(guild).entries())
async def unloaded_aliases(self, guild: discord.Guild) -> Generator[AliasEntry, None, None]:
return (AliasEntry.from_json(d) for d in (await self._aliases.guild(guild).entries()))
def unloaded_global_aliases(self) -> Generator[AliasEntry, None, None]:
return (AliasEntry.from_json(d) for d in self._aliases.entries())
async def unloaded_global_aliases(self) -> Generator[AliasEntry, None, None]:
return (AliasEntry.from_json(d) for d in (await self._aliases.entries()))
def loaded_aliases(self, guild: discord.Guild) -> Generator[AliasEntry, None, None]:
async def loaded_aliases(self, guild: discord.Guild) -> Generator[AliasEntry, None, None]:
return (AliasEntry.from_json(d, bot=self.bot)
for d in self._aliases.guild(guild).entries())
for d in (await self._aliases.guild(guild).entries()))
def loaded_global_aliases(self) -> Generator[AliasEntry, None, None]:
return (AliasEntry.from_json(d, bot=self.bot) for d in self._aliases.entries())
async def loaded_global_aliases(self) -> Generator[AliasEntry, None, None]:
return (AliasEntry.from_json(d, bot=self.bot) for d in (await self._aliases.entries()))
def is_alias(self, guild: discord.Guild, alias_name: str,
async def is_alias(self, guild: discord.Guild, alias_name: str,
server_aliases: Iterable[AliasEntry]=()) -> (bool, AliasEntry):
if not server_aliases:
server_aliases = self.unloaded_aliases(guild)
server_aliases = await self.unloaded_aliases(guild)
global_aliases = self.unloaded_global_aliases()
global_aliases = await self.unloaded_global_aliases()
for aliases in (server_aliases, global_aliases):
for alias in aliases:
@@ -79,11 +79,11 @@ class Alias:
alias = AliasEntry(alias_name, command, ctx.author, global_=global_)
if global_:
curr_aliases = self._aliases.entries()
curr_aliases = await self._aliases.entries()
curr_aliases.append(alias.to_json())
await self._aliases.entries.set(curr_aliases)
else:
curr_aliases = self._aliases.guild(ctx.guild).entries()
curr_aliases = await self._aliases.guild(ctx.guild).entries()
curr_aliases.append(alias.to_json())
await self._aliases.guild(ctx.guild).entries.set(curr_aliases)
@@ -94,10 +94,10 @@ class Alias:
async def delete_alias(self, ctx: commands.Context, alias_name: str,
global_: bool=False) -> bool:
if global_:
aliases = self.unloaded_global_aliases()
aliases = await self.unloaded_global_aliases()
setter_func = self._aliases.entries.set
else:
aliases = self.unloaded_aliases(ctx.guild)
aliases = await self.unloaded_aliases(ctx.guild)
setter_func = self._aliases.guild(ctx.guild).entries.set
did_delete_alias = False
@@ -161,7 +161,7 @@ class Alias:
except IndexError:
return False
is_alias, alias = self.is_alias(message.guild, potential_alias, server_aliases=aliases)
is_alias, alias = await self.is_alias(message.guild, potential_alias, server_aliases=aliases)
if is_alias:
await self.call_alias(message, prefix, alias)
@@ -206,7 +206,7 @@ class Alias:
" name is already a command on this bot.").format(alias_name))
return
is_alias, _ = self.is_alias(ctx.guild, alias_name)
is_alias, _ = await self.is_alias(ctx.guild, alias_name)
if is_alias:
await ctx.send(("You attempted to create a new alias"
" with the name {} but that"
@@ -285,7 +285,7 @@ class Alias:
@commands.guild_only()
async def _show_alias(self, ctx: commands.Context, alias_name: str):
"""Shows what command the alias executes."""
is_alias, alias = self.is_alias(ctx.guild, alias_name)
is_alias, alias = await self.is_alias(ctx.guild, alias_name)
if is_alias:
await ctx.send(("The `{}` alias will execute the"
@@ -299,7 +299,7 @@ class Alias:
"""
Deletes an existing alias on this server.
"""
aliases = self.unloaded_aliases(ctx.guild)
aliases = await self.unloaded_aliases(ctx.guild)
try:
next(aliases)
except StopIteration:
@@ -317,7 +317,7 @@ class Alias:
"""
Deletes an existing global alias.
"""
aliases = self.unloaded_global_aliases()
aliases = await self.unloaded_global_aliases()
try:
next(aliases)
except StopIteration:
@@ -336,7 +336,7 @@ class Alias:
"""
Lists the available aliases on this server.
"""
names = ["Aliases:", ] + sorted(["+ " + a.name for a in self.unloaded_aliases(ctx.guild)])
names = ["Aliases:", ] + sorted(["+ " + a.name for a in (await self.unloaded_aliases(ctx.guild))])
if len(names) == 0:
await ctx.send("There are no aliases on this server.")
else:
@@ -347,16 +347,16 @@ class Alias:
"""
Lists the available global aliases on this bot.
"""
names = ["Aliases:", ] + sorted(["+ " + a.name for a in self.unloaded_global_aliases()])
names = ["Aliases:", ] + sorted(["+ " + a.name for a in await self.unloaded_global_aliases()])
if len(names) == 0:
await ctx.send("There are no aliases on this server.")
else:
await ctx.send(box("\n".join(names), "diff"))
async def on_message(self, message: discord.Message):
aliases = list(self.unloaded_global_aliases())
aliases = list(await self.unloaded_global_aliases())
if message.guild is not None:
aliases = aliases + list(self.unloaded_aliases(message.guild))
aliases = aliases + list(await self.unloaded_aliases(message.guild))
if len(aliases) == 0:
return

View File

@@ -6,7 +6,7 @@ from core.bot import Red # Only used for type hints
def check_global_setting_guildowner():
async def pred(ctx: commands.Context):
if bank.is_global():
if await bank.is_global():
return checks.is_owner()
else:
return checks.guildowner_or_permissions(administrator=True)
@@ -15,7 +15,7 @@ def check_global_setting_guildowner():
def check_global_setting_admin():
async def pred(ctx: commands.Context):
if bank.is_global():
if await bank.is_global():
return checks.is_owner()
else:
return checks.admin_or_permissions(manage_guild=True)
@@ -43,7 +43,7 @@ class Bank:
"""Toggles whether the bank is global or not
If the bank is global, it will become per-guild
If the bank is per-guild, it will become global"""
cur_setting = bank.is_global()
cur_setting = await bank.is_global()
await bank.set_global(not cur_setting, ctx.author)
word = "per-guild" if cur_setting else "global"

View File

@@ -49,22 +49,20 @@ class Downloader:
self._repo_manager = RepoManager(self.conf)
@property
def cog_install_path(self):
async def cog_install_path(self):
"""
Returns the current cog install path.
:return:
"""
return self.bot.cog_mgr.install_path
return await self.bot.cog_mgr.install_path()
@property
def installed_cogs(self) -> Tuple[Installable]:
async def installed_cogs(self) -> Tuple[Installable]:
"""
Returns the dictionary mapping cog name to install location
and repo name.
:return:
"""
installed = self.conf.installed()
installed = await self.conf.installed()
# noinspection PyTypeChecker
return tuple(Installable.from_json(v) for v in installed)
@@ -74,7 +72,7 @@ class Downloader:
:param cog:
:return:
"""
installed = self.conf.installed()
installed = await self.conf.installed()
cog_json = cog.to_json()
if cog_json not in installed:
@@ -87,7 +85,7 @@ class Downloader:
:param cog:
:return:
"""
installed = self.conf.installed()
installed = await self.conf.installed()
cog_json = cog.to_json()
if cog_json in installed:
@@ -102,7 +100,7 @@ class Downloader:
"""
failed = []
for cog in cogs:
if not await cog.copy_to(self.cog_install_path):
if not await cog.copy_to(await self.cog_install_path()):
failed.append(cog)
# noinspection PyTypeChecker
@@ -249,7 +247,7 @@ class Downloader:
" `{}`: `{}`".format(cog.name, cog.requirements))
return
await repo_name.install_cog(cog, self.cog_install_path)
await repo_name.install_cog(cog, await self.cog_install_path())
await self._add_to_installed(cog)
@@ -266,7 +264,7 @@ class Downloader:
# noinspection PyUnresolvedReferences,PyProtectedMember
real_name = cog_name.name
poss_installed_path = self.cog_install_path / real_name
poss_installed_path = (await self.cog_install_path()) / real_name
if poss_installed_path.exists():
await self._delete_cog(poss_installed_path)
# noinspection PyTypeChecker
@@ -284,7 +282,7 @@ class Downloader:
"""
if cog_name is None:
updated = await self._repo_manager.update_all_repos()
installed_cogs = set(self.installed_cogs)
installed_cogs = set(await self.installed_cogs())
updated_cogs = set(cog for repo in updated.keys() for cog in repo.available_cogs)
installed_and_updated = updated_cogs & installed_cogs
@@ -325,14 +323,14 @@ class Downloader:
msg = "Information on {}:\n{}".format(cog.name, cog.description or "")
await ctx.send(box(msg))
def is_installed(self, cog_name: str) -> (bool, Union[Installable, None]):
async def is_installed(self, cog_name: str) -> (bool, Union[Installable, None]):
"""
Checks to see if a cog with the given name was installed
through Downloader.
:param cog_name:
:return: is_installed, Installable
"""
for installable in self.installed_cogs:
for installable in await self.installed_cogs():
if installable.name == cog_name:
return True, installable
return False, None
@@ -384,7 +382,7 @@ class Downloader:
# Check if in installed cogs
cog_name = self.cog_name_from_instance(command.instance)
installed, cog_installable = self.is_installed(cog_name)
installed, cog_installable = await self.is_installed(cog_name)
if installed:
msg = self.format_findcog_info(command_name, cog_installable)
else:

View File

@@ -430,7 +430,10 @@ class RepoManager:
self.repos_folder = Path(__file__).parent / 'repos'
self._repos = self._load_repos() # str_name: Repo
self._repos = {}
loop = asyncio.get_event_loop()
loop.run_until_complete(self._load_repos(set=True)) # str_name: Repo
def does_repo_exist(self, name: str) -> bool:
return name in self._repos
@@ -494,7 +497,6 @@ class RepoManager:
shutil.rmtree(str(repo.folder_path))
repos = self.downloader_config.repos()
try:
del self._repos[name]
except KeyError:
@@ -518,11 +520,14 @@ class RepoManager:
await self._save_repos()
return ret
def _load_repos(self) -> MutableMapping[str, Repo]:
return {
async def _load_repos(self, set=False) -> MutableMapping[str, Repo]:
ret = {
name: Repo.from_json(data) for name, data in
self.downloader_config.repos().items()
(await self.downloader_config.repos()).items()
}
if set:
self._repos = ret
return ret
async def _save_repos(self):
repo_json_info = {name: r.to_json() for name, r in self._repos.items()}

View File

@@ -72,9 +72,9 @@ SLOT_PAYOUTS_MSG = ("Slot machine payouts:\n"
def guild_only_check():
async def pred(ctx: commands.Context):
if bank.is_global():
if await bank.is_global():
return True
elif not bank.is_global() and ctx.guild is not None:
elif not await bank.is_global() and ctx.guild is not None:
return True
else:
return False
@@ -146,8 +146,8 @@ class Economy:
if user is None:
user = ctx.author
bal = bank.get_balance(user)
currency = bank.get_currency_name(ctx.guild)
bal = await bank.get_balance(user)
currency = await bank.get_currency_name(ctx.guild)
await ctx.send("{}'s balance is {} {}".format(
user.display_name, bal, currency))
@@ -156,7 +156,7 @@ class Economy:
async def transfer(self, ctx: commands.Context, to: discord.Member, amount: int):
"""Transfer currency to other users"""
from_ = ctx.author
currency = bank.get_currency_name(ctx.guild)
currency = await bank.get_currency_name(ctx.guild)
try:
await bank.transfer_credits(from_, to, amount)
@@ -206,12 +206,12 @@ class Economy:
await ctx.send(
"This will delete all bank accounts for {}.\nIf you're sure, type "
"{}bank reset yes".format(
self.bot.user.name if bank.is_global() else "this guild",
self.bot.user.name if await bank.is_global() else "this guild",
ctx.prefix
)
)
else:
if bank.is_global():
if await bank.is_global():
# Bank being global means that the check would cause only
# the owner and any co-owners to be able to run the command
# so if we're in the function, it's safe to assume that the
@@ -232,18 +232,18 @@ class Economy:
guild = ctx.guild
cur_time = calendar.timegm(ctx.message.created_at.utctimetuple())
credits_name = bank.get_currency_name(ctx.guild)
if bank.is_global():
next_payday = self.config.user(author).next_payday()
credits_name = await bank.get_currency_name(ctx.guild)
if await bank.is_global():
next_payday = await self.config.user(author).next_payday()
if cur_time >= next_payday:
await bank.deposit_credits(author, self.config.PAYDAY_CREDITS())
next_payday = cur_time + self.config.PAYDAY_TIME()
await bank.deposit_credits(author, await self.config.PAYDAY_CREDITS())
next_payday = cur_time + await self.config.PAYDAY_TIME()
await self.config.user(author).next_payday.set(next_payday)
await ctx.send(
"{} Here, take some {}. Enjoy! (+{}"
" {}!)".format(
author.mention, credits_name,
str(self.config.PAYDAY_CREDITS()),
str(await self.config.PAYDAY_CREDITS()),
credits_name
)
)
@@ -254,16 +254,16 @@ class Economy:
" wait {}.".format(author.mention, dtime)
)
else:
next_payday = self.config.member(author).next_payday()
next_payday = await self.config.member(author).next_payday()
if cur_time >= next_payday:
await bank.deposit_credits(author, self.config.guild(guild).PAYDAY_CREDITS())
next_payday = cur_time + self.config.guild(guild).PAYDAY_TIME()
await bank.deposit_credits(author, await self.config.guild(guild).PAYDAY_CREDITS())
next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME()
await self.config.member(author).next_payday.set(next_payday)
await ctx.send(
"{} Here, take some {}. Enjoy! (+{}"
" {}!)".format(
author.mention, credits_name,
str(self.config.guild(guild).PAYDAY_CREDITS()),
str(await self.config.guild(guild).PAYDAY_CREDITS()),
credits_name))
else:
dtime = self.display_time(next_payday - cur_time)
@@ -282,10 +282,10 @@ class Economy:
if top < 1:
top = 10
if bank.is_global():
bank_sorted = sorted(bank.get_global_accounts(ctx.author),
bank_sorted = sorted(await bank.get_global_accounts(ctx.author),
key=lambda x: x.balance, reverse=True)
else:
bank_sorted = sorted(bank.get_guild_accounts(guild),
bank_sorted = sorted(await bank.get_guild_accounts(guild),
key=lambda x: x.balance, reverse=True)
if len(bank_sorted) < top:
top = len(bank_sorted)
@@ -320,14 +320,14 @@ class Economy:
author = ctx.author
guild = ctx.guild
channel = ctx.channel
if bank.is_global():
valid_bid = self.config.SLOT_MIN() <= bid <= self.config.SLOT_MAX()
slot_time = self.config.SLOT_TIME()
last_slot = self.config.user(author).last_slot()
if await bank.is_global():
valid_bid = await self.config.SLOT_MIN() <= bid <= await self.config.SLOT_MAX()
slot_time = await self.config.SLOT_TIME()
last_slot = await self.config.user(author).last_slot()
else:
valid_bid = self.config.guild(guild).SLOT_MIN() <= bid <= self.config.guild(guild).SLOT_MAX()
slot_time = self.config.guild(guild).SLOT_TIME()
last_slot = self.config.member(author).last_slot()
valid_bid = await self.config.guild(guild).SLOT_MIN() <= bid <= await self.config.guild(guild).SLOT_MAX()
slot_time = await self.config.guild(guild).SLOT_TIME()
last_slot = await self.config.member(author).last_slot()
now = calendar.timegm(ctx.message.created_at.utctimetuple())
if (now - last_slot) < slot_time:
@@ -336,10 +336,10 @@ class Economy:
if not valid_bid:
await ctx.send("That's an invalid bid amount, sorry :/")
return
if not bank.can_spend(author, bid):
if not await bank.can_spend(author, bid):
await ctx.send("You ain't got enough money, friend.")
return
if bank.is_global():
if await bank.is_global():
await self.config.user(author).last_slot.set(now)
else:
await self.config.member(author).last_slot.set(now)
@@ -379,7 +379,7 @@ class Economy:
payout = PAYOUTS["2 symbols"]
if payout:
then = bank.get_balance(author)
then = await bank.get_balance(author)
pay = payout["payout"](bid)
now = then - bid + pay
await bank.set_balance(author, now)
@@ -387,7 +387,7 @@ class Economy:
"".format(slot, author.mention,
payout["phrase"], bid, then, now))
else:
then = bank.get_balance(author)
then = await bank.get_balance(author)
await bank.withdraw_credits(author, bid)
now = then - bid
await channel.send("{}\n{} Nothing!\nYour bid: {}\n{}{}!"
@@ -402,18 +402,18 @@ class Economy:
if ctx.invoked_subcommand is None:
await self.bot.send_cmd_help(ctx)
if bank.is_global():
slot_min = self.config.SLOT_MIN()
slot_max = self.config.SLOT_MAX()
slot_time = self.config.SLOT_TIME()
payday_time = self.config.PAYDAY_TIME()
payday_amount = self.config.PAYDAY_CREDITS()
slot_min = await self.config.SLOT_MIN()
slot_max = await self.config.SLOT_MAX()
slot_time = await self.config.SLOT_TIME()
payday_time = await self.config.PAYDAY_TIME()
payday_amount = await self.config.PAYDAY_CREDITS()
else:
slot_min = self.config.guild(guild).SLOT_MIN()
slot_max = self.config.guild(guild).SLOT_MAX()
slot_time = self.config.guild(guild).SLOT_TIME()
payday_time = self.config.guild(guild).PAYDAY_TIME()
payday_amount = self.config.guild(guild).PAYDAY_CREDITS()
register_amount = bank.get_default_balance(guild)
slot_min = await self.config.guild(guild).SLOT_MIN()
slot_max = await self.config.guild(guild).SLOT_MAX()
slot_time = await self.config.guild(guild).SLOT_TIME()
payday_time = await self.config.guild(guild).PAYDAY_TIME()
payday_amount = await self.config.guild(guild).PAYDAY_CREDITS()
register_amount = await bank.get_default_balance(guild)
msg = box(
"Minimum slot bid: {}\n"
"Maximum slot bid: {}\n"
@@ -436,24 +436,24 @@ class Economy:
await ctx.send('Invalid min bid amount.')
return
guild = ctx.guild
if bank.is_global():
if await bank.is_global():
await self.config.SLOT_MIN.set(bid)
else:
await self.config.guild(guild).SLOT_MIN.set(bid)
credits_name = bank.get_currency_name(guild)
credits_name = await bank.get_currency_name(guild)
await ctx.send("Minimum bid is now {} {}.".format(bid, credits_name))
@economyset.command()
async def slotmax(self, ctx: commands.Context, bid: int):
"""Maximum slot machine bid"""
slot_min = self.config.SLOT_MIN()
slot_min = await self.config.SLOT_MIN()
if bid < 1 or bid < slot_min:
await ctx.send('Invalid slotmax bid amount. Must be greater'
' than slotmin.')
return
guild = ctx.guild
credits_name = bank.get_currency_name(guild)
if bank.is_global():
credits_name = await bank.get_currency_name(guild)
if await bank.is_global():
await self.config.SLOT_MAX.set(bid)
else:
await self.config.guild(guild).SLOT_MAX.set(bid)
@@ -463,7 +463,7 @@ class Economy:
async def slottime(self, ctx: commands.Context, seconds: int):
"""Seconds between each slots use"""
guild = ctx.guild
if bank.is_global():
if await bank.is_global():
await self.config.SLOT_TIME.set(seconds)
else:
await self.config.guild(guild).SLOT_TIME.set(seconds)
@@ -473,7 +473,7 @@ class Economy:
async def paydaytime(self, ctx: commands.Context, seconds: int):
"""Seconds between each payday"""
guild = ctx.guild
if bank.is_global():
if await bank.is_global():
await self.config.PAYDAY_TIME.set(seconds)
else:
await self.config.guild(guild).PAYDAY_TIME.set(seconds)
@@ -484,11 +484,11 @@ class Economy:
async def paydayamount(self, ctx: commands.Context, creds: int):
"""Amount earned each payday"""
guild = ctx.guild
credits_name = bank.get_currency_name(guild)
credits_name = await bank.get_currency_name(guild)
if creds <= 0:
await ctx.send("Har har so funny.")
return
if bank.is_global():
if await bank.is_global():
await self.config.PAYDAY_CREDITS.set(creds)
else:
await self.config.guild(guild).PAYDAY_CREDITS.set(creds)
@@ -501,7 +501,7 @@ class Economy:
guild = ctx.guild
if creds < 0:
creds = 0
credits_name = bank.get_currency_name(guild)
credits_name = await bank.get_currency_name(guild)
await bank.set_default_balance(creds, guild)
await ctx.send("Registering an account will now give {} {}."
"".format(creds, credits_name))