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") )
This commit is contained in:
Dave Pearson
2022-11-01 09:13:29 +00:00
parent fcfd02aca2
commit 9e99f7a2c7
4 changed files with 31 additions and 39 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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")

View File

@@ -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.