Browse Source

Implement BaseCommand.application properly; app command documentation fixes

pull/10109/head
dolfies 3 years ago
parent
commit
ec2834f050
  1. 12
      discord/appinfo.py
  2. 56
      discord/commands.py
  3. 13
      discord/iterators.py

12
discord/appinfo.py

@ -31,6 +31,7 @@ from .asset import Asset
from .enums import ApplicationType, ApplicationVerificationState, RPCApplicationState, StoreApplicationState, try_enum
from .flags import ApplicationFlags
from .mixins import Hashable
from .object import Object
from .permissions import Permissions
from .user import User
@ -554,13 +555,8 @@ class InteractionApplication(Hashable):
The bot attached to the application.
description: Optional[:class:`str`]
The application description.
Only available from :attr:`~Modal.application`.
type: Optional[:class:`ApplicationType`]
The type of application.
Only available from :attr:`~Modal.application`.
command_count: Optional[:class:`int`]
The number of commands the application has.
Only available from :attr:`~BaseCommand.application`.
"""
__slots__ = (
@ -583,14 +579,16 @@ class InteractionApplication(Hashable):
def _update(self, data: dict) -> None:
self.id: int = int(data['id'])
self.name: str = data['name']
self.description: Optional[str] = data.get('description')
self.description: str = data.get('description') or ''
self._icon: Optional[str] = data.get('icon')
self.type: Optional[ApplicationType] = try_enum(ApplicationType, data['type']) if 'type' in data else None
self.bot: User = None # type: ignore # This should never be None but it's volatile
self.bot: User # User data should always be available, but these payloads are volatile
user = data.get('bot')
if user is not None:
self.bot = User(state=self._state, data=user)
else:
self.bot = Object(id=self.id) # type: ignore
def __repr__(self) -> str:
return f'<{self.__class__.__name__} id={self.id} name={self.name!r}>'

56
discord/commands.py

@ -33,6 +33,7 @@ from .utils import _generate_nonce
if TYPE_CHECKING:
from .abc import Messageable, Snowflake
from .appinfo import InteractionApplication
from .interactions import Interaction
from .message import Message
from .state import ConnectionState
@ -68,19 +69,27 @@ class ApplicationCommand(Protocol):
The command's description, if any.
type: :class:`.AppCommandType`
The type of application command.
default_permission: :class:`bool`
Whether the command is enabled in guilds by default.
application: Optional[:class:`InteractionApplication`]
The application this command belongs to.
Only available if requested.
application_id: :class:`int`
The ID of the application this command belongs to.
"""
__slots__ = ()
if TYPE_CHECKING:
_state: ConnectionState
_application_id: int
application_id: int
name: str
description: str
version: int
type: AppCommandType
target_channel: Optional[Messageable]
default_permission: bool
application: Optional[InteractionApplication]
def __str__(self) -> str:
return self.name
@ -97,7 +106,7 @@ class ApplicationCommand(Protocol):
state._interaction_cache[nonce] = (type.value, data['name'], acc_channel)
try:
await state.http.interact(
type, data, acc_channel, form_data=True, nonce=nonce, application_id=self._application_id
type, data, acc_channel, form_data=True, nonce=nonce, application_id=self.application_id
)
i = await state.client.wait_for(
'interaction_finish',
@ -138,14 +147,19 @@ class BaseCommand(ApplicationCommand, Hashable):
The command's ID.
version: :class:`int`
The command's version.
default_permission: :class:`bool`
Whether the command is enabled in guilds by default.
name: :class:`str`
The command's name.
description: :class:`str`
The command's description, if any.
type: :class:`AppCommandType`
The type of application command.
default_permission: :class:`bool`
Whether the command is enabled in guilds by default.
application: Optional[:class:`InteractionApplication`]
The application this command belongs to.
Only available if requested.
application_id: :class:`int`
The ID of the application this command belongs to.
"""
__slots__ = (
@ -155,27 +169,29 @@ class BaseCommand(ApplicationCommand, Hashable):
'version',
'type',
'default_permission',
'application',
'application_id',
'_data',
'_state',
'_channel',
'_application_id',
'_dm_permission',
'_default_member_permissions',
)
def __init__(self, *, state: ConnectionState, data: Dict[str, Any], channel: Optional[Messageable] = None) -> None:
def __init__(self, *, state: ConnectionState, data: Dict[str, Any], channel: Optional[Messageable] = None, application: Optional[InteractionApplication] = None) -> None:
self._state = state
self._data = data
self.name = data['name']
self.description = data['description']
self._channel = channel
self._application_id: int = int(data['application_id'])
self.application_id: int = int(data['application_id'])
self.id: int = int(data['id'])
self.version = int(data['version'])
self.type = try_enum(AppCommandType, data['type'])
self.default_permission: bool = data['default_permission']
self.default_permission: bool = data.get('default_permission', True)
self._dm_permission = data.get('dm_permission')
self._default_member_permissions = data['default_member_permissions']
self.application = application
def __repr__(self) -> str:
return f'<{self.__class__.__name__} id={self.id} name={self.name!r}>'
@ -192,12 +208,6 @@ class BaseCommand(ApplicationCommand, Hashable):
"""
return False
@property
def application(self):
"""The application this command belongs to."""
...
# return self._state.get_application(self._application_id)
@property
def target_channel(self) -> Optional[Messageable]:
"""Optional[:class:`.abc.Messageable`]: The channel this application command will be used on.
@ -567,8 +577,9 @@ class SubCommand(SlashMixin):
return BASE + '>'
@property
def _application_id(self) -> int:
return self._parent._application_id
def application_id(self) -> int:
""":class:`int`: The ID of the application this command belongs to."""
return self._parent.application_id
@property
def version(self) -> int:
@ -592,7 +603,9 @@ class SubCommand(SlashMixin):
@property
def application(self):
"""The application this command belongs to."""
"""Optional[:class:`InteractionApplication`]: The application this command belongs to.
Only available if requested.
"""
return self._parent.application
@property
@ -608,7 +621,7 @@ class SubCommand(SlashMixin):
self._parent.target_channel = value
class Option: # TODO: Add validation
class Option:
"""Represents a command option.
.. container:: operations
@ -633,12 +646,17 @@ class Option: # TODO: Add validation
Maximum value of the option. Only applicable to :attr:`AppCommandOptionType.integer` and :attr:`AppCommandOptionType.number`.
choices: List[:class:`OptionChoice`]
A list of possible choices to choose from. If these are present, you must choose one from them.
Only applicable to :attr:`AppCommandOptionType.string`, :attr:`AppCommandOptionType.integer`, and :attr:`AppCommandOptionType.number`.
channel_types: List[:class:`ChannelType`]
A list of channel types that you can choose from. If these are present, you must choose a channel that is one of these types.
Only applicable to :attr:`AppCommandOptionType.channel`.
autocomplete: :class:`bool`
Whether the option autocompletes. Always ``False`` if :attr:`choices` are present.
Whether the option autocompletes.
Only applicable to :attr:`AppCommandOptionType.string`, :attr:`AppCommandOptionType.integer`, and :attr:`AppCommandOptionType.number`.
Always ``False`` if :attr:`choices` are present.
"""
__slots__ = (

13
discord/iterators.py

@ -27,8 +27,9 @@ from __future__ import annotations
import asyncio
from typing import Awaitable, TYPE_CHECKING, TypeVar, Optional, Any, Callable, Union, List, Tuple, AsyncIterator, Dict
from .appinfo import InteractionApplication
from .errors import InvalidData
from .utils import _generate_nonce
from .utils import _generate_nonce, _get_as_snowflake
from .object import Object
from .commands import _command_factory
from .enums import AppCommandType
@ -97,6 +98,7 @@ class CommandIterator:
self.applications: bool = kwargs.get('applications', True)
self.application: Snowflake = kwargs.get('application', None)
self.commands = asyncio.Queue()
self._application_cache: Dict[int, InteractionApplication] = {}
async def _process_args(self) -> Tuple[DMChannel, Optional[str], Optional[Union[User, Message]]]:
item = self.item
@ -189,19 +191,20 @@ class CommandIterator:
kwargs['offset'] += retrieve
for app in data.get('applications', []):
self._application_cache[int(app['id'])] = InteractionApplication(state=state, data=app)
for cmd in cmds:
self.commands.put_nowait(self.create_command(cmd))
for app in data.get('applications', []):
...
def create_command(self, data) -> ApplicationCommand:
channel, item, value = self._tuple # type: ignore
if item is not None:
kwargs = {item: value}
else:
kwargs = {}
return self.cls(state=channel._state, data=data, channel=channel, **kwargs)
app_id = _get_as_snowflake(data, 'application_id')
return self.cls(state=channel._state, data=data, channel=channel, application=self._application_cache.get(app_id), **kwargs) # type: ignore
class FakeCommandIterator:

Loading…
Cancel
Save