From 9a07491f3d88e44593a62d56de0e1c377062b782 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 11 Jun 2024 14:44:46 +0800 Subject: [PATCH 1/3] Correct the typing of SplitContainer content to be list/Sequence, not tuple. --- changes/2638.bugfix.rst | 1 + core/src/toga/widgets/splitcontainer.py | 18 ++++++++---------- core/tests/widgets/test_splitcontainer.py | 18 +++++++++--------- .../api/containers/splitcontainer.rst | 6 +++--- 4 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 changes/2638.bugfix.rst diff --git a/changes/2638.bugfix.rst b/changes/2638.bugfix.rst new file mode 100644 index 0000000000..449610133f --- /dev/null +++ b/changes/2638.bugfix.rst @@ -0,0 +1 @@ +The type of SplitContainer's content was modified to be a list, rather than a tuple. diff --git a/core/src/toga/widgets/splitcontainer.py b/core/src/toga/widgets/splitcontainer.py index 04589bc737..62946b3cc4 100644 --- a/core/src/toga/widgets/splitcontainer.py +++ b/core/src/toga/widgets/splitcontainer.py @@ -1,7 +1,7 @@ from __future__ import annotations import sys -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Sequence from toga.app import App from toga.constants import Direction @@ -27,7 +27,7 @@ def __init__( id: str | None = None, style: StyleT | None = None, direction: Direction = Direction.VERTICAL, - content: tuple[SplitContainerContentT, SplitContainerContentT] = (None, None), + content: Sequence[SplitContainerContentT] = [None, None], ): """Create a new SplitContainer. @@ -42,10 +42,10 @@ def __init__( of the container. Defaults to both panels being empty. """ super().__init__(id=id, style=style) - self._content: tuple[SplitContainerContentT, SplitContainerContentT] = ( + self._content: Sequence[SplitContainerContentT] = [ None, None, - ) + ] # Create a platform specific implementation of a SplitContainer self._impl = self.factory.SplitContainer(interface=self) @@ -71,7 +71,7 @@ def focus(self) -> None: pass @property - def content(self) -> tuple[SplitContainerContentT, SplitContainerContentT]: + def content(self) -> Sequence[SplitContainerContentT]: """The widgets displayed in the SplitContainer. This property accepts a sequence of exactly 2 elements, each of which can be @@ -89,9 +89,7 @@ def content(self) -> tuple[SplitContainerContentT, SplitContainerContentT]: return self._content @content.setter - def content( - self, content: tuple[SplitContainerContentT, SplitContainerContentT] - ) -> None: + def content(self, content: Sequence[SplitContainerContentT]) -> None: try: if len(content) != 2: raise TypeError() @@ -128,10 +126,10 @@ def content( widget.window = self.window self._impl.set_content( - tuple(w._impl if w is not None else None for w in _content), + list(w._impl if w is not None else None for w in _content), flex, ) - self._content = tuple(_content) + self._content = list(_content) self.refresh() @Widget.app.setter diff --git a/core/tests/widgets/test_splitcontainer.py b/core/tests/widgets/test_splitcontainer.py index 62a61a0572..4d27599661 100644 --- a/core/tests/widgets/test_splitcontainer.py +++ b/core/tests/widgets/test_splitcontainer.py @@ -39,7 +39,7 @@ def test_widget_created(): assert splitcontainer._impl.interface == splitcontainer assert_action_performed(splitcontainer, "create SplitContainer") - assert splitcontainer.content == (None, None) + assert splitcontainer.content == [None, None] assert splitcontainer.direction == toga.SplitContainer.VERTICAL @@ -52,14 +52,14 @@ def test_widget_created_with_values(content1, content2): assert splitcontainer._impl.interface == splitcontainer assert_action_performed(splitcontainer, "create SplitContainer") - assert splitcontainer.content == (content1, content2) + assert splitcontainer.content == [content1, content2] assert splitcontainer.direction == toga.SplitContainer.HORIZONTAL # The content has been assigned to the widget assert_action_performed_with( splitcontainer, "set content", - content=(content1._impl, content2._impl), + content=[content1._impl, content2._impl], flex=[1, 1], ) @@ -212,10 +212,10 @@ def test_set_content_widgets( assert_action_performed_with( splitcontainer, "set content", - content=( + content=[ content2._impl if include_left else None, content3._impl if include_right else None, - ), + ], flex=[1, 1], ) @@ -248,10 +248,10 @@ def test_set_content_flex( assert_action_performed_with( splitcontainer, "set content", - content=( + content=[ content2._impl if include_left else None, content3._impl if include_right else None, - ), + ], flex=[2, 3], ) @@ -284,10 +284,10 @@ def test_set_content_flex_mixed( assert_action_performed_with( splitcontainer, "set content", - content=( + content=[ content2._impl if include_left else None, content3._impl if include_right else None, - ), + ], flex=[1, 3], ) diff --git a/docs/reference/api/containers/splitcontainer.rst b/docs/reference/api/containers/splitcontainer.rst index 6d04683daf..cbaaa8e563 100644 --- a/docs/reference/api/containers/splitcontainer.rst +++ b/docs/reference/api/containers/splitcontainer.rst @@ -49,7 +49,7 @@ Usage left_container = toga.Box() right_container = toga.ScrollContainer() - split = toga.SplitContainer(content=(left_container, right_container)) + split = toga.SplitContainer(content=[left_container, right_container]) Content can be specified when creating the widget, or after creation by assigning the ``content`` attribute. The direction of the split can also be configured, either @@ -65,7 +65,7 @@ at time of creation, or by setting the ``direction`` attribute: left_container = toga.Box() right_container = toga.ScrollContainer() - split.content = (left_container, right_container) + split.content = [left_container, right_container] By default, the space of the SplitContainer will be evenly divided between the two panels. To specify an uneven split, you can provide a flex value when specifying @@ -80,7 +80,7 @@ and right panels. left_container = toga.Box() right_container = toga.ScrollContainer() - split.content = ((left_container, 3), (right_container, 2)) + split.content = [(left_container, 3), (right_container, 2)] This only specifies the initial split; the split can be modified by the user once it is displayed. From aceaca33af6dd3c48a62eb6119906bb1542beba1 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 12 Jun 2024 05:54:17 +0800 Subject: [PATCH 2/3] Don't use a mutable container as a default. --- core/src/toga/widgets/splitcontainer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/toga/widgets/splitcontainer.py b/core/src/toga/widgets/splitcontainer.py index 62946b3cc4..c86a603460 100644 --- a/core/src/toga/widgets/splitcontainer.py +++ b/core/src/toga/widgets/splitcontainer.py @@ -27,7 +27,7 @@ def __init__( id: str | None = None, style: StyleT | None = None, direction: Direction = Direction.VERTICAL, - content: Sequence[SplitContainerContentT] = [None, None], + content: Sequence[SplitContainerContentT] | None = None, ): """Create a new SplitContainer. @@ -50,7 +50,8 @@ def __init__( # Create a platform specific implementation of a SplitContainer self._impl = self.factory.SplitContainer(interface=self) - self.content = content + if content: + self.content = content self.direction = direction @property From 8a0886f97155ee0e0c74c846c1a1bf9667e27e49 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 12 Jun 2024 07:44:19 +0800 Subject: [PATCH 3/3] Apply typing suggestions from @rmartin16 --- core/src/toga/widgets/splitcontainer.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/toga/widgets/splitcontainer.py b/core/src/toga/widgets/splitcontainer.py index c86a603460..5d76f2a24a 100644 --- a/core/src/toga/widgets/splitcontainer.py +++ b/core/src/toga/widgets/splitcontainer.py @@ -1,7 +1,8 @@ from __future__ import annotations import sys -from typing import TYPE_CHECKING, Sequence +from collections.abc import Sequence +from typing import TYPE_CHECKING from toga.app import App from toga.constants import Direction @@ -42,10 +43,7 @@ def __init__( of the container. Defaults to both panels being empty. """ super().__init__(id=id, style=style) - self._content: Sequence[SplitContainerContentT] = [ - None, - None, - ] + self._content: list[SplitContainerContentT] = [None, None] # Create a platform specific implementation of a SplitContainer self._impl = self.factory.SplitContainer(interface=self) @@ -72,7 +70,7 @@ def focus(self) -> None: pass @property - def content(self) -> Sequence[SplitContainerContentT]: + def content(self) -> list[SplitContainerContentT]: """The widgets displayed in the SplitContainer. This property accepts a sequence of exactly 2 elements, each of which can be