diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d4cefa254..4444d79d1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -192,6 +192,8 @@ These changes are available on the `master` branch, but have not yet been releas recognize them. ([#2256](https://github.com/Pycord-Development/pycord/pull/2256)) - Fixed offset-aware tasks causing `TypeError` when being prepared. ([#2271](https://github.com/Pycord-Development/pycord/pull/2271)) +- Fixed `AttributeError` when serializing commands with `Annotated` type hints. + ([#2243](https://github.com/Pycord-Development/pycord/pull/2243)) ## [2.4.1] - 2023-03-20 diff --git a/discord/commands/core.py b/discord/commands/core.py index d53bac0d71..c7bd4efd40 100644 --- a/discord/commands/core.py +++ b/discord/commands/core.py @@ -746,10 +746,12 @@ def _parse_options(self, params, *, check_params: bool = True) -> list[Option]: option = next(option_gen, Option()) # Handle Optional if self._is_typing_optional(type_hint): - option.input_type = get_args(type_hint)[0] + option.input_type = SlashCommandOptionType.from_datatype( + get_args(type_hint)[0] + ) option.default = None else: - option.input_type = type_hint + option.input_type = SlashCommandOptionType.from_datatype(type_hint) if self._is_typing_union(option): if self._is_typing_optional(option): diff --git a/tests/test_typing_annotated.py b/tests/test_typing_annotated.py index 582bd4f8a0..7091a241ff 100644 --- a/tests/test_typing_annotated.py +++ b/tests/test_typing_annotated.py @@ -1,10 +1,9 @@ from typing import Optional -import pytest from typing_extensions import Annotated import discord -from discord import ApplicationContext +from discord import SlashCommandOptionType from discord.commands.core import SlashCommand, slash_command @@ -15,6 +14,10 @@ async def echo(ctx, txt: Annotated[str, discord.Option()]): cmd = SlashCommand(echo) bot = discord.Bot() bot.add_application_command(cmd) + dict_result = cmd.to_dict() + assert ( + dict_result.get("options")[0].get("type") == SlashCommandOptionType.string.value + ) def test_typing_annotated_decorator(): @@ -24,6 +27,12 @@ def test_typing_annotated_decorator(): async def echo(ctx, txt: Annotated[str, discord.Option(description="Some text")]): await ctx.respond(txt) + dict_result = echo.to_dict() + + option = dict_result.get("options")[0] + assert option.get("type") == SlashCommandOptionType.string.value + assert option.get("description") == "Some text" + def test_typing_annotated_cog(): class echoCog(discord.Cog): @@ -38,7 +47,14 @@ async def echo( await ctx.respond(txt) bot = discord.Bot() - bot.add_cog(echoCog(bot)) + cog = echoCog(bot) + bot.add_cog(cog) + + dict_result = cog.echo.to_dict() + + option = dict_result.get("options")[0] + assert option.get("type") == SlashCommandOptionType.string.value + assert option.get("description") == "Some text" def test_typing_annotated_cog_slashgroup(): @@ -56,7 +72,14 @@ async def echo( await ctx.respond(txt) bot = discord.Bot() - bot.add_cog(echoCog(bot)) + cog = echoCog(bot) + bot.add_cog(cog) + + dict_result = cog.echo.to_dict() + + option = dict_result.get("options")[0] + assert option.get("type") == SlashCommandOptionType.string.value + assert option.get("description") == "Some text" def test_typing_annotated_optional(): @@ -67,6 +90,11 @@ async def echo(ctx, txt: Annotated[Optional[str], discord.Option()]): bot = discord.Bot() bot.add_application_command(cmd) + dict_result = cmd.to_dict() + + option = dict_result.get("options")[0] + assert option.get("type") == SlashCommandOptionType.string.value + def test_no_annotation(): async def echo(ctx, txt: str): @@ -76,6 +104,11 @@ async def echo(ctx, txt: str): bot = discord.Bot() bot.add_application_command(cmd) + dict_result = cmd.to_dict() + + option = dict_result.get("options")[0] + assert option.get("type") == SlashCommandOptionType.string.value + def test_annotated_no_option(): async def echo(ctx, txt: Annotated[str, "..."]): @@ -84,3 +117,8 @@ async def echo(ctx, txt: Annotated[str, "..."]): cmd = SlashCommand(echo) bot = discord.Bot() bot.add_application_command(cmd) + + dict_result = cmd.to_dict() + + option = dict_result.get("options")[0] + assert option.get("type") == SlashCommandOptionType.string.value