From 9e99f7a2c74f19838bde9a003effed9e990349f8 Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Tue, 1 Nov 2022 09:13:29 +0000 Subject: [PATCH] Drop support for anonymous vs named widget mounting In the past App.mount and Widget.mount allowed you to do something like this: self.mount( Static("A"), Static("B"), c=Static("C"), d=Static("D") ) which would result in two widgets being mounted with no ID, and two widgets being mounted with assigned IDs, taken from the name of the keyword argument. It's been decided that this is unnecessary, especially given that the above can still be done (after this commit) like this: self.mount( Static("A"), Static("B"), Static("C", id="c"), Static("D", id="d") ) --- CHANGELOG.md | 8 ++++++++ src/textual/app.py | 40 ++++++++++++++++++---------------------- src/textual/dom.py | 7 +------ src/textual/widget.py | 15 ++++----------- 4 files changed, 31 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7465479be..548d6aede 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.4.0] - Unreleased + +### Changed + +- Dropped support for mounting "named" and "anonymous" widgets via + `App.mount` and `Widget.mount`. Both methods now simply take one or more + widgets as positional arguments. + ## [0.3.0] - 2022-10-31 ### Fixed diff --git a/src/textual/app.py b/src/textual/app.py index 9e96a4b94..7ea329ed4 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -822,27 +822,27 @@ class App(Generic[ReturnType], DOMNode): self._require_stylesheet_update.add(self.screen if node is None else node) self.check_idle() - def mount(self, *anon_widgets: Widget, **widgets: Widget) -> AwaitMount: - """Mount widgets. Widgets specified as positional args, or keywords args. If supplied - as keyword args they will be assigned an id of the key. + def mount(self, *widgets: Widget) -> AwaitMount: + """Mount the given widgets. + + Args: + *widgets (Widget): The widget(s) to mount. Returns: AwaitMount: An awaitable object that waits for widgets to be mounted. - """ - mounted_widgets = self._register(self.screen, *anon_widgets, **widgets) - return AwaitMount(mounted_widgets) + return AwaitMount(self._register(self.screen, *widgets)) def mount_all(self, widgets: Iterable[Widget]) -> AwaitMount: """Mount widgets from an iterable. Args: widgets (Iterable[Widget]): An iterable of widgets. + + Returns: + AwaitMount: An awaitable object that waits for widgets to be mounted. """ - mounted_widgets = list(widgets) - for widget in mounted_widgets: - self._register(self.screen, widget) - return AwaitMount(mounted_widgets) + return self.mount(*widgets) def is_screen_installed(self, screen: Screen | str) -> bool: """Check if a given screen has been installed. @@ -1300,37 +1300,33 @@ class App(Generic[ReturnType], DOMNode): return True return False - def _register( - self, parent: DOMNode, *anon_widgets: Widget, **widgets: Widget - ) -> list[Widget]: + def _register(self, parent: DOMNode, *widgets: Widget) -> list[Widget]: """Register widget(s) so they may receive events. Args: - parent (Widget): Parent Widget. + parent (DOMNode): Parent node. + *widgets: The widget(s) to register. Returns: list[Widget]: List of modified widgets. """ - if not anon_widgets and not widgets: + + if not widgets: return [] - name_widgets: list[tuple[str | None, Widget]] - name_widgets = [*((None, widget) for widget in anon_widgets), *widgets.items()] + apply_stylesheet = self.stylesheet.apply - for widget_id, widget in name_widgets: + for widget in widgets: if not isinstance(widget, Widget): raise AppError(f"Can't register {widget!r}; expected a Widget instance") if widget not in self._registry: - if widget_id is not None: - widget.id = widget_id self._register_child(parent, widget) if widget.children: self._register(widget, *widget.children) apply_stylesheet(widget) - registered_widgets = [widget for _, widget in name_widgets] - return registered_widgets + return list(widgets) def _unregister(self, widget: Widget) -> None: """Unregister a widget. diff --git a/src/textual/dom.py b/src/textual/dom.py index 89cd3b95b..aa8f9a1b4 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -609,21 +609,16 @@ class DOMNode(MessagePump): self.children._append(node) node._attach(self) - def _add_children(self, *nodes: Widget, **named_nodes: Widget) -> None: + def _add_children(self, *nodes: Widget) -> None: """Add multiple children to this node. Args: *nodes (DOMNode): Positional args should be new DOM nodes. - **named_nodes (DOMNode): Keyword args will be assigned the argument name as an ID. """ _append = self.children._append for node in nodes: node._attach(self) _append(node) - for node_id, node in named_nodes.items(): - node._attach(self) - _append(node) - node.id = node_id WalkType = TypeVar("WalkType") diff --git a/src/textual/widget.py b/src/textual/widget.py index 13fd2ab5b..9d1f50bb2 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -375,23 +375,16 @@ class Widget(DOMNode): if self._scrollbar_corner is not None: yield self._scrollbar_corner - def mount(self, *anon_widgets: Widget, **widgets: Widget) -> AwaitMount: + def mount(self, *widgets: Widget) -> AwaitMount: """Mount child widgets (making this widget a container). - Widgets may be passed as positional arguments or keyword arguments. If keyword arguments, - the keys will be set as the Widget's id. - - Example: - ```python - self.mount(Static("hello"), header=Header()) - ``` + Args: + *widgets (Widget): The widget(s) to mount. Returns: AwaitMount: An awaitable object that waits for widgets to be mounted. - """ - mounted_widgets = self.app._register(self, *anon_widgets, **widgets) - return AwaitMount(mounted_widgets) + return AwaitMount(self.app._register(self, *widgets)) def compose(self) -> ComposeResult: """Called by Textual to create child widgets.