From ec30069ff5e5fafb2706a72e7f3fba416f8c7768 Mon Sep 17 00:00:00 2001 From: Nick Jungmann Date: Sun, 11 Dec 2022 02:51:35 +0100 Subject: [PATCH 1/5] Added user set command --- .../src/modules/base/command/user_group.py | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/kdb-bot/src/modules/base/command/user_group.py b/kdb-bot/src/modules/base/command/user_group.py index 077a32d3..171e713e 100644 --- a/kdb-bot/src/modules/base/command/user_group.py +++ b/kdb-bot/src/modules/base/command/user_group.py @@ -2,6 +2,7 @@ from typing import Optional, List import discord from cpl_core.configuration import ConfigurationABC +from cpl_core.database.context import DatabaseContextABC from cpl_discord.command import DiscordCommandABC from cpl_discord.service import DiscordBotServiceABC from cpl_translation import TranslatePipe @@ -32,6 +33,7 @@ class UserGroup(DiscordCommandABC): client_utils: ClientUtilsServiceABC, permissions: PermissionServiceABC, servers: ServerRepositoryABC, + db: DatabaseContextABC, users: UserRepositoryABC, user_joined_servers: UserJoinedServerRepositoryABC, user_joined_voice_channel: UserJoinedVoiceChannelRepositoryABC, @@ -47,6 +49,7 @@ class UserGroup(DiscordCommandABC): self._client_utils = client_utils self._permissions = permissions self._servers = servers + self._db = db self._users = users self._user_joined_servers = user_joined_servers self._user_joined_voice_channel = user_joined_voice_channel @@ -130,7 +133,7 @@ class UserGroup(DiscordCommandABC): @commands.guild_only() @CommandChecks.check_is_ready() async def get(self, ctx: Context, atr: str, member: discord.Member = None): - self._logger.debug(__name__, f'Received command user-info {ctx}:{member}') + self._logger.debug(__name__, f'Received command user-get {ctx}:{member}') is_mod = self._permissions.is_member_moderator(ctx.author) if member is not None and not is_mod: @@ -167,3 +170,49 @@ class UserGroup(DiscordCommandABC): async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: atr_list = ['xp', 'ontime'] return [app_commands.Choice(name=atr, value=atr) for atr in atr_list] + + @user.command() + @commands.guild_only() + @CommandChecks.check_is_ready() + @CommandChecks.check_is_member_moderator() + async def set(self, ctx: Context, atr: str, value: str, member: discord.Member = None): + self._logger.debug(__name__, f'Received command user-set {ctx}:{member}') + + if value == '': + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.no_value')) + return + + if member is None or not isinstance(member, discord.Member): + member = ctx.author + + server = self._servers.find_server_by_discord_id(ctx.guild.id) + user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) + + match atr: + case 'xp': + try: + user.xp = int(value) + self._users.update_user(user) + self._db.save_changes() + except Exception as e: + await self._logger.trace(__name__, f'Value couldn\'t be converted to int\n'+e) + # ToDo: Add text for this exception + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.value_type')) + return + + case other: + # ToDo: Move atr_not_found + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( + 'modules.base.user.error.atr_not_found').format(atr)) + return + + # ToDo: Add text for set + await self._message_service.send_interaction_msg( + ctx.interaction, + self._t.transform(f'modules.base.user.set.{atr}').format(member.mention, value) + ) + + @set.autocomplete('atr') + async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: + atr_list = ['xp'] + return [app_commands.Choice(name=atr, value=atr) for atr in atr_list] From cf610b770b71a74efa419e624603f856066d6bac Mon Sep 17 00:00:00 2001 From: Nick Jungmann Date: Sun, 11 Dec 2022 14:18:31 +0100 Subject: [PATCH 2/5] Added translation for user set command --- kdb-bot/src/bot/translation/de.json | 8 +++++++- kdb-bot/src/modules/base/command/user_group.py | 9 +-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kdb-bot/src/bot/translation/de.json b/kdb-bot/src/bot/translation/de.json index 2c88a59e..01809096 100644 --- a/kdb-bot/src/bot/translation/de.json +++ b/kdb-bot/src/bot/translation/de.json @@ -177,9 +177,15 @@ "footer": "" }, "get": { - "atr_not_found": "Das Attribut {} konnte nicht gefunden werden :(", "xp": "{} hat {} xp", "ontime": "{} war insgesamt {} Stunden aktiv in einem Sprachkanal" + }, + "set": { + "xp": "{} hat nun {} xp" + }, + "error": { + "atr_not_found": "Das Attribut {} konnte nicht gefunden werden :(", + "value_type": "Der angegebende Wert konnte nicht für das Attribut interpretiert werden :(" } } }, diff --git a/kdb-bot/src/modules/base/command/user_group.py b/kdb-bot/src/modules/base/command/user_group.py index 171e713e..3fa0b81e 100644 --- a/kdb-bot/src/modules/base/command/user_group.py +++ b/kdb-bot/src/modules/base/command/user_group.py @@ -158,7 +158,7 @@ class UserGroup(DiscordCommandABC): )) case other: - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.get.atr_not_found').format(atr)) + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.atr_not_found').format(atr)) return await self._message_service.send_interaction_msg( @@ -178,10 +178,6 @@ class UserGroup(DiscordCommandABC): async def set(self, ctx: Context, atr: str, value: str, member: discord.Member = None): self._logger.debug(__name__, f'Received command user-set {ctx}:{member}') - if value == '': - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.no_value')) - return - if member is None or not isinstance(member, discord.Member): member = ctx.author @@ -196,17 +192,14 @@ class UserGroup(DiscordCommandABC): self._db.save_changes() except Exception as e: await self._logger.trace(__name__, f'Value couldn\'t be converted to int\n'+e) - # ToDo: Add text for this exception await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.value_type')) return case other: - # ToDo: Move atr_not_found await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( 'modules.base.user.error.atr_not_found').format(atr)) return - # ToDo: Add text for set await self._message_service.send_interaction_msg( ctx.interaction, self._t.transform(f'modules.base.user.set.{atr}').format(member.mention, value) From 5a4c2901f520e3744d397dfc1d3bf3c291ff11a2 Mon Sep 17 00:00:00 2001 From: Nick Jungmann Date: Sat, 17 Dec 2022 19:21:04 +0100 Subject: [PATCH 3/5] Fixed not checking level after new XP is assinged to user #22 --- kdb-bot/src/bot/translation/de.json | 9 ++++++--- kdb-bot/src/modules/base/command/user_group.py | 14 +++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/kdb-bot/src/bot/translation/de.json b/kdb-bot/src/bot/translation/de.json index 01809096..e18c24b5 100644 --- a/kdb-bot/src/bot/translation/de.json +++ b/kdb-bot/src/bot/translation/de.json @@ -181,11 +181,14 @@ "ontime": "{} war insgesamt {} Stunden aktiv in einem Sprachkanal" }, "set": { - "xp": "{} hat nun {} xp" + "xp": "{} hat nun {} xp", + "error": { + "value_type_not_numeric": "Der angegebende Wert ist keine Ganzzahl! :(", + "set_xp": "Es kam zu einem Fehler bei der Zuweisung der XP :(" + } }, "error": { - "atr_not_found": "Das Attribut {} konnte nicht gefunden werden :(", - "value_type": "Der angegebende Wert konnte nicht für das Attribut interpretiert werden :(" + "atr_not_found": "Das Attribut {} konnte nicht gefunden werden :(" } } }, diff --git a/kdb-bot/src/modules/base/command/user_group.py b/kdb-bot/src/modules/base/command/user_group.py index 3fa0b81e..0c6692f6 100644 --- a/kdb-bot/src/modules/base/command/user_group.py +++ b/kdb-bot/src/modules/base/command/user_group.py @@ -19,6 +19,7 @@ from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC from bot_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC from bot_data.abc.user_repository_abc import UserRepositoryABC +from modules.level.service.level_service import LevelService from modules.permission.abc.permission_service_abc import PermissionServiceABC @@ -38,7 +39,8 @@ class UserGroup(DiscordCommandABC): user_joined_servers: UserJoinedServerRepositoryABC, user_joined_voice_channel: UserJoinedVoiceChannelRepositoryABC, translate: TranslatePipe, - date: DateTimeOffsetPipe + date: DateTimeOffsetPipe, + level: LevelService ): DiscordCommandABC.__init__(self) @@ -55,6 +57,7 @@ class UserGroup(DiscordCommandABC): self._user_joined_voice_channel = user_joined_voice_channel self._t = translate self._date = date + self._level = level self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}') @@ -186,13 +189,18 @@ class UserGroup(DiscordCommandABC): match atr: case 'xp': + if not value.isnumeric(): + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.value_type_not_numeric')) + return + try: user.xp = int(value) self._users.update_user(user) self._db.save_changes() + await self._level.check_level(member) except Exception as e: - await self._logger.trace(__name__, f'Value couldn\'t be converted to int\n'+e) - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.value_type')) + self._logger.error(__name__, f'Value couldn\'t be converted to int', e) + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.set_xp')) return case other: From 1b9553e63b874fe4a6bf67327f00cb577a62b23b Mon Sep 17 00:00:00 2001 From: Nick Jungmann Date: Sun, 18 Dec 2022 22:42:38 +0100 Subject: [PATCH 4/5] Improved error handling and changed attribute names from constants to variables which are located in the language file #22 --- kdb-bot/src/bot/translation/de.json | 28 +++++----- .../src/modules/base/command/user_group.py | 51 ++++++++++++------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/kdb-bot/src/bot/translation/de.json b/kdb-bot/src/bot/translation/de.json index e18c24b5..ea3b84f3 100644 --- a/kdb-bot/src/bot/translation/de.json +++ b/kdb-bot/src/bot/translation/de.json @@ -161,19 +161,19 @@ "max_char_count_exceeded": "Der Text darf nicht mehr als 128 Zeichen lang sein!" }, "user": { + "atr": { + "id": "Id", + "name": "Name", + "discord_join": "Discord beigetreten am", + "last_join": "Server beigetreten am", + "xp": "XP", + "ontime": "Ontime", + "roles": "Rollen", + "joins": "Beitritte", + "lefts": "Abgänge", + "warnings": "Verwarnungen" + }, "info": { - "fields": { - "id": "Id", - "name": "Name", - "discord_join": "Discord beigetreten am", - "last_join": "Server beigetreten am", - "xp": "XP", - "ontime": "Ontime", - "roles": "Rollen", - "joins": "Beitritte", - "lefts": "Abgänge", - "warnings": "Verwarnungen" - }, "footer": "" }, "get": { @@ -184,7 +184,9 @@ "xp": "{} hat nun {} xp", "error": { "value_type_not_numeric": "Der angegebende Wert ist keine Ganzzahl! :(", - "set_xp": "Es kam zu einem Fehler bei der Zuweisung der XP :(" + "type_error": "Der angegebene Wert konnte nicht als eine Ganzzahl interpretiert werden :(", + "database_error": "Beim Speichern des Wertes kam es zu einem Fehler :(", + "general_error": "Bei der Ausführung dieses Befehls kam es zu einen Fehler :(" } }, "error": { diff --git a/kdb-bot/src/modules/base/command/user_group.py b/kdb-bot/src/modules/base/command/user_group.py index 0c6692f6..64f78938 100644 --- a/kdb-bot/src/modules/base/command/user_group.py +++ b/kdb-bot/src/modules/base/command/user_group.py @@ -9,6 +9,7 @@ from cpl_translation import TranslatePipe from discord import app_commands from discord.ext import commands from discord.ext.commands import Context +from mysql.connector.errors import DatabaseError from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.message_service_abc import MessageServiceABC @@ -25,6 +26,10 @@ from modules.permission.abc.permission_service_abc import PermissionServiceABC class UserGroup(DiscordCommandABC): + class _AtrClass: + xp: str + ontime: str + def __init__( self, config: ConfigurationABC, @@ -61,6 +66,10 @@ class UserGroup(DiscordCommandABC): self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}') + self._atr_class = self._AtrClass + self._atr_class.xp = self._t.transform('modules.base.user.atr.xp') + self._atr_class.ontime = self._t.transform('modules.base.user.atr.ontime') + @commands.hybrid_group() @commands.guild_only() async def user(self, ctx: Context): @@ -93,25 +102,25 @@ class UserGroup(DiscordCommandABC): ontime = self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id).sum( lambda join: round((join.leaved_on - join.joined_on).total_seconds() / 3600, 2)) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.id'), value=member.id) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.name'), value=member.name) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.discord_join'), + embed.add_field(name=self._t.transform('modules.base.user.atr.id'), value=member.id) + embed.add_field(name=self._t.transform('modules.base.user.atr.name'), value=member.name) + embed.add_field(name=self._t.transform('modules.base.user.atr.discord_join'), value=self._date.transform(member.created_at), inline=False) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.last_join'), + embed.add_field(name=self._t.transform('modules.base.user.atr.last_join'), value=self._date.transform(member.joined_at), inline=False) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.xp'), value=str(user.xp)) - embed.add_field(name=self._t.transform('modules.base.user.info.fields.ontime'), value=str(ontime)) + embed.add_field(name=self._t.transform('modules.base.user.atr.xp'), value=str(user.xp)) + embed.add_field(name=self._t.transform('modules.base.user.atr.ontime'), value=str(ontime)) roles = '' for role in member.roles: roles += f'{role.name}\n' - embed.add_field(name=self._t.transform('modules.base.user.info.fields.roles'), value=roles, inline=False) + embed.add_field(name=self._t.transform('modules.base.user.atr.roles'), value=roles, inline=False) if is_mod or member == ctx.author: joins_string = '' for join in joins: joins_string += f'{self._date.transform(join.joined_on)}\n' - embed.add_field(name=self._t.transform('modules.base.user.info.fields.joins'), value=joins_string) + embed.add_field(name=self._t.transform('modules.base.user.atr.joins'), value=joins_string) if is_mod or member == ctx.author: lefts_string = '' @@ -122,10 +131,10 @@ class UserGroup(DiscordCommandABC): continue lefts_string += f'{self._date.transform(join.leaved_on)}\n' - embed.add_field(name=self._t.transform('modules.base.user.info.fields.lefts'), value=lefts_string) + embed.add_field(name=self._t.transform('modules.base.user.atr.lefts'), value=lefts_string) if is_mod or member == ctx.author: - embed.add_field(name=self._t.transform('modules.base.user.info.fields.warnings'), + embed.add_field(name=self._t.transform('modules.base.user.atr.warnings'), value=self._t.transform('common.not_implemented_yet'), inline=False) # send to interaction because of sensitive data @@ -150,10 +159,10 @@ class UserGroup(DiscordCommandABC): user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) match atr: - case 'xp': + case self._atr_class.xp: value = str(user.xp) - case 'ontime': + case self._atr_class.ontime: value = str(round( self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id) .sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600), @@ -171,7 +180,7 @@ class UserGroup(DiscordCommandABC): @get.autocomplete('atr') async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: - atr_list = ['xp', 'ontime'] + atr_list = [self._atr_class.xp, self._atr_class.ontime] return [app_commands.Choice(name=atr, value=atr) for atr in atr_list] @user.command() @@ -188,7 +197,7 @@ class UserGroup(DiscordCommandABC): user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) match atr: - case 'xp': + case self._atr_class.xp: if not value.isnumeric(): await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.value_type_not_numeric')) return @@ -198,9 +207,17 @@ class UserGroup(DiscordCommandABC): self._users.update_user(user) self._db.save_changes() await self._level.check_level(member) + except TypeError as te: + self._logger.error(__name__, f'String value couldn\'t be converted to int', te) + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.type_error')) + return + except DatabaseError as de: + self._logger.error(__name__, f'An error occurred while updating the user', de) + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.database_error')) + return except Exception as e: - self._logger.error(__name__, f'Value couldn\'t be converted to int', e) - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.set_xp')) + self._logger.error(__name__, f'An error occurred while setting xp', e) + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.general_error')) return case other: @@ -215,5 +232,5 @@ class UserGroup(DiscordCommandABC): @set.autocomplete('atr') async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: - atr_list = ['xp'] + atr_list = [self._atr_class.xp] return [app_commands.Choice(name=atr, value=atr) for atr in atr_list] From 40e53de3f2bf393c1efd72737b6853698aa75f44 Mon Sep 17 00:00:00 2001 From: Nick Jungmann Date: Thu, 22 Dec 2022 20:38:40 +0100 Subject: [PATCH 5/5] Removed error handling for database errors and replaced match-case-statements with if-else-statements #22 --- .../src/modules/base/command/user_group.py | 86 ++++++++----------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/kdb-bot/src/modules/base/command/user_group.py b/kdb-bot/src/modules/base/command/user_group.py index 64f78938..a919f3f7 100644 --- a/kdb-bot/src/modules/base/command/user_group.py +++ b/kdb-bot/src/modules/base/command/user_group.py @@ -26,10 +26,6 @@ from modules.permission.abc.permission_service_abc import PermissionServiceABC class UserGroup(DiscordCommandABC): - class _AtrClass: - xp: str - ontime: str - def __init__( self, config: ConfigurationABC, @@ -66,9 +62,10 @@ class UserGroup(DiscordCommandABC): self._logger.trace(__name__, f'Loaded command service: {type(self).__name__}') - self._atr_class = self._AtrClass - self._atr_class.xp = self._t.transform('modules.base.user.atr.xp') - self._atr_class.ontime = self._t.transform('modules.base.user.atr.ontime') + self._atr_dict = { + "xp": self._t.transform('modules.base.user.atr.xp'), + 'ontime': self._t.transform('modules.base.user.atr.ontime') + } @commands.hybrid_group() @commands.guild_only() @@ -158,20 +155,19 @@ class UserGroup(DiscordCommandABC): server = self._servers.find_server_by_discord_id(ctx.guild.id) user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) - match atr: - case self._atr_class.xp: - value = str(user.xp) - - case self._atr_class.ontime: - value = str(round( - self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id) - .sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600), - 2 - )) + if atr == self._atr_dict["xp"]: + value = str(user.xp) - case other: - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.atr_not_found').format(atr)) - return + elif atr == self._atr_dict["ontime"]: + value = str(round( + self._user_joined_voice_channel.get_user_joined_voice_channels_by_user_id(user.user_id) + .sum(lambda join: (join.leaved_on - join.joined_on).total_seconds() / 3600), + 2 + )) + + else: + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.error.atr_not_found').format(atr)) + return await self._message_service.send_interaction_msg( ctx.interaction, @@ -180,7 +176,7 @@ class UserGroup(DiscordCommandABC): @get.autocomplete('atr') async def get_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: - atr_list = [self._atr_class.xp, self._atr_class.ontime] + atr_list = [self._atr_dict["xp"], self._atr_dict["ontime"]] return [app_commands.Choice(name=atr, value=atr) for atr in atr_list] @user.command() @@ -196,35 +192,29 @@ class UserGroup(DiscordCommandABC): server = self._servers.find_server_by_discord_id(ctx.guild.id) user = self._users.find_user_by_discord_id_and_server_id(member.id, server.server_id) - match atr: - case self._atr_class.xp: - if not value.isnumeric(): - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.value_type_not_numeric')) - return - - try: - user.xp = int(value) - self._users.update_user(user) - self._db.save_changes() - await self._level.check_level(member) - except TypeError as te: - self._logger.error(__name__, f'String value couldn\'t be converted to int', te) - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.type_error')) - return - except DatabaseError as de: - self._logger.error(__name__, f'An error occurred while updating the user', de) - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.database_error')) - return - except Exception as e: - self._logger.error(__name__, f'An error occurred while setting xp', e) - await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform('modules.base.user.set.error.general_error')) - return - - case other: + if atr == self._atr_dict["xp"]: + if not value.isnumeric(): await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( - 'modules.base.user.error.atr_not_found').format(atr)) + 'modules.base.user.set.error.value_type_not_numeric')) return + try: + user.xp = int(value) + except TypeError as te: + self._logger.error(__name__, f'String value couldn\'t be converted to int', te) + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( + 'modules.base.user.set.error.type_error')) + return + else: + self._users.update_user(user) + self._db.save_changes() + await self._level.check_level(member) + + else: + await self._message_service.send_interaction_msg(ctx.interaction, self._t.transform( + 'modules.base.user.error.atr_not_found').format(atr)) + return + await self._message_service.send_interaction_msg( ctx.interaction, self._t.transform(f'modules.base.user.set.{atr}').format(member.mention, value) @@ -232,5 +222,5 @@ class UserGroup(DiscordCommandABC): @set.autocomplete('atr') async def set_autocomplete(self, interaction: discord.Interaction, current: str) -> List[app_commands.Choice[str]]: - atr_list = [self._atr_class.xp] + atr_list = [self._atr_dict["xp"]] return [app_commands.Choice(name=atr, value=atr) for atr in atr_list]