mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-07-06 18:11:59 +00:00
Change View.children to be a property
This allows users to call remove_item in a loop. Likewise, it prevents the footgun of doing children.append(...) which does not uphold the invariants with the weight system.
This commit is contained in:
parent
d5d9a532b2
commit
1458251736
@ -89,8 +89,6 @@ class Modal(View):
|
|||||||
------------
|
------------
|
||||||
title: :class:`str`
|
title: :class:`str`
|
||||||
The title of the modal.
|
The title of the modal.
|
||||||
children: List[:class:`Item`]
|
|
||||||
The list of children attached to this view.
|
|
||||||
custom_id: :class:`str`
|
custom_id: :class:`str`
|
||||||
The ID of the modal that gets received during an interaction.
|
The ID of the modal that gets received during an interaction.
|
||||||
"""
|
"""
|
||||||
@ -172,7 +170,7 @@ class Modal(View):
|
|||||||
if component['type'] == 1:
|
if component['type'] == 1:
|
||||||
self._refresh(component['components'])
|
self._refresh(component['components'])
|
||||||
else:
|
else:
|
||||||
item = find(lambda i: i.custom_id == component['custom_id'], self.children) # type: ignore
|
item = find(lambda i: i.custom_id == component['custom_id'], self._children) # type: ignore
|
||||||
if item is None:
|
if item is None:
|
||||||
_log.debug("Modal interaction referencing unknown item custom_id %s. Discarding", component['custom_id'])
|
_log.debug("Modal interaction referencing unknown item custom_id %s. Discarding", component['custom_id'])
|
||||||
continue
|
continue
|
||||||
|
@ -151,11 +151,6 @@ class View:
|
|||||||
timeout: Optional[:class:`float`]
|
timeout: Optional[:class:`float`]
|
||||||
Timeout in seconds from last interaction with the UI before no longer accepting input.
|
Timeout in seconds from last interaction with the UI before no longer accepting input.
|
||||||
If ``None`` then there is no timeout.
|
If ``None`` then there is no timeout.
|
||||||
|
|
||||||
Attributes
|
|
||||||
------------
|
|
||||||
children: List[:class:`Item`]
|
|
||||||
The list of children attached to this view.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__discord_ui_view__: ClassVar[bool] = True
|
__discord_ui_view__: ClassVar[bool] = True
|
||||||
@ -186,8 +181,8 @@ class View:
|
|||||||
|
|
||||||
def __init__(self, *, timeout: Optional[float] = 180.0):
|
def __init__(self, *, timeout: Optional[float] = 180.0):
|
||||||
self.__timeout = timeout
|
self.__timeout = timeout
|
||||||
self.children: List[Item[Self]] = self._init_children()
|
self._children: List[Item[Self]] = self._init_children()
|
||||||
self.__weights = _ViewWeights(self.children)
|
self.__weights = _ViewWeights(self._children)
|
||||||
self.id: str = os.urandom(16).hex()
|
self.id: str = os.urandom(16).hex()
|
||||||
self.__cancel_callback: Optional[Callable[[View], None]] = None
|
self.__cancel_callback: Optional[Callable[[View], None]] = None
|
||||||
self.__timeout_expiry: Optional[float] = None
|
self.__timeout_expiry: Optional[float] = None
|
||||||
@ -195,7 +190,7 @@ class View:
|
|||||||
self.__stopped: asyncio.Future[bool] = asyncio.get_running_loop().create_future()
|
self.__stopped: asyncio.Future[bool] = asyncio.get_running_loop().create_future()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'<{self.__class__.__name__} timeout={self.timeout} children={len(self.children)}>'
|
return f'<{self.__class__.__name__} timeout={self.timeout} children={len(self._children)}>'
|
||||||
|
|
||||||
async def __timeout_task_impl(self) -> None:
|
async def __timeout_task_impl(self) -> None:
|
||||||
while True:
|
while True:
|
||||||
@ -218,7 +213,7 @@ class View:
|
|||||||
def key(item: Item) -> int:
|
def key(item: Item) -> int:
|
||||||
return item._rendered_row or 0
|
return item._rendered_row or 0
|
||||||
|
|
||||||
children = sorted(self.children, key=key)
|
children = sorted(self._children, key=key)
|
||||||
components: List[Dict[str, Any]] = []
|
components: List[Dict[str, Any]] = []
|
||||||
for _, group in groupby(children, key=key):
|
for _, group in groupby(children, key=key):
|
||||||
children = [item.to_component_dict() for item in group]
|
children = [item.to_component_dict() for item in group]
|
||||||
@ -257,6 +252,11 @@ class View:
|
|||||||
|
|
||||||
self.__timeout = value
|
self.__timeout = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def children(self) -> List[Item[Self]]:
|
||||||
|
"""List[:class:`Item`]: The list of children attached to this view."""
|
||||||
|
return self._children.copy()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_message(cls, message: Message, /, *, timeout: Optional[float] = 180.0) -> View:
|
def from_message(cls, message: Message, /, *, timeout: Optional[float] = 180.0) -> View:
|
||||||
"""Converts a message's components into a :class:`View`.
|
"""Converts a message's components into a :class:`View`.
|
||||||
@ -304,7 +304,7 @@ class View:
|
|||||||
or the row the item is trying to be added to is full.
|
or the row the item is trying to be added to is full.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if len(self.children) > 25:
|
if len(self._children) > 25:
|
||||||
raise ValueError('maximum number of children exceeded')
|
raise ValueError('maximum number of children exceeded')
|
||||||
|
|
||||||
if not isinstance(item, Item):
|
if not isinstance(item, Item):
|
||||||
@ -313,7 +313,7 @@ class View:
|
|||||||
self.__weights.add_item(item)
|
self.__weights.add_item(item)
|
||||||
|
|
||||||
item._view = self
|
item._view = self
|
||||||
self.children.append(item)
|
self._children.append(item)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def remove_item(self, item: Item[Any]) -> Self:
|
def remove_item(self, item: Item[Any]) -> Self:
|
||||||
@ -329,7 +329,7 @@ class View:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.children.remove(item)
|
self._children.remove(item)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
@ -342,7 +342,7 @@ class View:
|
|||||||
This function returns the class instance to allow for fluent-style
|
This function returns the class instance to allow for fluent-style
|
||||||
chaining.
|
chaining.
|
||||||
"""
|
"""
|
||||||
self.children.clear()
|
self._children.clear()
|
||||||
self.__weights.clear()
|
self.__weights.clear()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -445,7 +445,7 @@ class View:
|
|||||||
# fmt: off
|
# fmt: off
|
||||||
old_state: Dict[Tuple[int, str], Item[Any]] = {
|
old_state: Dict[Tuple[int, str], Item[Any]] = {
|
||||||
(item.type.value, item.custom_id): item # type: ignore
|
(item.type.value, item.custom_id): item # type: ignore
|
||||||
for item in self.children
|
for item in self._children
|
||||||
if item.is_dispatchable()
|
if item.is_dispatchable()
|
||||||
}
|
}
|
||||||
# fmt: on
|
# fmt: on
|
||||||
@ -459,7 +459,7 @@ class View:
|
|||||||
older._refresh_component(component)
|
older._refresh_component(component)
|
||||||
children.append(older)
|
children.append(older)
|
||||||
|
|
||||||
self.children = children
|
self._children = children
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
"""Stops listening to interaction events from this view.
|
"""Stops listening to interaction events from this view.
|
||||||
@ -492,7 +492,7 @@ class View:
|
|||||||
A persistent view has all their components with a set ``custom_id`` and
|
A persistent view has all their components with a set ``custom_id`` and
|
||||||
a :attr:`timeout` set to ``None``.
|
a :attr:`timeout` set to ``None``.
|
||||||
"""
|
"""
|
||||||
return self.timeout is None and all(item.is_persistent() for item in self.children)
|
return self.timeout is None and all(item.is_persistent() for item in self._children)
|
||||||
|
|
||||||
async def wait(self) -> bool:
|
async def wait(self) -> bool:
|
||||||
"""Waits until the view has finished interacting.
|
"""Waits until the view has finished interacting.
|
||||||
@ -547,7 +547,7 @@ class ViewStore:
|
|||||||
|
|
||||||
self.__verify_integrity()
|
self.__verify_integrity()
|
||||||
|
|
||||||
for item in view.children:
|
for item in view._children:
|
||||||
if item.is_dispatchable():
|
if item.is_dispatchable():
|
||||||
self._views[(item.type.value, message_id, item.custom_id)] = (view, item) # type: ignore
|
self._views[(item.type.value, message_id, item.custom_id)] = (view, item) # type: ignore
|
||||||
|
|
||||||
@ -559,7 +559,7 @@ class ViewStore:
|
|||||||
self._modals.pop(view.custom_id, None) # type: ignore
|
self._modals.pop(view.custom_id, None) # type: ignore
|
||||||
return
|
return
|
||||||
|
|
||||||
for item in view.children:
|
for item in view._children:
|
||||||
if item.is_dispatchable():
|
if item.is_dispatchable():
|
||||||
self._views.pop((item.type.value, item.custom_id), None) # type: ignore
|
self._views.pop((item.type.value, item.custom_id), None) # type: ignore
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user