aboutsummaryrefslogtreecommitdiff
path: root/discord/ui/item.py
diff options
context:
space:
mode:
authorRapptz <[email protected]>2021-04-25 04:57:29 -0400
committerRapptz <[email protected]>2021-05-27 00:53:13 -0400
commit98570793e4af8dcfca25621e86fecd85297b0d59 (patch)
treeefcbe97935fa61126c642f00fdd3ebbc15b61375 /discord/ui/item.py
parentFix bug in Embed.__len__ caused by footer without text (diff)
downloaddiscord.py-98570793e4af8dcfca25621e86fecd85297b0d59.tar.xz
discord.py-98570793e4af8dcfca25621e86fecd85297b0d59.zip
Add initial support for buttons and components
Diffstat (limited to 'discord/ui/item.py')
-rw-r--r--discord/ui/item.py140
1 files changed, 140 insertions, 0 deletions
diff --git a/discord/ui/item.py b/discord/ui/item.py
new file mode 100644
index 00000000..7726407e
--- /dev/null
+++ b/discord/ui/item.py
@@ -0,0 +1,140 @@
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+from __future__ import annotations
+
+from typing import Any, Callable, Coroutine, Dict, Optional, TYPE_CHECKING, Tuple, Type, TypeVar, Union
+import inspect
+
+from ..interactions import Interaction
+
+__all__ = (
+ 'Item',
+)
+
+if TYPE_CHECKING:
+ from ..enums import ComponentType
+ from .view import View
+ from ..components import Component
+
+I = TypeVar('I', bound='Item')
+ItemCallbackType = Callable[[Any, I, Interaction], Coroutine[Any, Any, Any]]
+
+
+class Item:
+ """Represents the base UI item that all UI components inherit from.
+
+ The current UI items supported are:
+
+ - :class:`discord.ui.Button`
+ """
+
+ __slots__: Tuple[str, ...] = (
+ '_callback',
+ '_pass_view_arg',
+ 'group_id',
+ )
+
+ __item_repr_attributes__: Tuple[str, ...] = ('group_id',)
+
+ def __init__(self):
+ self._callback: Optional[ItemCallbackType] = None
+ self._pass_view_arg = True
+ self.group_id: Optional[int] = None
+
+ def to_component_dict(self) -> Dict[str, Any]:
+ raise NotImplementedError
+
+ def copy(self: I) -> I:
+ raise NotImplementedError
+
+ def refresh_state(self, component: Component) -> None:
+ return None
+
+ @classmethod
+ def from_component(cls: Type[I], component: Component) -> I:
+ return cls()
+
+ @property
+ def type(self) -> ComponentType:
+ raise NotImplementedError
+
+ def is_dispatchable(self) -> bool:
+ return False
+
+ def __repr__(self) -> str:
+ attrs = ' '.join(f'{key}={getattr(self, key)!r}' for key in self.__item_repr_attributes__)
+ return f'<{self.__class__.__name__} {attrs}>'
+
+ @property
+ def callback(self) -> Optional[ItemCallbackType]:
+ """Returns the underlying callback associated with this interaction."""
+ return self._callback
+
+ @callback.setter
+ def callback(self, value: Optional[ItemCallbackType]):
+ if value is None:
+ self._callback = None
+ return
+
+ # Check if it's a partial function
+ try:
+ partial = value.func
+ except AttributeError:
+ pass
+ else:
+ if not inspect.iscoroutinefunction(value.func):
+ raise TypeError(f'inner partial function must be a coroutine')
+
+ # Check if the partial is bound
+ try:
+ bound_partial = partial.__self__
+ except AttributeError:
+ pass
+ else:
+ self._pass_view_arg = not hasattr(bound_partial, '__discord_ui_view__')
+
+ self._callback = value
+ return
+
+ try:
+ func_self = value.__self__
+ except AttributeError:
+ pass
+ else:
+ if not isinstance(func_self, Item):
+ raise TypeError(f'callback bound method must be from Item not {func_self!r}')
+ else:
+ value = value.__func__
+
+ if not inspect.iscoroutinefunction(value):
+ raise TypeError(f'callback must be a coroutine not {value!r}')
+
+ self._callback = value
+
+ async def _do_call(self, view: View, interaction: Interaction):
+ if self._pass_view_arg:
+ await self._callback(view, self, interaction)
+ else:
+ await self._callback(self, interaction) # type: ignore