Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ These changes are available on the `master` branch, but have not yet been releas

### Fixed

- Fixed the `view` attribute on many view items being incorrect.
([#2981](https://github.com/Pycord-Development/pycord/pull/2981))

### Deprecated

- Deprecated manually setting the `view` attribute on view items.
([#2981](https://github.com/Pycord-Development/pycord/pull/2981))

### Removed

## [2.7.0rc2] - 2025-10-22
Expand Down
2 changes: 1 addition & 1 deletion discord/ui/action_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ def add_item(self, item: ViewItem) -> Self:
if self.width + item.width > 5:
raise ValueError(f"Not enough space left on this ActionRow")

item._view = self.view
item.parent = self

self.children.append(item)
Expand All @@ -162,6 +161,7 @@ def remove_item(self, item: ViewItem | str | int) -> Self:
self.children.remove(item)
except ValueError:
pass
item.parent = None
return self

def get_item(self, id: str | int) -> ViewItem | None:
Expand Down
6 changes: 2 additions & 4 deletions discord/ui/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,6 @@ def add_item(self, item: ViewItem) -> Self:
f"{item.__class__!r} cannot be added directly. Use ActionRow instead."
)

item._view = self.view
if hasattr(item, "items"):
item.view = self
item.parent = self

self.items.append(item)
Expand All @@ -170,12 +167,13 @@ def remove_item(self, item: ViewItem | str | int) -> Self:
if isinstance(item, (str, int)):
item = self.get_item(item)
try:
if isinstance(item, Container):
if item.parent is self:
self.items.remove(item)
else:
item.parent.remove_item(item)
except ValueError:
pass
item.parent = None
return self

def get_item(self, id: str | int) -> ViewItem | None:
Expand Down
15 changes: 12 additions & 3 deletions discord/ui/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
"ModalItem",
)

from ..utils import deprecated, warn_deprecated

if TYPE_CHECKING:
from ..components import Component
from ..enums import ComponentType
Expand Down Expand Up @@ -152,7 +154,7 @@ def __init__(self):
self._view: V | None = None
self._row: int | None = None
self._rendered_row: int | None = None
self.parent: ViewItem | BaseView | None = self.view
self.parent: ViewItem | BaseView | None = None

@property
def row(self) -> int | None:
Expand Down Expand Up @@ -208,10 +210,17 @@ def view(self) -> V | None:
Optional[:class:`BaseView`]
The parent view of this item, or ``None`` if the item is not attached to any view.
"""
return self._view
if self._view:
return self._view
if self.parent:
if isinstance(self.parent, BaseView):
return self.parent
return self.parent.view
return None

@view.setter
def view(self, value) -> None:
def view(self, value: V | None) -> None:
warn_deprecated("Manually setting .view", since="2.7", removed="2.8")
self._view = value

async def callback(self, interaction: Interaction):
Expand Down
11 changes: 2 additions & 9 deletions discord/ui/section.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ def remove_item(self, item: ViewItem | str | int) -> Self:
self.items.remove(item)
except ValueError:
pass
item.parent = None
return self

def get_item(self, id: int | str) -> ViewItem | None:
Expand Down Expand Up @@ -226,8 +227,7 @@ def set_accessory(self, item: ViewItem) -> Self:

if not isinstance(item, ViewItem):
raise TypeError(f"expected ViewItem not {item.__class__!r}")
if self.view:
item._view = self.view

item.parent = self

self.accessory = item
Expand Down Expand Up @@ -260,13 +260,6 @@ def set_thumbnail(

return self.set_accessory(thumbnail)

@ViewItem.view.setter
def view(self, value):
self._view = value
for item in self.walk_items():
item._view = value
item.parent = self

def copy_text(self) -> str:
"""Returns the text of all :class:`~discord.ui.TextDisplay` items in this section.
Equivalent to the `Copy Text` option on Discord clients.
Expand Down
10 changes: 6 additions & 4 deletions discord/ui/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,10 @@ def add_item(self, item: ViewItem[V]) -> Self:
raise TypeError(f"expected ViewItem not {item.__class__!r}")

item.parent = self
item._view = self
self.children.append(item)
return self

def remove_item(self, item: ViewItem[V] | int | str) -> None:
def remove_item(self, item: ViewItem[V] | int | str) -> Self:
"""Removes an item from the view. If an :class:`int` or :class:`str` is passed,
the item will be removed by ViewItem ``id`` or ``custom_id`` respectively.

Expand All @@ -252,16 +251,19 @@ def remove_item(self, item: ViewItem[V] | int | str) -> None:
if isinstance(item, (str, int)):
item = self.get_item(item)
try:
if isinstance(item.parent, BaseView):
if item.parent is self:
self.children.remove(item)
else:
item.parent.remove_item(item)
except ValueError:
pass
item.parent = None
return self

def clear_items(self) -> None:
def clear_items(self) -> Self:
"""Removes all items from this view."""
for child in self.children:
child.parent = None
self.children.clear()
return self

Expand Down