Skip to content

Commit

Permalink
Roll back ALLOW_CHILDREN and max height fix (#3814)
Browse files Browse the repository at this point in the history
* max height

* changelog

* snapshot

* unused exception
  • Loading branch information
willmcgugan authored Dec 7, 2023
1 parent 4f459d6 commit 82d6e3e
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 36 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Removed renderables/align.py which was no longer used

### Changed

- Dropped ALLOW_CHILDREN flag introduced in 0.43.0 https://github.com/Textualize/textual/pull/3814
- Widgets with an auto height in an auto height container will now expand if they have no siblings https://github.com/Textualize/textual/pull/3814

### Added

- Added `get_loading_widget` to Widget and App customize the loading widget. https://github.com/Textualize/textual/pull/3816
Expand Down
12 changes: 11 additions & 1 deletion src/textual/_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,17 @@ def get_content_height(
height = 0
else:
# Use a height of zero to ignore relative heights
arrangement = widget._arrange(Size(width, 0))
styles_height = widget.styles.height
if widget._parent and len(widget._nodes) == 1:
# If it is an only child with height auto we want it to expand
height = (
container.height
if styles_height is not None and styles_height.is_auto
else 0
)
else:
height = 0
arrangement = widget._arrange(Size(width, height))
height = arrangement.total_region.bottom

return height
Expand Down
2 changes: 0 additions & 2 deletions src/textual/scroll_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ class ScrollView(ScrollableContainer):
on the compositor to render children).
"""

ALLOW_CHILDREN = False

DEFAULT_CSS = """
ScrollView {
overflow-y: auto;
Expand Down
9 changes: 0 additions & 9 deletions src/textual/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@
}


class NotAContainer(Exception):
"""Exception raised if you attempt to add a child to a widget which doesn't permit child nodes."""


_NULL_STYLE = Style()


Expand Down Expand Up @@ -267,9 +263,6 @@ class Widget(DOMNode):
BORDER_SUBTITLE: ClassVar[str] = ""
"""Initial value for border_subtitle attribute."""

ALLOW_CHILDREN: ClassVar[bool] = True
"""Set to `False` to prevent adding children to this widget."""

can_focus: bool = False
"""Widget may receive focus."""
can_focus_children: bool = True
Expand Down Expand Up @@ -518,8 +511,6 @@ def compose_add_child(self, widget: Widget) -> None:
widget: A Widget to add.
"""
_rich_traceback_omit = True
if not self.ALLOW_CHILDREN:
raise NotAContainer(f"Can't add children to {type(widget)} widgets")
self._nodes._append(widget)

def __enter__(self) -> Self:
Expand Down
2 changes: 0 additions & 2 deletions src/textual/widgets/_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,6 @@ class Button(Widget, can_focus=True):

BINDINGS = [Binding("enter", "press", "Press Button", show=False)]

ALLOW_CHILDREN = False

label: reactive[TextType] = reactive[TextType]("")
"""The text label that appears within the button."""

Expand Down
2 changes: 0 additions & 2 deletions src/textual/widgets/_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ class Static(Widget, inherit_bindings=False):
}
"""

ALLOW_CHILDREN = False

_renderable: RenderableType

def __init__(
Expand Down
2 changes: 0 additions & 2 deletions src/textual/widgets/_toggle_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ class ToggleButton(Static, can_focus=True):
| `toggle--label` | Targets the text label of the toggle button. |
"""

ALLOW_CHILDREN = False

DEFAULT_CSS = """
ToggleButton {
width: auto;
Expand Down
158 changes: 158 additions & 0 deletions tests/snapshot_tests/__snapshots__/test_snapshots.ambr

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions tests/snapshot_tests/snapshot_apps/max_height_100.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from textual.app import App, ComposeResult
from textual.widgets import DataTable, Static


class HappyDataTableFunApp(App[None]):
"""The DataTable should expand as if it has height 1fr."""

CSS = """
DataTable {
max-height: 100%;
}
"""

def populate(self, table: DataTable) -> DataTable:
for n in range(20):
table.add_column(f"Column {n}")
for row in range(100):
table.add_row(*[str(row * n) for n in range(20)])
return table

def compose(self) -> ComposeResult:
with Static(id="s"):
yield self.populate(DataTable())


if __name__ == "__main__":
HappyDataTableFunApp().run()
5 changes: 5 additions & 0 deletions tests/snapshot_tests/test_snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,10 @@ def test_vertical_max_height(snap_compare):
assert snap_compare(SNAPSHOT_APPS_DIR / "vertical_max_height.py")


def test_max_height_100(snap_compare):
"""Test vertical max height takes border in to account."""
assert snap_compare(SNAPSHOT_APPS_DIR / "max_height_100.py")

def test_loading_indicator(snap_compare):
"""Test loading indicator."""
# https://github.com/Textualize/textual/pull/3816
Expand All @@ -949,3 +953,4 @@ def test_loading_indicator_disables_widget(snap_compare):
assert snap_compare(
SNAPSHOT_APPS_DIR / "loading.py", press=["space", "down", "down", "space"]
)

20 changes: 2 additions & 18 deletions tests/test_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
from textual.css.query import NoMatches
from textual.geometry import Offset, Size
from textual.message import Message
from textual.widget import MountError, NotAContainer, PseudoClasses, Widget
from textual.widgets import Label, LoadingIndicator, Static
from textual.widget import MountError, PseudoClasses, Widget
from textual.widgets import Label, LoadingIndicator


@pytest.mark.parametrize(
Expand Down Expand Up @@ -396,22 +396,6 @@ class TestWidgetIsMountedApp(App):
assert widget.is_mounted is True


async def test_not_allow_children():
"""Regression test for https://github.com/Textualize/textual/pull/3758"""

class TestAppExpectFail(App):
def compose(self) -> ComposeResult:
# Statics don't have children, so this should error
with Static():
yield Label("foo")

app = TestAppExpectFail()

with pytest.raises(NotAContainer):
async with app.run_test():
pass


async def test_mount_error_not_widget():
class NotWidgetApp(App):
def compose(self) -> ComposeResult:
Expand Down

0 comments on commit 82d6e3e

Please sign in to comment.