Application commands
attrs
class
LocalisedName (LocalisedField)
¶
A localisation object for names.
Attr attributes:
Name | Type | Description |
---|
Source code in naff/models/naff/application_commands.py
@define(field_transformer=attrs_validator(name_validator, skip_fields=["default_locale"]))
class LocalisedName(LocalisedField):
"""A localisation object for names."""
def __repr__(self) -> str:
return super().__repr__()
inherited
property
readonly
default: str
¶
The default value based on the CONST default_locale
inherited
method
get_locale(self, locale)
¶
Get the value for the specified locale. Supports locale-codes and locale names.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
locale |
str |
The locale to fetch |
required |
Returns:
Type | Description |
---|---|
str |
The localised string, or the default value |
Source code in naff/models/naff/application_commands.py
def get_locale(self, locale: str) -> str:
"""
Get the value for the specified locale. Supports locale-codes and locale names.
Args:
locale: The locale to fetch
Returns:
The localised string, or the default value
"""
if val := getattr(self, locale, None):
# Attempt to retrieve an attribute with the specified locale
return val
if attr := self._code_mapping.get(locale):
# assume the locale is a code, and attempt to find an attribute with that code
if val := getattr(self, attr, None):
# if the value isn't None, return
return val
# no value was found, return default
return self.default
attrs
class
LocalizedName (LocalisedField)
¶
A localisation object for names.
Attr attributes:
Name | Type | Description |
---|
Source code in naff/models/naff/application_commands.py
@define(field_transformer=attrs_validator(name_validator, skip_fields=["default_locale"]))
class LocalisedName(LocalisedField):
"""A localisation object for names."""
def __repr__(self) -> str:
return super().__repr__()
inherited
property
readonly
default: str
¶
The default value based on the CONST default_locale
inherited
method
get_locale(self, locale)
¶
Get the value for the specified locale. Supports locale-codes and locale names.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
locale |
str |
The locale to fetch |
required |
Returns:
Type | Description |
---|---|
str |
The localised string, or the default value |
Source code in naff/models/naff/application_commands.py
def get_locale(self, locale: str) -> str:
"""
Get the value for the specified locale. Supports locale-codes and locale names.
Args:
locale: The locale to fetch
Returns:
The localised string, or the default value
"""
if val := getattr(self, locale, None):
# Attempt to retrieve an attribute with the specified locale
return val
if attr := self._code_mapping.get(locale):
# assume the locale is a code, and attempt to find an attribute with that code
if val := getattr(self, attr, None):
# if the value isn't None, return
return val
# no value was found, return default
return self.default
attrs
class
LocalisedDesc (LocalisedField)
¶
A localisation object for descriptions.
Attr attributes:
Name | Type | Description |
---|
Source code in naff/models/naff/application_commands.py
@define(field_transformer=attrs_validator(desc_validator, skip_fields=["default_locale"]))
class LocalisedDesc(LocalisedField):
"""A localisation object for descriptions."""
def __repr__(self) -> str:
return super().__repr__()
inherited
property
readonly
default: str
¶
The default value based on the CONST default_locale
inherited
method
get_locale(self, locale)
¶
Get the value for the specified locale. Supports locale-codes and locale names.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
locale |
str |
The locale to fetch |
required |
Returns:
Type | Description |
---|---|
str |
The localised string, or the default value |
Source code in naff/models/naff/application_commands.py
def get_locale(self, locale: str) -> str:
"""
Get the value for the specified locale. Supports locale-codes and locale names.
Args:
locale: The locale to fetch
Returns:
The localised string, or the default value
"""
if val := getattr(self, locale, None):
# Attempt to retrieve an attribute with the specified locale
return val
if attr := self._code_mapping.get(locale):
# assume the locale is a code, and attempt to find an attribute with that code
if val := getattr(self, attr, None):
# if the value isn't None, return
return val
# no value was found, return default
return self.default
attrs
class
LocalizedDesc (LocalisedField)
¶
A localisation object for descriptions.
Attr attributes:
Name | Type | Description |
---|
Source code in naff/models/naff/application_commands.py
@define(field_transformer=attrs_validator(desc_validator, skip_fields=["default_locale"]))
class LocalisedDesc(LocalisedField):
"""A localisation object for descriptions."""
def __repr__(self) -> str:
return super().__repr__()
inherited
property
readonly
default: str
¶
The default value based on the CONST default_locale
inherited
method
get_locale(self, locale)
¶
Get the value for the specified locale. Supports locale-codes and locale names.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
locale |
str |
The locale to fetch |
required |
Returns:
Type | Description |
---|---|
str |
The localised string, or the default value |
Source code in naff/models/naff/application_commands.py
def get_locale(self, locale: str) -> str:
"""
Get the value for the specified locale. Supports locale-codes and locale names.
Args:
locale: The locale to fetch
Returns:
The localised string, or the default value
"""
if val := getattr(self, locale, None):
# Attempt to retrieve an attribute with the specified locale
return val
if attr := self._code_mapping.get(locale):
# assume the locale is a code, and attempt to find an attribute with that code
if val := getattr(self, attr, None):
# if the value isn't None, return
return val
# no value was found, return default
return self.default
class
OptionTypes (IntEnum)
¶
Option types supported by slash commands.
Source code in naff/models/naff/application_commands.py
class OptionTypes(IntEnum):
"""Option types supported by slash commands."""
SUB_COMMAND = 1
SUB_COMMAND_GROUP = 2
STRING = 3
INTEGER = 4
BOOLEAN = 5
USER = 6
CHANNEL = 7
ROLE = 8
MENTIONABLE = 9
NUMBER = 10
ATTACHMENT = 11
@classmethod
def from_type(cls, t: type) -> "OptionTypes":
"""
Convert data types to their corresponding OptionType.
Args:
t: The datatype to convert
Returns:
OptionType or None
"""
if issubclass(t, str):
return cls.STRING
if issubclass(t, int):
return cls.INTEGER
if issubclass(t, bool):
return cls.BOOLEAN
if issubclass(t, BaseUser):
return cls.USER
if issubclass(t, channel.BaseChannel):
return cls.CHANNEL
if issubclass(t, Role):
return cls.ROLE
if issubclass(t, float):
return cls.NUMBER
class
CallbackTypes (IntEnum)
¶
Types of callback supported by interaction response.
Source code in naff/models/naff/application_commands.py
class CallbackTypes(IntEnum):
"""Types of callback supported by interaction response."""
PONG = 1
CHANNEL_MESSAGE_WITH_SOURCE = 4
DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE = 5
DEFERRED_UPDATE_MESSAGE = 6
UPDATE_MESSAGE = 7
AUTOCOMPLETE_RESULT = 8
MODAL = 9
attrs
class
InteractionCommand (BaseCommand)
¶
Represents a discord abstract interaction command.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scope |
Denotes whether its global or for specific guild. |
required | |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command. |
None |
dm_permission |
bool |
Should this command be available in DMs. |
True |
cmd_id |
Dict[str, Snowflake_Type] |
The id of this command given by discord. |
NOTHING |
callback |
Callable[..., Coroutine] |
The coroutine to callback when this interaction is received. |
None |
Attr attributes:
Name | Type | Description |
---|---|---|
extension |
Any |
The extension this command belongs to |
enabled |
bool |
Whether this can be run at all |
checks |
list |
Any checks that must be checked before the command can run |
cooldown |
Cooldown |
An optional cooldown to apply to the command |
max_concurrency |
MaxConcurrency |
An optional maximum number of concurrent instances to apply to the command |
error_callback |
Callable[..., Coroutine] |
The coroutine to be called when an error occurs |
pre_run_callback |
Callable[..., Coroutine] |
The coroutine to be called before the command is executed, but after the checks |
post_run_callback |
Callable[..., Coroutine] |
The coroutine to be called after the command has executed |
name |
LocalisedName |
1-32 character name |
scopes |
List[Snowflake_Type] |
The scopes of this interaction. Global or guild ids |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command |
dm_permission |
bool |
Whether this command is enabled in DMs |
cmd_id |
Dict[str, Snowflake_Type] |
The unique IDs of this commands |
callback |
Callable[..., Coroutine] |
The coroutine to call when this interaction is received |
auto_defer |
AutoDefer |
A system to automatically defer this command after a set duration |
nsfw |
bool |
This command should only work in NSFW channels |
Source code in naff/models/naff/application_commands.py
@define()
class InteractionCommand(BaseCommand):
"""
Represents a discord abstract interaction command.
Args:
scope: Denotes whether its global or for specific guild.
default_member_permissions: What permissions members need to have by default to use this command.
dm_permission: Should this command be available in DMs.
cmd_id: The id of this command given by discord.
callback: The coroutine to callback when this interaction is received.
"""
name: LocalisedName = field(
metadata=docs("1-32 character name") | no_export_meta, converter=LocalisedName.converter
)
scopes: List["Snowflake_Type"] = field(
default=[GLOBAL_SCOPE],
converter=to_snowflake_list,
metadata=docs("The scopes of this interaction. Global or guild ids") | no_export_meta,
)
default_member_permissions: Optional["Permissions"] = field(
default=None, metadata=docs("What permissions members need to have by default to use this command")
)
dm_permission: bool = field(default=True, metadata=docs("Whether this command is enabled in DMs"))
cmd_id: Dict[str, "Snowflake_Type"] = field(
factory=dict, metadata=docs("The unique IDs of this commands") | no_export_meta
) # scope: cmd_id
callback: Callable[..., Coroutine] = field(
default=None, metadata=docs("The coroutine to call when this interaction is received") | no_export_meta
)
auto_defer: "AutoDefer" = field(
default=MISSING,
metadata=docs("A system to automatically defer this command after a set duration") | no_export_meta,
)
nsfw: bool = field(default=False, metadata=docs("This command should only work in NSFW channels"))
_application_id: "Snowflake_Type" = field(default=None, converter=optional(to_snowflake))
def __attrs_post_init__(self) -> None:
if self.callback is not None:
if hasattr(self.callback, "auto_defer"):
self.auto_defer = self.callback.auto_defer
super().__attrs_post_init__()
def to_dict(self) -> dict:
data = super().to_dict()
if self.default_member_permissions is not None:
data["default_member_permissions"] = str(int(self.default_member_permissions))
else:
data["default_member_permissions"] = None
return data
def mention(self, scope: Optional["Snowflake_Type"] = None) -> str:
"""
Returns a string that would mention the interaction.
Args:
scope: If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified.
Returns:
The markdown mention.
"""
if scope:
cmd_id = self.get_cmd_id(scope=scope)
else:
cmd_id = list(self.cmd_id.values())[0]
return f"</{self.resolved_name}:{cmd_id}>"
@property
def resolved_name(self) -> str:
"""A representation of this interaction's name."""
return str(self.name)
def get_localised_name(self, locale: str) -> str:
return self.name.get_locale(locale)
def get_cmd_id(self, scope: "Snowflake_Type") -> "Snowflake_Type":
return self.cmd_id.get(scope, self.cmd_id.get(GLOBAL_SCOPE, None))
@property
def is_subcommand(self) -> bool:
return False
async def _permission_enforcer(self, ctx: "Context") -> bool:
"""A check that enforces Discord permissions."""
# I wish this wasn't needed, but unfortunately Discord permissions cant be trusted to actually prevent usage
if self.dm_permission is False:
return ctx.guild is not None
return True
async
inherited
method
call_with_binding(self, callback, *args, **kwargs)
¶
Call a given method using this objects _binding.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback |
Callable[..., Coroutine[Any, Any, Any]] |
The callback to call. |
required |
Source code in naff/models/naff/application_commands.py
async def call_with_binding(self, callback: Callable[..., Coroutine[Any, Any, Any]], *args, **kwargs) -> Any:
"""
Call a given method using this objects _binding.
Args:
callback: The callback to call.
"""
if self._binding:
return await callback(self._binding, *args, **kwargs)
return await callback(*args, **kwargs)
inherited
method
update_from_dict(self, data)
¶
Updates object attribute(s) with new json data received from discord api.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Dict[str, Any] |
The json data received from discord api. |
required |
Returns:
Type | Description |
---|---|
~T |
The updated object class instance. |
Source code in naff/models/naff/application_commands.py
def update_from_dict(self: Type[const.T], data: Dict[str, Any]) -> const.T:
"""
Updates object attribute(s) with new json data received from discord api.
Args:
data: The json data received from discord api.
Returns:
The updated object class instance.
"""
data = self._process_dict(data)
for key, value in self._filter_kwargs(data, self._get_keys()).items():
# todo improve
setattr(self, key, value)
return self
method
to_dict(self)
¶
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
Type | Description |
---|---|
dict |
The exported dictionary. |
Source code in naff/models/naff/application_commands.py
def to_dict(self) -> dict:
data = super().to_dict()
if self.default_member_permissions is not None:
data["default_member_permissions"] = str(int(self.default_member_permissions))
else:
data["default_member_permissions"] = None
return data
method
mention(self, scope)
¶
Returns a string that would mention the interaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scope |
Optional[Snowflake_Type] |
If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified. |
None |
Returns:
Type | Description |
---|---|
str |
The markdown mention. |
Source code in naff/models/naff/application_commands.py
def mention(self, scope: Optional["Snowflake_Type"] = None) -> str:
"""
Returns a string that would mention the interaction.
Args:
scope: If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified.
Returns:
The markdown mention.
"""
if scope:
cmd_id = self.get_cmd_id(scope=scope)
else:
cmd_id = list(self.cmd_id.values())[0]
return f"</{self.resolved_name}:{cmd_id}>"
property
readonly
resolved_name: str
¶
A representation of this interaction's name.
inherited
method
error(self, call)
¶
A decorator to declare a coroutine as one that will be run upon an error.
Source code in naff/models/naff/application_commands.py
def error(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run upon an error."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("Error handler must be coroutine")
self.error_callback = call
return call
inherited
method
pre_run(self, call)
¶
A decorator to declare a coroutine as one that will be run before the command.
Source code in naff/models/naff/application_commands.py
def pre_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run before the command."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("pre_run must be coroutine")
self.pre_run_callback = call
return call
inherited
method
post_run(self, call)
¶
A decorator to declare a coroutine as one that will be run after the command has.
Source code in naff/models/naff/application_commands.py
def post_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run after the command has."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("post_run must be coroutine")
self.post_run_callback = call
return call
attrs
class
ContextMenu (InteractionCommand)
¶
Represents a discord context menu.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str | None |
The name of this entry. |
required |
type |
CommandTypes |
The type of entry (user or message). |
required |
Attr attributes:
Name | Type | Description |
---|---|---|
extension |
Any |
The extension this command belongs to |
enabled |
bool |
Whether this can be run at all |
checks |
list |
Any checks that must be checked before the command can run |
cooldown |
Cooldown |
An optional cooldown to apply to the command |
max_concurrency |
MaxConcurrency |
An optional maximum number of concurrent instances to apply to the command |
error_callback |
Callable[..., Coroutine] |
The coroutine to be called when an error occurs |
pre_run_callback |
Callable[..., Coroutine] |
The coroutine to be called before the command is executed, but after the checks |
post_run_callback |
Callable[..., Coroutine] |
The coroutine to be called after the command has executed |
scopes |
List[Snowflake_Type] |
The scopes of this interaction. Global or guild ids |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command |
dm_permission |
bool |
Whether this command is enabled in DMs |
cmd_id |
Dict[str, Snowflake_Type] |
The unique IDs of this commands |
callback |
Callable[..., Coroutine] |
The coroutine to call when this interaction is received |
auto_defer |
AutoDefer |
A system to automatically defer this command after a set duration |
nsfw |
bool |
This command should only work in NSFW channels |
name |
LocalisedField |
1-32 character name |
type |
CommandTypes |
The type of command, defaults to 1 if not specified |
Source code in naff/models/naff/application_commands.py
@define()
class ContextMenu(InteractionCommand):
"""
Represents a discord context menu.
Args:
name: The name of this entry.
type: The type of entry (user or message).
"""
name: LocalisedField = field(metadata=docs("1-32 character name"), converter=LocalisedField.converter)
type: CommandTypes = field(metadata=docs("The type of command, defaults to 1 if not specified"))
@type.validator
def _type_validator(self, attribute: str, value: int) -> None:
if not isinstance(value, CommandTypes):
if value not in CommandTypes.__members__.values():
raise ValueError("Context Menu type not recognised, please consult the docs.")
elif value == CommandTypes.CHAT_INPUT:
raise ValueError(
"The CHAT_INPUT type is basically slash commands. Please use the @slash_command() " "decorator instead."
)
def to_dict(self) -> dict:
data = super().to_dict()
data["name"] = str(self.name)
return data
async
inherited
method
call_with_binding(self, callback, *args, **kwargs)
¶
Call a given method using this objects _binding.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback |
Callable[..., Coroutine[Any, Any, Any]] |
The callback to call. |
required |
Source code in naff/models/naff/application_commands.py
async def call_with_binding(self, callback: Callable[..., Coroutine[Any, Any, Any]], *args, **kwargs) -> Any:
"""
Call a given method using this objects _binding.
Args:
callback: The callback to call.
"""
if self._binding:
return await callback(self._binding, *args, **kwargs)
return await callback(*args, **kwargs)
inherited
method
update_from_dict(self, data)
¶
Updates object attribute(s) with new json data received from discord api.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Dict[str, Any] |
The json data received from discord api. |
required |
Returns:
Type | Description |
---|---|
~T |
The updated object class instance. |
Source code in naff/models/naff/application_commands.py
def update_from_dict(self: Type[const.T], data: Dict[str, Any]) -> const.T:
"""
Updates object attribute(s) with new json data received from discord api.
Args:
data: The json data received from discord api.
Returns:
The updated object class instance.
"""
data = self._process_dict(data)
for key, value in self._filter_kwargs(data, self._get_keys()).items():
# todo improve
setattr(self, key, value)
return self
inherited
method
mention(self, scope)
¶
Returns a string that would mention the interaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scope |
Optional[Snowflake_Type] |
If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified. |
None |
Returns:
Type | Description |
---|---|
str |
The markdown mention. |
Source code in naff/models/naff/application_commands.py
def mention(self, scope: Optional["Snowflake_Type"] = None) -> str:
"""
Returns a string that would mention the interaction.
Args:
scope: If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified.
Returns:
The markdown mention.
"""
if scope:
cmd_id = self.get_cmd_id(scope=scope)
else:
cmd_id = list(self.cmd_id.values())[0]
return f"</{self.resolved_name}:{cmd_id}>"
inherited
property
readonly
resolved_name: str
¶
A representation of this interaction's name.
method
to_dict(self)
¶
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
Type | Description |
---|---|
dict |
The exported dictionary. |
Source code in naff/models/naff/application_commands.py
def to_dict(self) -> dict:
data = super().to_dict()
data["name"] = str(self.name)
return data
inherited
method
error(self, call)
¶
A decorator to declare a coroutine as one that will be run upon an error.
Source code in naff/models/naff/application_commands.py
def error(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run upon an error."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("Error handler must be coroutine")
self.error_callback = call
return call
inherited
method
pre_run(self, call)
¶
A decorator to declare a coroutine as one that will be run before the command.
Source code in naff/models/naff/application_commands.py
def pre_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run before the command."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("pre_run must be coroutine")
self.pre_run_callback = call
return call
inherited
method
post_run(self, call)
¶
A decorator to declare a coroutine as one that will be run after the command has.
Source code in naff/models/naff/application_commands.py
def post_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run after the command has."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("post_run must be coroutine")
self.post_run_callback = call
return call
attrs
class
SlashCommandChoice (DictSerializationMixin)
¶
Represents a discord slash command choice.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str | None |
The name the user will see |
required |
value |
Union[str, int, float] |
The data sent to your code when this choice is used |
required |
Attr attributes:
Name | Type | Description |
---|
Source code in naff/models/naff/application_commands.py
@define(kw_only=False)
class SlashCommandChoice(DictSerializationMixin):
"""
Represents a discord slash command choice.
Args:
name: The name the user will see
value: The data sent to your code when this choice is used
"""
name: LocalisedField = field(converter=LocalisedField.converter)
value: Union[str, int, float] = field()
def as_dict(self) -> dict:
return {"name": str(self.name), "value": self.value, "name_localizations": self.name.to_locale_dict()}
inherited
method
update_from_dict(self, data)
¶
Updates object attribute(s) with new json data received from discord api.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Dict[str, Any] |
The json data received from discord api. |
required |
Returns:
Type | Description |
---|---|
~T |
The updated object class instance. |
Source code in naff/models/naff/application_commands.py
def update_from_dict(self: Type[const.T], data: Dict[str, Any]) -> const.T:
"""
Updates object attribute(s) with new json data received from discord api.
Args:
data: The json data received from discord api.
Returns:
The updated object class instance.
"""
data = self._process_dict(data)
for key, value in self._filter_kwargs(data, self._get_keys()).items():
# todo improve
setattr(self, key, value)
return self
inherited
method
to_dict(self)
¶
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
Type | Description |
---|---|
Dict[str, Any] |
The exported dictionary. |
Source code in naff/models/naff/application_commands.py
def to_dict(self) -> Dict[str, Any]:
"""
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
The exported dictionary.
"""
self._check_object()
return serializer.to_dict(self)
attrs
class
SlashCommandOption (DictSerializationMixin)
¶
Represents a discord slash command option.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str | None |
The name of this option |
required |
type |
Union[naff.models.naff.application_commands.OptionTypes, int] |
The type of option |
required |
description |
str | None |
The description of this option |
'No Description Set' |
required |
bool |
"This option must be filled to use the command" |
True |
choices |
List[Union[naff.models.naff.application_commands.SlashCommandChoice, Dict]] |
A list of choices the user has to pick between |
NOTHING |
channel_types |
Optional[list[Union[naff.models.discord.enums.ChannelTypes, int]]] |
The channel types permitted. The option needs to be a channel |
None |
min_value |
Optional[float] |
The minimum value permitted. The option needs to be an integer or float |
None |
max_value |
Optional[float] |
The maximum value permitted. The option needs to be an integer or float |
None |
min_length |
Optional[int] |
The minimum length of text a user can input. The option needs to be a string |
None |
max_length |
Optional[int] |
The maximum length of text a user can input. The option needs to be a string |
None |
Attr attributes:
Name | Type | Description |
---|
Source code in naff/models/naff/application_commands.py
@define(kw_only=False)
class SlashCommandOption(DictSerializationMixin):
"""
Represents a discord slash command option.
Args:
name: The name of this option
type: The type of option
description: The description of this option
required: "This option must be filled to use the command"
choices: A list of choices the user has to pick between
channel_types: The channel types permitted. The option needs to be a channel
min_value: The minimum value permitted. The option needs to be an integer or float
max_value: The maximum value permitted. The option needs to be an integer or float
min_length: The minimum length of text a user can input. The option needs to be a string
max_length: The maximum length of text a user can input. The option needs to be a string
"""
name: LocalisedName = field(converter=LocalisedName.converter)
type: Union[OptionTypes, int] = field()
description: LocalisedDesc = field(default="No Description Set", converter=LocalisedDesc.converter)
required: bool = field(default=True)
autocomplete: bool = field(default=False)
choices: List[Union[SlashCommandChoice, Dict]] = field(factory=list)
channel_types: Optional[list[Union[ChannelTypes, int]]] = field(default=None)
min_value: Optional[float] = field(default=None)
max_value: Optional[float] = field(default=None)
min_length: Optional[int] = field(default=None)
max_length: Optional[int] = field(default=None)
@type.validator
def _type_validator(self, attribute: str, value: int) -> None:
if value == OptionTypes.SUB_COMMAND or value == OptionTypes.SUB_COMMAND_GROUP:
raise ValueError(
"Options cannot be SUB_COMMAND or SUB_COMMAND_GROUP. If you want to use subcommands, "
"see the @sub_command() decorator."
)
@channel_types.validator
def _channel_types_validator(self, attribute: str, value: Optional[list[OptionTypes]]) -> None:
if value is not None:
if self.type != OptionTypes.CHANNEL:
raise ValueError("The option needs to be CHANNEL to use this")
allowed_int = [channel_type.value for channel_type in ChannelTypes]
for item in value:
if (item not in allowed_int) and (item not in ChannelTypes):
raise ValueError(f"{value} is not allowed here")
@min_value.validator
def _min_value_validator(self, attribute: str, value: Optional[float]) -> None:
if value is not None:
if self.type != OptionTypes.INTEGER and self.type != OptionTypes.NUMBER:
raise ValueError("`min_value` can only be supplied with int or float options")
if self.type == OptionTypes.INTEGER:
if isinstance(value, float):
raise ValueError("`min_value` needs to be an int in an int option")
if self.max_value is not None and self.min_value is not None:
if self.max_value < self.min_value:
raise ValueError("`min_value` needs to be <= than `max_value`")
@max_value.validator
def _max_value_validator(self, attribute: str, value: Optional[float]) -> None:
if value is not None:
if self.type != OptionTypes.INTEGER and self.type != OptionTypes.NUMBER:
raise ValueError("`max_value` can only be supplied with int or float options")
if self.type == OptionTypes.INTEGER:
if isinstance(value, float):
raise ValueError("`max_value` needs to be an int in an int option")
if self.max_value and self.min_value:
if self.max_value < self.min_value:
raise ValueError("`min_value` needs to be <= than `max_value`")
@min_length.validator
def _min_length_validator(self, attribute: str, value: Optional[int]) -> None:
if value is not None:
if self.type != OptionTypes.STRING:
raise ValueError("`min_length` can only be supplied with string options")
if self.max_length is not None and self.min_length is not None:
if self.max_length < self.min_length:
raise ValueError("`min_length` needs to be <= than `max_length`")
if self.min_length < 0:
raise ValueError("`min_length` needs to be >= 0")
@max_length.validator
def _max_length_validator(self, attribute: str, value: Optional[int]) -> None:
if value is not None:
if self.type != OptionTypes.STRING:
raise ValueError("`max_length` can only be supplied with string options")
if self.min_length is not None and self.max_length is not None:
if self.max_length < self.min_length:
raise ValueError("`min_length` needs to be <= than `max_length`")
if self.max_length < 1:
raise ValueError("`max_length` needs to be >= 1")
def as_dict(self) -> dict:
data = attrs.asdict(self)
data["name"] = str(self.name)
data["description"] = str(self.description)
data["choices"] = [
choice.as_dict() if isinstance(choice, SlashCommandChoice) else choice for choice in self.choices
]
data["name_localizations"] = self.name.to_locale_dict()
data["description_localizations"] = self.description.to_locale_dict()
return data
inherited
method
update_from_dict(self, data)
¶
Updates object attribute(s) with new json data received from discord api.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Dict[str, Any] |
The json data received from discord api. |
required |
Returns:
Type | Description |
---|---|
~T |
The updated object class instance. |
Source code in naff/models/naff/application_commands.py
def update_from_dict(self: Type[const.T], data: Dict[str, Any]) -> const.T:
"""
Updates object attribute(s) with new json data received from discord api.
Args:
data: The json data received from discord api.
Returns:
The updated object class instance.
"""
data = self._process_dict(data)
for key, value in self._filter_kwargs(data, self._get_keys()).items():
# todo improve
setattr(self, key, value)
return self
inherited
method
to_dict(self)
¶
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
Type | Description |
---|---|
Dict[str, Any] |
The exported dictionary. |
Source code in naff/models/naff/application_commands.py
def to_dict(self) -> Dict[str, Any]:
"""
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
The exported dictionary.
"""
self._check_object()
return serializer.to_dict(self)
attrs
class
SlashCommand (InteractionCommand)
¶
Attr attributes:
Name | Type | Description |
---|---|---|
extension |
Any |
The extension this command belongs to |
enabled |
bool |
Whether this can be run at all |
checks |
list |
Any checks that must be checked before the command can run |
cooldown |
Cooldown |
An optional cooldown to apply to the command |
max_concurrency |
MaxConcurrency |
An optional maximum number of concurrent instances to apply to the command |
error_callback |
Callable[..., Coroutine] |
The coroutine to be called when an error occurs |
pre_run_callback |
Callable[..., Coroutine] |
The coroutine to be called before the command is executed, but after the checks |
post_run_callback |
Callable[..., Coroutine] |
The coroutine to be called after the command has executed |
scopes |
List[Snowflake_Type] |
The scopes of this interaction. Global or guild ids |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command |
dm_permission |
bool |
Whether this command is enabled in DMs |
cmd_id |
Dict[str, Snowflake_Type] |
The unique IDs of this commands |
callback |
Callable[..., Coroutine] |
The coroutine to call when this interaction is received |
auto_defer |
AutoDefer |
A system to automatically defer this command after a set duration |
nsfw |
bool |
This command should only work in NSFW channels |
Source code in naff/models/naff/application_commands.py
@define()
class SlashCommand(InteractionCommand):
name: LocalisedName = field(converter=LocalisedName.converter)
description: LocalisedDesc = field(default="No Description Set", converter=LocalisedDesc.converter)
group_name: LocalisedName = field(default=None, metadata=no_export_meta, converter=LocalisedName.converter)
group_description: LocalisedDesc = field(
default="No Description Set", metadata=no_export_meta, converter=LocalisedDesc.converter
)
sub_cmd_name: LocalisedName = field(default=None, metadata=no_export_meta, converter=LocalisedName.converter)
sub_cmd_description: LocalisedDesc = field(
default="No Description Set", metadata=no_export_meta, converter=LocalisedDesc.converter
)
options: List[Union[SlashCommandOption, Dict]] = field(factory=list)
autocomplete_callbacks: dict = field(factory=dict, metadata=no_export_meta)
@property
def resolved_name(self) -> str:
return (
f"{self.name}"
f"{f' {self.group_name}' if bool(self.group_name) else ''}"
f"{f' {self.sub_cmd_name}' if bool(self.sub_cmd_name) else ''}"
)
def get_localised_name(self, locale: str) -> str:
return (
f"{self.name.get_locale(locale)}"
f"{f' {self.group_name.get_locale(locale)}' if bool(self.group_name) else ''}"
f"{f' {self.sub_cmd_name.get_locale(locale)}' if bool(self.sub_cmd_name) else ''}"
)
@property
def is_subcommand(self) -> bool:
return bool(self.sub_cmd_name)
def __attrs_post_init__(self) -> None:
if self.callback is not None:
params = get_parameters(self.callback)
for name, val in params.items():
annotation = None
if val.annotation and isinstance(val.annotation, SlashCommandOption):
annotation = val.annotation
elif typing.get_origin(val.annotation) is Annotated:
for ann in typing.get_args(val.annotation):
if isinstance(ann, SlashCommandOption):
annotation = ann
if annotation:
if not self.options:
self.options = []
annotation.name = name
self.options.append(annotation)
if hasattr(self.callback, "options"):
if not self.options:
self.options = []
self.options += self.callback.options
super().__attrs_post_init__()
def to_dict(self) -> dict:
data = super().to_dict()
if self.is_subcommand:
data["name"] = str(self.sub_cmd_name)
data["description"] = str(self.sub_cmd_description)
data["name_localizations"] = self.sub_cmd_name.to_locale_dict()
data["description_localizations"] = self.sub_cmd_description.to_locale_dict()
data.pop("default_member_permissions", None)
data.pop("dm_permission", None)
data.pop("nsfw", None)
else:
data["name_localizations"] = self.name.to_locale_dict()
data["description_localizations"] = self.description.to_locale_dict()
return data
@options.validator
def options_validator(self, attribute: str, value: List) -> None:
if value:
if isinstance(value, list):
if len(value) > SLASH_CMD_MAX_OPTIONS:
raise ValueError(f"Slash commands can only hold {SLASH_CMD_MAX_OPTIONS} options")
if value != sorted(
value,
key=lambda x: x.required if isinstance(x, SlashCommandOption) else x["required"],
reverse=True,
):
raise ValueError("Required options must go before optional options")
else:
raise TypeError("Options attribute must be either None or a list of options")
def autocomplete(self, option_name: str) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as an option autocomplete."""
def wrapper(call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
if not asyncio.iscoroutinefunction(call):
raise TypeError("autocomplete must be coroutine")
self.autocomplete_callbacks[option_name] = call
# automatically set the option's autocomplete attribute to True
for opt in self.options:
if isinstance(opt, dict) and str(opt["name"]) == option_name:
opt["autocomplete"] = True
elif isinstance(opt, SlashCommandOption) and str(opt.name) == option_name:
opt.autocomplete = True
return call
option_name = option_name.lower()
return wrapper
def group(self, name: str = None, description: str = "No Description Set") -> "SlashCommand":
return SlashCommand(
name=self.name,
description=self.description,
group_name=name,
group_description=description,
scopes=self.scopes,
)
def subcommand(
self,
sub_cmd_name: LocalisedName | str,
group_name: LocalisedName | str = None,
sub_cmd_description: Absent[LocalisedDesc | str] = MISSING,
group_description: Absent[LocalisedDesc | str] = MISSING,
options: List[Union[SlashCommandOption, Dict]] = None,
nsfw: bool = False,
) -> Callable[..., "SlashCommand"]:
def wrapper(call: Callable[..., Coroutine]) -> "SlashCommand":
nonlocal sub_cmd_description
if not asyncio.iscoroutinefunction(call):
raise TypeError("Subcommand must be coroutine")
if sub_cmd_description is MISSING:
sub_cmd_description = call.__doc__ or "No Description Set"
return SlashCommand(
name=self.name,
description=self.description,
group_name=group_name or self.group_name,
group_description=group_description or self.group_description,
sub_cmd_name=sub_cmd_name,
sub_cmd_description=sub_cmd_description,
default_member_permissions=self.default_member_permissions,
dm_permission=self.dm_permission,
options=options,
callback=call,
scopes=self.scopes,
nsfw=nsfw,
)
return wrapper
async
inherited
method
call_with_binding(self, callback, *args, **kwargs)
¶
Call a given method using this objects _binding.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback |
Callable[..., Coroutine[Any, Any, Any]] |
The callback to call. |
required |
Source code in naff/models/naff/application_commands.py
async def call_with_binding(self, callback: Callable[..., Coroutine[Any, Any, Any]], *args, **kwargs) -> Any:
"""
Call a given method using this objects _binding.
Args:
callback: The callback to call.
"""
if self._binding:
return await callback(self._binding, *args, **kwargs)
return await callback(*args, **kwargs)
inherited
method
update_from_dict(self, data)
¶
Updates object attribute(s) with new json data received from discord api.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Dict[str, Any] |
The json data received from discord api. |
required |
Returns:
Type | Description |
---|---|
~T |
The updated object class instance. |
Source code in naff/models/naff/application_commands.py
def update_from_dict(self: Type[const.T], data: Dict[str, Any]) -> const.T:
"""
Updates object attribute(s) with new json data received from discord api.
Args:
data: The json data received from discord api.
Returns:
The updated object class instance.
"""
data = self._process_dict(data)
for key, value in self._filter_kwargs(data, self._get_keys()).items():
# todo improve
setattr(self, key, value)
return self
inherited
method
mention(self, scope)
¶
Returns a string that would mention the interaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scope |
Optional[Snowflake_Type] |
If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified. |
None |
Returns:
Type | Description |
---|---|
str |
The markdown mention. |
Source code in naff/models/naff/application_commands.py
def mention(self, scope: Optional["Snowflake_Type"] = None) -> str:
"""
Returns a string that would mention the interaction.
Args:
scope: If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified.
Returns:
The markdown mention.
"""
if scope:
cmd_id = self.get_cmd_id(scope=scope)
else:
cmd_id = list(self.cmd_id.values())[0]
return f"</{self.resolved_name}:{cmd_id}>"
inherited
method
error(self, call)
¶
A decorator to declare a coroutine as one that will be run upon an error.
Source code in naff/models/naff/application_commands.py
def error(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run upon an error."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("Error handler must be coroutine")
self.error_callback = call
return call
inherited
method
pre_run(self, call)
¶
A decorator to declare a coroutine as one that will be run before the command.
Source code in naff/models/naff/application_commands.py
def pre_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run before the command."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("pre_run must be coroutine")
self.pre_run_callback = call
return call
inherited
method
post_run(self, call)
¶
A decorator to declare a coroutine as one that will be run after the command has.
Source code in naff/models/naff/application_commands.py
def post_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run after the command has."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("post_run must be coroutine")
self.post_run_callback = call
return call
property
readonly
resolved_name: str
¶
A representation of this interaction's name.
method
to_dict(self)
¶
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
Type | Description |
---|---|
dict |
The exported dictionary. |
Source code in naff/models/naff/application_commands.py
def to_dict(self) -> dict:
data = super().to_dict()
if self.is_subcommand:
data["name"] = str(self.sub_cmd_name)
data["description"] = str(self.sub_cmd_description)
data["name_localizations"] = self.sub_cmd_name.to_locale_dict()
data["description_localizations"] = self.sub_cmd_description.to_locale_dict()
data.pop("default_member_permissions", None)
data.pop("dm_permission", None)
data.pop("nsfw", None)
else:
data["name_localizations"] = self.name.to_locale_dict()
data["description_localizations"] = self.description.to_locale_dict()
return data
method
autocomplete(self, option_name)
¶
A decorator to declare a coroutine as an option autocomplete.
Source code in naff/models/naff/application_commands.py
def autocomplete(self, option_name: str) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as an option autocomplete."""
def wrapper(call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
if not asyncio.iscoroutinefunction(call):
raise TypeError("autocomplete must be coroutine")
self.autocomplete_callbacks[option_name] = call
# automatically set the option's autocomplete attribute to True
for opt in self.options:
if isinstance(opt, dict) and str(opt["name"]) == option_name:
opt["autocomplete"] = True
elif isinstance(opt, SlashCommandOption) and str(opt.name) == option_name:
opt.autocomplete = True
return call
option_name = option_name.lower()
return wrapper
attrs
class
ComponentCommand (InteractionCommand)
¶
Attr attributes:
Name | Type | Description |
---|---|---|
extension |
Any |
The extension this command belongs to |
enabled |
bool |
Whether this can be run at all |
checks |
list |
Any checks that must be checked before the command can run |
cooldown |
Cooldown |
An optional cooldown to apply to the command |
max_concurrency |
MaxConcurrency |
An optional maximum number of concurrent instances to apply to the command |
error_callback |
Callable[..., Coroutine] |
The coroutine to be called when an error occurs |
pre_run_callback |
Callable[..., Coroutine] |
The coroutine to be called before the command is executed, but after the checks |
post_run_callback |
Callable[..., Coroutine] |
The coroutine to be called after the command has executed |
scopes |
List[Snowflake_Type] |
The scopes of this interaction. Global or guild ids |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command |
dm_permission |
bool |
Whether this command is enabled in DMs |
cmd_id |
Dict[str, Snowflake_Type] |
The unique IDs of this commands |
callback |
Callable[..., Coroutine] |
The coroutine to call when this interaction is received |
auto_defer |
AutoDefer |
A system to automatically defer this command after a set duration |
nsfw |
bool |
This command should only work in NSFW channels |
Source code in naff/models/naff/application_commands.py
@define()
class ComponentCommand(InteractionCommand):
# right now this adds no extra functionality, but for future dev ive implemented it
name: str = field()
listeners: list[str] = field(factory=list)
async
inherited
method
call_with_binding(self, callback, *args, **kwargs)
¶
Call a given method using this objects _binding.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback |
Callable[..., Coroutine[Any, Any, Any]] |
The callback to call. |
required |
Source code in naff/models/naff/application_commands.py
async def call_with_binding(self, callback: Callable[..., Coroutine[Any, Any, Any]], *args, **kwargs) -> Any:
"""
Call a given method using this objects _binding.
Args:
callback: The callback to call.
"""
if self._binding:
return await callback(self._binding, *args, **kwargs)
return await callback(*args, **kwargs)
inherited
method
update_from_dict(self, data)
¶
Updates object attribute(s) with new json data received from discord api.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Dict[str, Any] |
The json data received from discord api. |
required |
Returns:
Type | Description |
---|---|
~T |
The updated object class instance. |
Source code in naff/models/naff/application_commands.py
def update_from_dict(self: Type[const.T], data: Dict[str, Any]) -> const.T:
"""
Updates object attribute(s) with new json data received from discord api.
Args:
data: The json data received from discord api.
Returns:
The updated object class instance.
"""
data = self._process_dict(data)
for key, value in self._filter_kwargs(data, self._get_keys()).items():
# todo improve
setattr(self, key, value)
return self
inherited
method
to_dict(self)
¶
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
Type | Description |
---|---|
dict |
The exported dictionary. |
Source code in naff/models/naff/application_commands.py
def to_dict(self) -> dict:
data = super().to_dict()
if self.default_member_permissions is not None:
data["default_member_permissions"] = str(int(self.default_member_permissions))
else:
data["default_member_permissions"] = None
return data
inherited
method
mention(self, scope)
¶
Returns a string that would mention the interaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scope |
Optional[Snowflake_Type] |
If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified. |
None |
Returns:
Type | Description |
---|---|
str |
The markdown mention. |
Source code in naff/models/naff/application_commands.py
def mention(self, scope: Optional["Snowflake_Type"] = None) -> str:
"""
Returns a string that would mention the interaction.
Args:
scope: If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified.
Returns:
The markdown mention.
"""
if scope:
cmd_id = self.get_cmd_id(scope=scope)
else:
cmd_id = list(self.cmd_id.values())[0]
return f"</{self.resolved_name}:{cmd_id}>"
inherited
property
readonly
resolved_name: str
¶
A representation of this interaction's name.
inherited
method
error(self, call)
¶
A decorator to declare a coroutine as one that will be run upon an error.
Source code in naff/models/naff/application_commands.py
def error(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run upon an error."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("Error handler must be coroutine")
self.error_callback = call
return call
inherited
method
pre_run(self, call)
¶
A decorator to declare a coroutine as one that will be run before the command.
Source code in naff/models/naff/application_commands.py
def pre_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run before the command."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("pre_run must be coroutine")
self.pre_run_callback = call
return call
inherited
method
post_run(self, call)
¶
A decorator to declare a coroutine as one that will be run after the command has.
Source code in naff/models/naff/application_commands.py
def post_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run after the command has."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("post_run must be coroutine")
self.post_run_callback = call
return call
attrs
class
ModalCommand (ComponentCommand)
¶
Attr attributes:
Name | Type | Description |
---|---|---|
extension |
Any |
The extension this command belongs to |
enabled |
bool |
Whether this can be run at all |
checks |
list |
Any checks that must be checked before the command can run |
cooldown |
Cooldown |
An optional cooldown to apply to the command |
max_concurrency |
MaxConcurrency |
An optional maximum number of concurrent instances to apply to the command |
error_callback |
Callable[..., Coroutine] |
The coroutine to be called when an error occurs |
pre_run_callback |
Callable[..., Coroutine] |
The coroutine to be called before the command is executed, but after the checks |
post_run_callback |
Callable[..., Coroutine] |
The coroutine to be called after the command has executed |
scopes |
List[Snowflake_Type] |
The scopes of this interaction. Global or guild ids |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command |
dm_permission |
bool |
Whether this command is enabled in DMs |
cmd_id |
Dict[str, Snowflake_Type] |
The unique IDs of this commands |
callback |
Callable[..., Coroutine] |
The coroutine to call when this interaction is received |
auto_defer |
AutoDefer |
A system to automatically defer this command after a set duration |
nsfw |
bool |
This command should only work in NSFW channels |
Source code in naff/models/naff/application_commands.py
@define()
class ModalCommand(ComponentCommand):
...
async
inherited
method
call_with_binding(self, callback, *args, **kwargs)
¶
Call a given method using this objects _binding.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback |
Callable[..., Coroutine[Any, Any, Any]] |
The callback to call. |
required |
Source code in naff/models/naff/application_commands.py
async def call_with_binding(self, callback: Callable[..., Coroutine[Any, Any, Any]], *args, **kwargs) -> Any:
"""
Call a given method using this objects _binding.
Args:
callback: The callback to call.
"""
if self._binding:
return await callback(self._binding, *args, **kwargs)
return await callback(*args, **kwargs)
inherited
method
update_from_dict(self, data)
¶
Updates object attribute(s) with new json data received from discord api.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Dict[str, Any] |
The json data received from discord api. |
required |
Returns:
Type | Description |
---|---|
~T |
The updated object class instance. |
Source code in naff/models/naff/application_commands.py
def update_from_dict(self: Type[const.T], data: Dict[str, Any]) -> const.T:
"""
Updates object attribute(s) with new json data received from discord api.
Args:
data: The json data received from discord api.
Returns:
The updated object class instance.
"""
data = self._process_dict(data)
for key, value in self._filter_kwargs(data, self._get_keys()).items():
# todo improve
setattr(self, key, value)
return self
inherited
method
to_dict(self)
¶
Exports object into dictionary representation, ready to be sent to discord api.
Returns:
Type | Description |
---|---|
dict |
The exported dictionary. |
Source code in naff/models/naff/application_commands.py
def to_dict(self) -> dict:
data = super().to_dict()
if self.default_member_permissions is not None:
data["default_member_permissions"] = str(int(self.default_member_permissions))
else:
data["default_member_permissions"] = None
return data
inherited
method
mention(self, scope)
¶
Returns a string that would mention the interaction.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
scope |
Optional[Snowflake_Type] |
If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified. |
None |
Returns:
Type | Description |
---|---|
str |
The markdown mention. |
Source code in naff/models/naff/application_commands.py
def mention(self, scope: Optional["Snowflake_Type"] = None) -> str:
"""
Returns a string that would mention the interaction.
Args:
scope: If the command is available in multiple scope, specify which scope to get the mention for. Defaults to the first available one if not specified.
Returns:
The markdown mention.
"""
if scope:
cmd_id = self.get_cmd_id(scope=scope)
else:
cmd_id = list(self.cmd_id.values())[0]
return f"</{self.resolved_name}:{cmd_id}>"
inherited
property
readonly
resolved_name: str
¶
A representation of this interaction's name.
inherited
method
error(self, call)
¶
A decorator to declare a coroutine as one that will be run upon an error.
Source code in naff/models/naff/application_commands.py
def error(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run upon an error."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("Error handler must be coroutine")
self.error_callback = call
return call
inherited
method
pre_run(self, call)
¶
A decorator to declare a coroutine as one that will be run before the command.
Source code in naff/models/naff/application_commands.py
def pre_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run before the command."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("pre_run must be coroutine")
self.pre_run_callback = call
return call
inherited
method
post_run(self, call)
¶
A decorator to declare a coroutine as one that will be run after the command has.
Source code in naff/models/naff/application_commands.py
def post_run(self, call: Callable[..., Coroutine]) -> Callable[..., Coroutine]:
"""A decorator to declare a coroutine as one that will be run after the command has."""
if not asyncio.iscoroutinefunction(call):
raise TypeError("post_run must be coroutine")
self.post_run_callback = call
return call
function
slash_command(name, *, description, scopes, options, default_member_permissions, dm_permission, sub_cmd_name, group_name, sub_cmd_description, group_description, nsfw)
¶
A decorator to declare a coroutine as a slash command.
Note
While the base and group descriptions arent visible in the discord client, currently. We strongly advise defining them anyway, if you're using subcommands, as Discord has said they will be visible in one of the future ui updates.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str | naff.models.naff.application_commands.LocalisedName |
1-32 character name of the command |
required |
description |
Union[naff.models.naff.application_commands.LocalisedDesc, str, naff.client.const.Missing] |
1-100 character description of the command |
Missing |
scopes |
Union[List[Snowflake_Type], naff.client.const.Missing] |
The scope this command exists within |
Missing |
options |
Optional[List[Union[naff.models.naff.application_commands.SlashCommandOption, Dict]]] |
The parameters for the command, max 25 |
None |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command. |
None |
dm_permission |
bool |
Should this command be available in DMs. |
True |
sub_cmd_name |
str | naff.models.naff.application_commands.LocalisedName |
1-32 character name of the subcommand |
None |
sub_cmd_description |
str | naff.models.naff.application_commands.LocalisedDesc |
1-100 character description of the subcommand |
'No Description Set' |
group_name |
str | naff.models.naff.application_commands.LocalisedName |
1-32 character name of the group |
None |
group_description |
str | naff.models.naff.application_commands.LocalisedDesc |
1-100 character description of the group |
'No Description Set' |
nsfw |
bool |
This command should only work in NSFW channels |
False |
Returns:
Type | Description |
---|---|
Callable[[Callable[..., Coroutine]], naff.models.naff.application_commands.SlashCommand] |
SlashCommand Object |
Source code in naff/models/naff/application_commands.py
def slash_command(
name: str | LocalisedName,
*,
description: Absent[str | LocalisedDesc] = MISSING,
scopes: Absent[List["Snowflake_Type"]] = MISSING,
options: Optional[List[Union[SlashCommandOption, Dict]]] = None,
default_member_permissions: Optional["Permissions"] = None,
dm_permission: bool = True,
sub_cmd_name: str | LocalisedName = None,
group_name: str | LocalisedName = None,
sub_cmd_description: str | LocalisedDesc = "No Description Set",
group_description: str | LocalisedDesc = "No Description Set",
nsfw: bool = False,
) -> Callable[[Callable[..., Coroutine]], SlashCommand]:
"""
A decorator to declare a coroutine as a slash command.
note:
While the base and group descriptions arent visible in the discord client, currently.
We strongly advise defining them anyway, if you're using subcommands, as Discord has said they will be visible in
one of the future ui updates.
Args:
name: 1-32 character name of the command
description: 1-100 character description of the command
scopes: The scope this command exists within
options: The parameters for the command, max 25
default_member_permissions: What permissions members need to have by default to use this command.
dm_permission: Should this command be available in DMs.
sub_cmd_name: 1-32 character name of the subcommand
sub_cmd_description: 1-100 character description of the subcommand
group_name: 1-32 character name of the group
group_description: 1-100 character description of the group
nsfw: This command should only work in NSFW channels
Returns:
SlashCommand Object
"""
def wrapper(func: Callable[..., Coroutine]) -> SlashCommand:
if not asyncio.iscoroutinefunction(func):
raise ValueError("Commands must be coroutines")
perm = default_member_permissions
if hasattr(func, "default_member_permissions"):
if perm:
perm = perm | func.default_member_permissions
else:
perm = func.default_member_permissions
_description = description
if _description is MISSING:
_description = func.__doc__ if func.__doc__ else "No Description Set"
cmd = SlashCommand(
name=name,
group_name=group_name,
group_description=group_description,
sub_cmd_name=sub_cmd_name,
sub_cmd_description=sub_cmd_description,
description=_description,
scopes=scopes if scopes else [GLOBAL_SCOPE],
default_member_permissions=perm,
dm_permission=dm_permission,
callback=func,
options=options,
nsfw=nsfw,
)
return cmd
return wrapper
function
subcommand(base, *, subcommand_group, name, description, base_description, base_desc, base_default_member_permissions, base_dm_permission, subcommand_group_description, sub_group_desc, scopes, options, nsfw)
¶
A decorator specifically tailored for creating subcommands.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
base |
str | naff.models.naff.application_commands.LocalisedName |
The name of the base command |
required |
subcommand_group |
Union[str, naff.models.naff.application_commands.LocalisedName] |
The name of the subcommand group, if any. |
None |
name |
Union[str, naff.models.naff.application_commands.LocalisedName] |
The name of the subcommand, defaults to the name of the coroutine. |
None |
description |
Union[naff.models.naff.application_commands.LocalisedDesc, str, naff.client.const.Missing] |
The description of the subcommand |
Missing |
base_description |
Union[str, naff.models.naff.application_commands.LocalisedDesc] |
The description of the base command |
None |
base_desc |
Union[str, naff.models.naff.application_commands.LocalisedDesc] |
An alias of |
None |
base_default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command. |
None |
base_dm_permission |
bool |
Should this command be available in DMs. |
True |
subcommand_group_description |
Union[str, naff.models.naff.application_commands.LocalisedDesc] |
Description of the subcommand group |
None |
sub_group_desc |
Union[str, naff.models.naff.application_commands.LocalisedDesc] |
An alias for |
None |
scopes |
List[Snowflake_Type] |
The scopes of which this command is available, defaults to GLOBAL_SCOPE |
None |
options |
List[dict] |
The options for this command |
None |
nsfw |
bool |
This command should only work in NSFW channels |
False |
Returns:
Type | Description |
---|---|
Callable[[Coroutine], naff.models.naff.application_commands.SlashCommand] |
A SlashCommand object |
Source code in naff/models/naff/application_commands.py
def subcommand(
base: str | LocalisedName,
*,
subcommand_group: Optional[str | LocalisedName] = None,
name: Optional[str | LocalisedName] = None,
description: Absent[str | LocalisedDesc] = MISSING,
base_description: Optional[str | LocalisedDesc] = None,
base_desc: Optional[str | LocalisedDesc] = None,
base_default_member_permissions: Optional["Permissions"] = None,
base_dm_permission: bool = True,
subcommand_group_description: Optional[str | LocalisedDesc] = None,
sub_group_desc: Optional[str | LocalisedDesc] = None,
scopes: List["Snowflake_Type"] = None,
options: List[dict] = None,
nsfw: bool = False,
) -> Callable[[Coroutine], SlashCommand]:
"""
A decorator specifically tailored for creating subcommands.
Args:
base: The name of the base command
subcommand_group: The name of the subcommand group, if any.
name: The name of the subcommand, defaults to the name of the coroutine.
description: The description of the subcommand
base_description: The description of the base command
base_desc: An alias of `base_description`
base_default_member_permissions: What permissions members need to have by default to use this command.
base_dm_permission: Should this command be available in DMs.
subcommand_group_description: Description of the subcommand group
sub_group_desc: An alias for `subcommand_group_description`
scopes: The scopes of which this command is available, defaults to GLOBAL_SCOPE
options: The options for this command
nsfw: This command should only work in NSFW channels
Returns:
A SlashCommand object
"""
def wrapper(func) -> SlashCommand:
if not asyncio.iscoroutinefunction(func):
raise ValueError("Commands must be coroutines")
_description = description
if _description is MISSING:
_description = func.__doc__ if func.__doc__ else "No Description Set"
cmd = SlashCommand(
name=base,
description=(base_description or base_desc) or "No Description Set",
group_name=subcommand_group,
group_description=(subcommand_group_description or sub_group_desc) or "No Description Set",
sub_cmd_name=name,
sub_cmd_description=_description,
default_member_permissions=base_default_member_permissions,
dm_permission=base_dm_permission,
scopes=scopes if scopes else [GLOBAL_SCOPE],
callback=func,
options=options,
nsfw=nsfw,
)
return cmd
return wrapper
function
context_menu(name, context_type, scopes, default_member_permissions, dm_permission)
¶
A decorator to declare a coroutine as a Context Menu.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str | naff.models.naff.application_commands.LocalisedName |
1-32 character name of the context menu |
required |
context_type |
CommandTypes |
The type of context menu |
required |
scopes |
Union[List[Snowflake_Type], naff.client.const.Missing] |
The scope this command exists within |
Missing |
default_member_permissions |
Optional[Permissions] |
What permissions members need to have by default to use this command. |
None |
dm_permission |
bool |
Should this command be available in DMs. |
True |
Returns:
Type | Description |
---|---|
Callable[[Coroutine], naff.models.naff.application_commands.ContextMenu] |
ContextMenu object |
Source code in naff/models/naff/application_commands.py
def context_menu(
name: str | LocalisedName,
context_type: "CommandTypes",
scopes: Absent[List["Snowflake_Type"]] = MISSING,
default_member_permissions: Optional["Permissions"] = None,
dm_permission: bool = True,
) -> Callable[[Coroutine], ContextMenu]:
"""
A decorator to declare a coroutine as a Context Menu.
Args:
name: 1-32 character name of the context menu
context_type: The type of context menu
scopes: The scope this command exists within
default_member_permissions: What permissions members need to have by default to use this command.
dm_permission: Should this command be available in DMs.
Returns:
ContextMenu object
"""
def wrapper(func) -> ContextMenu:
if not asyncio.iscoroutinefunction(func):
raise ValueError("Commands must be coroutines")
perm = default_member_permissions
if hasattr(func, "default_member_permissions"):
if perm:
perm = perm | func.default_member_permissions
else:
perm = func.default_member_permissions
cmd = ContextMenu(
name=name,
type=context_type,
scopes=scopes if scopes else [GLOBAL_SCOPE],
default_member_permissions=perm,
dm_permission=dm_permission,
callback=func,
)
return cmd
return wrapper
function
component_callback(*custom_id)
¶
Register a coroutine as a component callback.
Component callbacks work the same way as commands, just using components as a way of invoking, instead of messages.
Your callback will be given a single argument, ComponentContext
Parameters:
Name | Type | Description | Default |
---|---|---|---|
custom_id |
str |
The custom ID of the component to wait for |
() |
Source code in naff/models/naff/application_commands.py
def component_callback(*custom_id: str) -> Callable[[Coroutine], ComponentCommand]:
"""
Register a coroutine as a component callback.
Component callbacks work the same way as commands, just using components as a way of invoking, instead of messages.
Your callback will be given a single argument, `ComponentContext`
Args:
custom_id: The custom ID of the component to wait for
"""
def wrapper(func) -> ComponentCommand:
if not asyncio.iscoroutinefunction(func):
raise ValueError("Commands must be coroutines")
return ComponentCommand(name=f"ComponentCallback::{custom_id}", callback=func, listeners=custom_id)
custom_id = _unpack_helper(custom_id)
return wrapper
function
modal_callback(*custom_id)
¶
Register a coroutine as a modal callback.
Modal callbacks work the same way as commands, just using modals as a way of invoking, instead of messages.
Your callback will be given a single argument, ModalContext
Parameters:
Name | Type | Description | Default |
---|---|---|---|
*custom_id |
str |
The custom ID of the modal to wait for |
() |
Source code in naff/models/naff/application_commands.py
def modal_callback(*custom_id: str) -> Callable[[Coroutine], ModalCommand]:
"""
Register a coroutine as a modal callback.
Modal callbacks work the same way as commands, just using modals as a way of invoking, instead of messages.
Your callback will be given a single argument, `ModalContext`
Args:
*custom_id: The custom ID of the modal to wait for
"""
def wrapper(func) -> ModalCommand:
if not asyncio.iscoroutinefunction(func):
raise ValueError("Commands must be coroutines")
return ModalCommand(name=f"ModalCallback::{custom_id}", callback=func, listeners=custom_id)
custom_id = _unpack_helper(custom_id)
return wrapper
function
slash_option(name, description, opt_type, required, autocomplete, choices, channel_types, min_value, max_value, min_length, max_length)
¶
A decorator to add an option to a slash command.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str |
1-32 lowercase character name matching ^[\w-]{1,32}$ |
required |
opt_type |
Union[naff.models.naff.application_commands.OptionTypes, int] |
The type of option |
required |
description |
str |
1-100 character description of option |
required |
required |
bool |
If the parameter is required or optional--default false |
False |
choices |
List[Union[naff.models.naff.application_commands.SlashCommandChoice, dict]] |
A list of choices the user has to pick between (max 25) |
None |
channel_types |
Optional[list[Union[naff.models.discord.enums.ChannelTypes, int]]] |
The channel types permitted. The option needs to be a channel |
None |
min_value |
Optional[float] |
The minimum value permitted. The option needs to be an integer or float |
None |
max_value |
Optional[float] |
The maximum value permitted. The option needs to be an integer or float |
None |
min_length |
Optional[int] |
The minimum length of text a user can input. The option needs to be a string |
None |
max_length |
Optional[int] |
The maximum length of text a user can input. The option needs to be a string |
None |
Source code in naff/models/naff/application_commands.py
def slash_option(
name: str,
description: str,
opt_type: Union[OptionTypes, int],
required: bool = False,
autocomplete: bool = False,
choices: List[Union[SlashCommandChoice, dict]] = None,
channel_types: Optional[list[Union[ChannelTypes, int]]] = None,
min_value: Optional[float] = None,
max_value: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
) -> Any:
r"""
A decorator to add an option to a slash command.
Args:
name: 1-32 lowercase character name matching ^[\w-]{1,32}$
opt_type: The type of option
description: 1-100 character description of option
required: If the parameter is required or optional--default false
choices: A list of choices the user has to pick between (max 25)
channel_types: The channel types permitted. The option needs to be a channel
min_value: The minimum value permitted. The option needs to be an integer or float
max_value: The maximum value permitted. The option needs to be an integer or float
min_length: The minimum length of text a user can input. The option needs to be a string
max_length: The maximum length of text a user can input. The option needs to be a string
"""
def wrapper(func: Coroutine) -> Coroutine:
if hasattr(func, "cmd_id"):
raise Exception("slash_option decorators must be positioned under a slash_command decorator")
option = SlashCommandOption(
name=name,
type=opt_type,
description=description,
required=required,
autocomplete=autocomplete,
choices=choices if choices else [],
channel_types=channel_types,
min_value=min_value,
max_value=max_value,
min_length=min_length,
max_length=max_length,
)
if not hasattr(func, "options"):
func.options = []
func.options.insert(0, option)
return func
return wrapper
function
slash_default_member_permission(permission)
¶
A decorator to permissions members need to have by default to use a command.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
permission |
Permissions |
The permissions to require for to this command |
required |
Source code in naff/models/naff/application_commands.py
def slash_default_member_permission(permission: "Permissions") -> Any:
"""
A decorator to permissions members need to have by default to use a command.
Args:
permission: The permissions to require for to this command
"""
def wrapper(func: Coroutine) -> Coroutine:
if hasattr(func, "cmd_id"):
raise Exception(
"slash_default_member_permission decorators must be positioned under a slash_command decorator"
)
if not hasattr(func, "default_member_permissions") or func.default_member_permissions is None:
func.default_member_permissions = permission
else:
func.default_member_permissions = func.default_member_permissions | permission
return func
return wrapper
function
auto_defer(ephemeral, time_until_defer)
¶
A decorator to add an auto defer to a application command.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
ephemeral |
bool |
Should the command be deferred as ephemeral |
False |
time_until_defer |
float |
How long to wait before deferring automatically |
0.0 |
Source code in naff/models/naff/application_commands.py
def auto_defer(ephemeral: bool = False, time_until_defer: float = 0.0) -> Callable[[Coroutine], Coroutine]:
"""
A decorator to add an auto defer to a application command.
Args:
ephemeral: Should the command be deferred as ephemeral
time_until_defer: How long to wait before deferring automatically
"""
def wrapper(func: Coroutine) -> Coroutine:
if hasattr(func, "cmd_id"):
raise Exception("auto_defer decorators must be positioned under a slash_command decorator")
func.auto_defer = AutoDefer(enabled=True, ephemeral=ephemeral, time_until_defer=time_until_defer)
return func
return wrapper
function
application_commands_to_dict(commands)
¶
Convert the command list into a format that would be accepted by discord.
Client.interactions
should be the variable passed to this
Source code in naff/models/naff/application_commands.py
def application_commands_to_dict(commands: Dict["Snowflake_Type", Dict[str, InteractionCommand]]) -> dict:
"""
Convert the command list into a format that would be accepted by discord.
`Client.interactions` should be the variable passed to this
"""
cmd_bases = {} # {cmd_base: [commands]}
"""A store of commands organised by their base command"""
output = {}
"""The output dictionary"""
def squash_subcommand(subcommands: List) -> Dict:
output_data = {}
groups = {}
sub_cmds = []
for subcommand in subcommands:
if not output_data:
output_data = {
"name": str(subcommand.name),
"description": str(subcommand.description),
"options": [],
"default_member_permissions": str(int(subcommand.default_member_permissions))
if subcommand.default_member_permissions
else None,
"dm_permission": subcommand.dm_permission,
"name_localizations": subcommand.name.to_locale_dict(),
"description_localizations": subcommand.description.to_locale_dict(),
"nsfw": subcommand.nsfw,
}
if bool(subcommand.group_name):
if str(subcommand.group_name) not in groups:
groups[str(subcommand.group_name)] = {
"name": str(subcommand.group_name),
"description": str(subcommand.group_description),
"type": int(OptionTypes.SUB_COMMAND_GROUP),
"options": [],
"name_localizations": subcommand.group_name.to_locale_dict(),
"description_localizations": subcommand.group_description.to_locale_dict(),
}
groups[str(subcommand.group_name)]["options"].append(
subcommand.to_dict() | {"type": int(OptionTypes.SUB_COMMAND)}
)
elif subcommand.is_subcommand:
sub_cmds.append(subcommand.to_dict() | {"type": int(OptionTypes.SUB_COMMAND)})
options = list(groups.values()) + sub_cmds
output_data["options"] = options
return output_data
for _scope, cmds in commands.items():
for cmd in cmds.values():
cmd_name = str(cmd.name)
if cmd_name not in cmd_bases:
cmd_bases[cmd_name] = [cmd]
continue
if cmd not in cmd_bases[cmd_name]:
cmd_bases[cmd_name].append(cmd)
for cmd_list in cmd_bases.values():
if any(c.is_subcommand for c in cmd_list):
# validate all commands share required attributes
scopes: list[Snowflake_Type] = list({s for c in cmd_list for s in c.scopes})
base_description = next(
(
c.description
for c in cmd_list
if str(c.description) is not None and str(c.description) != "No Description Set"
),
"No Description Set",
)
nsfw = cmd_list[0].nsfw
if not all(str(c.description) in (str(base_description), "No Description Set") for c in cmd_list):
logger.warning(
f"Conflicting descriptions found in `{cmd_list[0].name}` subcommands; `{str(base_description)}` will be used"
)
if not all(c.default_member_permissions == cmd_list[0].default_member_permissions for c in cmd_list):
raise ValueError(f"Conflicting `default_member_permissions` values found in `{cmd_list[0].name}`")
if not all(c.dm_permission == cmd_list[0].dm_permission for c in cmd_list):
raise ValueError(f"Conflicting `dm_permission` values found in `{cmd_list[0].name}`")
if not all(c.nsfw == nsfw for c in cmd_list):
logger.warning(f"Conflicting `nsfw` values found in {cmd_list[0].name} - `True` will be used")
nsfw = True
for cmd in cmd_list:
cmd.scopes = list(scopes)
cmd.description = base_description
# end validation of attributes
cmd_data = squash_subcommand(cmd_list)
else:
scopes = cmd_list[0].scopes
cmd_data = cmd_list[0].to_dict()
for s in scopes:
if s not in output:
output[s] = [cmd_data]
continue
output[s].append(cmd_data)
return output
function
sync_needed(local_cmd, remote_cmd)
¶
Compares a local application command to its remote counterpart to determine if a sync is required.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
local_cmd |
dict |
The local json representation of the command |
required |
remote_cmd |
Optional[dict] |
The json representation of the command from Discord |
None |
Returns:
Type | Description |
---|---|
bool |
Boolean indicating if a sync is needed |
Source code in naff/models/naff/application_commands.py
def sync_needed(local_cmd: dict, remote_cmd: Optional[dict] = None) -> bool:
"""
Compares a local application command to its remote counterpart to determine if a sync is required.
Args:
local_cmd: The local json representation of the command
remote_cmd: The json representation of the command from Discord
Returns:
Boolean indicating if a sync is needed
"""
if not remote_cmd:
# No remote version, command must be new
return True
if not _compare_commands(local_cmd, remote_cmd):
# basic comparison of attributes
return True
if remote_cmd["type"] == CommandTypes.CHAT_INPUT:
try:
if not _compare_options(local_cmd["options"], remote_cmd["options"]):
# options are not the same, sync needed
return True
except KeyError:
if "options" in local_cmd or "options" in remote_cmd:
return True
return False