mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-11-20 15:51:30 +00:00
Fix container items having out of date internal state
This commit is contained in:
@@ -24,12 +24,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
ClassVar,
|
||||
Coroutine,
|
||||
Dict,
|
||||
Generator,
|
||||
List,
|
||||
@@ -42,7 +42,7 @@ from typing import (
|
||||
overload,
|
||||
)
|
||||
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType, _ItemCallback
|
||||
from .button import Button, button as _button
|
||||
from .select import select as _select, Select, UserSelect, RoleSelect, ChannelSelect, MentionableSelect
|
||||
from ..components import ActionRow as ActionRowComponent
|
||||
@@ -65,7 +65,6 @@ if TYPE_CHECKING:
|
||||
)
|
||||
from ..emoji import Emoji
|
||||
from ..components import SelectOption
|
||||
from ..interactions import Interaction
|
||||
from .container import Container
|
||||
from .dynamic import DynamicItem
|
||||
|
||||
@@ -77,18 +76,6 @@ V = TypeVar('V', bound='LayoutView', covariant=True)
|
||||
__all__ = ('ActionRow',)
|
||||
|
||||
|
||||
class _ActionRowCallback:
|
||||
__slots__ = ('row', 'callback', 'item')
|
||||
|
||||
def __init__(self, callback: ItemCallbackType[S, Any], row: ActionRow, item: Item[Any]) -> None:
|
||||
self.callback: ItemCallbackType[Any, Any] = callback
|
||||
self.row: ActionRow = row
|
||||
self.item: Item[Any] = item
|
||||
|
||||
def __call__(self, interaction: Interaction) -> Coroutine[Any, Any, Any]:
|
||||
return self.callback(self.row, interaction, self.item)
|
||||
|
||||
|
||||
class ActionRow(Item[V]):
|
||||
r"""Represents a UI action row.
|
||||
|
||||
@@ -143,8 +130,9 @@ class ActionRow(Item[V]):
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._children: List[Item[V]] = self._init_children()
|
||||
self._children.extend(children)
|
||||
self._weight: int = sum(i.width for i in self._children)
|
||||
for child in children:
|
||||
self.add_item(child)
|
||||
|
||||
if self._weight > 5:
|
||||
raise ValueError('maximum number of children exceeded')
|
||||
@@ -173,8 +161,8 @@ class ActionRow(Item[V]):
|
||||
|
||||
for func in self.__action_row_children_items__:
|
||||
item: Item = func.__discord_ui_model_type__(**func.__discord_ui_model_kwargs__)
|
||||
item.callback = _ActionRowCallback(func, self, item) # type: ignore
|
||||
item._parent = getattr(func, '__discord_ui_parent__', self)
|
||||
item.callback = _ItemCallback(func, self, item) # type: ignore
|
||||
item._parent = self
|
||||
setattr(self, func.__name__, item)
|
||||
children.append(item)
|
||||
return children
|
||||
@@ -184,6 +172,23 @@ class ActionRow(Item[V]):
|
||||
for child in self._children:
|
||||
child._view = view
|
||||
|
||||
def copy(self) -> ActionRow[V]:
|
||||
new = copy.copy(self)
|
||||
children = []
|
||||
for child in new._children:
|
||||
newch = child.copy()
|
||||
newch._parent = new
|
||||
if isinstance(newch.callback, _ItemCallback):
|
||||
newch.callback.parent = new
|
||||
children.append(newch)
|
||||
new._children = children
|
||||
new._parent = self._parent
|
||||
new._update_view(self.view)
|
||||
return new
|
||||
|
||||
def __deepcopy__(self, memo) -> ActionRow[V]:
|
||||
return self.copy()
|
||||
|
||||
def _has_children(self):
|
||||
return True
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import inspect
|
||||
import os
|
||||
|
||||
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType, _ItemCallback
|
||||
from ..enums import ButtonStyle, ComponentType
|
||||
from ..partial_emoji import PartialEmoji, _EmojiTag
|
||||
from ..components import Button as ButtonComponent
|
||||
@@ -304,6 +304,9 @@ class Button(Item[V]):
|
||||
sku_id=self.sku_id,
|
||||
id=self.id,
|
||||
)
|
||||
if isinstance(new.callback, _ItemCallback):
|
||||
new.callback.item = new
|
||||
new._update_view(self.view)
|
||||
return new
|
||||
|
||||
def __deepcopy__(self, memo) -> Self:
|
||||
|
||||
@@ -29,7 +29,6 @@ from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
ClassVar,
|
||||
Coroutine,
|
||||
Dict,
|
||||
Generator,
|
||||
List,
|
||||
@@ -39,7 +38,7 @@ from typing import (
|
||||
Union,
|
||||
)
|
||||
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType, _ItemCallback
|
||||
from .view import _component_to_item, LayoutView
|
||||
from ..enums import ComponentType
|
||||
from ..utils import get as _utils_get
|
||||
@@ -49,7 +48,6 @@ if TYPE_CHECKING:
|
||||
from typing_extensions import Self
|
||||
|
||||
from ..components import Container as ContainerComponent
|
||||
from ..interactions import Interaction
|
||||
from .dynamic import DynamicItem
|
||||
|
||||
S = TypeVar('S', bound='Container', covariant=True)
|
||||
@@ -58,18 +56,6 @@ V = TypeVar('V', bound='LayoutView', covariant=True)
|
||||
__all__ = ('Container',)
|
||||
|
||||
|
||||
class _ContainerCallback:
|
||||
__slots__ = ('container', 'callback', 'item')
|
||||
|
||||
def __init__(self, callback: ItemCallbackType[S, Any], container: Container, item: Item[Any]) -> None:
|
||||
self.callback: ItemCallbackType[Any, Any] = callback
|
||||
self.container: Container = container
|
||||
self.item: Item[Any] = item
|
||||
|
||||
def __call__(self, interaction: Interaction) -> Coroutine[Any, Any, Any]:
|
||||
return self.callback(self.container, interaction, self.item)
|
||||
|
||||
|
||||
class Container(Item[V]):
|
||||
r"""Represents a UI container.
|
||||
|
||||
@@ -163,7 +149,7 @@ class Container(Item[V]):
|
||||
# action rows can be created inside containers, and then callbacks can exist here
|
||||
# so we create items based off them
|
||||
item: Item = raw.__discord_ui_model_type__(**raw.__discord_ui_model_kwargs__)
|
||||
item.callback = _ContainerCallback(raw, self, item) # type: ignore
|
||||
item.callback = _ItemCallback(raw, self, item) # type: ignore
|
||||
setattr(self, raw.__name__, item)
|
||||
# this should not fail because in order for a function to be here it should be from
|
||||
# an action row and must have passed the check in __init_subclass__, but still
|
||||
@@ -196,6 +182,15 @@ class Container(Item[V]):
|
||||
child._update_view(view)
|
||||
return True
|
||||
|
||||
def copy(self) -> Container[V]:
|
||||
new = copy.deepcopy(self)
|
||||
for child in new._children:
|
||||
newch = child.copy()
|
||||
newch._parent = new
|
||||
new._parent = self._parent
|
||||
new._update_view(self.view)
|
||||
return new
|
||||
|
||||
def _has_children(self):
|
||||
return True
|
||||
|
||||
|
||||
@@ -55,6 +55,21 @@ ItemCallbackType = Callable[[V, Interaction[Any], I], Coroutine[Any, Any, Any]]
|
||||
ContainedItemCallbackType = Callable[[C, Interaction[Any], I], Coroutine[Any, Any, Any]]
|
||||
|
||||
|
||||
class _ItemCallback:
|
||||
__slots__ = ('parent', 'callback', 'item')
|
||||
|
||||
def __init__(self, callback: ContainedItemCallbackType[Any, Any], parent: Any, item: Item[Any]) -> None:
|
||||
self.callback: ItemCallbackType[Any, Any] = callback
|
||||
self.parent: Any = parent
|
||||
self.item: Item[Any] = item
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<ItemCallback callback={self.callback!r} parent={self.parent!r} item={self.item!r}>'
|
||||
|
||||
def __call__(self, interaction: Interaction) -> Coroutine[Any, Any, Any]:
|
||||
return self.callback(self.parent, interaction, self.item)
|
||||
|
||||
|
||||
class Item(Generic[V]):
|
||||
"""Represents the base UI item that all UI components inherit from.
|
||||
|
||||
|
||||
@@ -39,10 +39,11 @@ from typing import (
|
||||
Sequence,
|
||||
)
|
||||
from contextvars import ContextVar
|
||||
import copy
|
||||
import inspect
|
||||
import os
|
||||
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType
|
||||
from .item import Item, ContainedItemCallbackType as ItemCallbackType, _ItemCallback
|
||||
from ..enums import ChannelType, ComponentType, SelectDefaultValueType
|
||||
from ..partial_emoji import PartialEmoji
|
||||
from ..emoji import Emoji
|
||||
@@ -70,7 +71,7 @@ __all__ = (
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import TypeAlias, TypeGuard
|
||||
from typing_extensions import TypeAlias, TypeGuard, Self
|
||||
|
||||
from .view import BaseView
|
||||
from .action_row import ActionRow
|
||||
@@ -269,6 +270,14 @@ class BaseSelect(Item[V]):
|
||||
self.row = row
|
||||
self._values: List[PossibleValue] = []
|
||||
|
||||
def copy(self) -> Self:
|
||||
new = copy.copy(self)
|
||||
if isinstance(new.callback, _ItemCallback):
|
||||
new.callback.item = new
|
||||
new._parent = self._parent
|
||||
new._update_view(self.view)
|
||||
return new
|
||||
|
||||
@property
|
||||
def id(self) -> Optional[int]:
|
||||
"""Optional[:class:`int`]: The ID of this select."""
|
||||
|
||||
@@ -28,7 +28,6 @@ from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
ClassVar,
|
||||
Coroutine,
|
||||
Dict,
|
||||
Generator,
|
||||
Iterator,
|
||||
@@ -50,7 +49,7 @@ import sys
|
||||
import time
|
||||
import os
|
||||
|
||||
from .item import Item, ItemCallbackType
|
||||
from .item import Item, ItemCallbackType, _ItemCallback
|
||||
from .select import Select
|
||||
from .dynamic import DynamicItem
|
||||
from ..components import (
|
||||
@@ -207,18 +206,6 @@ class _ViewWeights:
|
||||
self.weights = [0, 0, 0, 0, 0]
|
||||
|
||||
|
||||
class _ViewCallback:
|
||||
__slots__ = ('view', 'callback', 'item')
|
||||
|
||||
def __init__(self, callback: ItemCallbackType[Any, Any], view: BaseView, item: Item[BaseView]) -> None:
|
||||
self.callback: ItemCallbackType[Any, Any] = callback
|
||||
self.view: BaseView = view
|
||||
self.item: Item[BaseView] = item
|
||||
|
||||
def __call__(self, interaction: Interaction) -> Coroutine[Any, Any, Any]:
|
||||
return self.callback(self.view, interaction, self.item)
|
||||
|
||||
|
||||
class BaseView:
|
||||
__discord_ui_view__: ClassVar[bool] = False
|
||||
__discord_ui_modal__: ClassVar[bool] = False
|
||||
@@ -252,13 +239,13 @@ class BaseView:
|
||||
item._update_view(self)
|
||||
parent = getattr(item, '__discord_ui_parent__', None)
|
||||
if parent and parent._view is None:
|
||||
parent._view = self
|
||||
parent._update_view(self)
|
||||
children.append(item)
|
||||
parents[raw] = item
|
||||
else:
|
||||
item: Item = raw.__discord_ui_model_type__(**raw.__discord_ui_model_kwargs__)
|
||||
item.callback = _ViewCallback(raw, self, item) # type: ignore
|
||||
item._view = self
|
||||
item.callback = _ItemCallback(raw, self, item) # type: ignore
|
||||
item._update_view(self)
|
||||
if isinstance(item, Select):
|
||||
item.options = [option.copy() for option in item.options]
|
||||
setattr(self, raw.__name__, item)
|
||||
|
||||
Reference in New Issue
Block a user