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