From 80f4c12e76f18da8a2f5133e5eadf03be7ff8d3d Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 24 Apr 2023 09:33:15 +0100 Subject: [PATCH 1/2] Fix scroll flicker (#2358) * fix scroll flicker * fix scroll flicker * remove event * do not delay scroll * remove comment * test fix * remove commented code * comment * increase pause on click * changelog [skip ci] * wait on resume * remove note [skip ci] --- CHANGELOG.md | 1 + src/textual/devtools/client.py | 4 ++-- src/textual/events.py | 9 --------- src/textual/message_pump.py | 2 ++ src/textual/pilot.py | 6 +++--- src/textual/screen.py | 20 ++++--------------- src/textual/scroll_view.py | 35 ++++++++++++++++++++++++++++++++++ src/textual/timer.py | 12 +++++------- tests/test_call_later.py | 2 +- 9 files changed, 53 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8ce08816..7b6164202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - `textual run` execs apps in a new context. +- Textual console no longer parses console markup. ### Added diff --git a/src/textual/devtools/client.py b/src/textual/devtools/client.py index 2982d07fe..1887d41ed 100644 --- a/src/textual/devtools/client.py +++ b/src/textual/devtools/client.py @@ -211,9 +211,9 @@ class DevtoolsClient: log: The log to write to devtools """ if isinstance(log.objects_or_string, str): - self.console.print(log.objects_or_string) + self.console.print(log.objects_or_string, markup=False) else: - self.console.print(*log.objects_or_string) + self.console.print(*log.objects_or_string, markup=False) segments = self.console.export_segments() diff --git a/src/textual/events.py b/src/textual/events.py index f2484b23d..fce28a6ea 100644 --- a/src/textual/events.py +++ b/src/textual/events.py @@ -50,15 +50,6 @@ class Callback(Event, bubble=False, verbose=True): yield "callback", self.callback -class InvokeCallbacks(Event, bubble=False, verbose=True): - """An internal event, sent to the screen to run callbacks. - - - [ ] Bubbles - - [X] Verbose - - """ - - class ShutdownRequest(Event): pass diff --git a/src/textual/message_pump.py b/src/textual/message_pump.py index 9d96f3d6a..34d691199 100644 --- a/src/textual/message_pump.py +++ b/src/textual/message_pump.py @@ -374,6 +374,7 @@ class MessagePump(metaclass=_MessagePumpMeta): **kwargs: Keyword arguments to pass to the callable. """ self._next_callbacks.append(partial(callback, *args, **kwargs)) + self.check_idle() def _on_invoke_later(self, message: messages.InvokeLater) -> None: # Forward InvokeLater message to the Screen @@ -506,6 +507,7 @@ class MessagePump(metaclass=_MessagePumpMeta): except Exception as error: self.app._handle_exception(error) break + await self._flush_next_callbacks() async def _flush_next_callbacks(self) -> None: """Invoke pending callbacks in next callbacks queue.""" diff --git a/src/textual/pilot.py b/src/textual/pilot.py index 68dcf8f25..cb18223f1 100644 --- a/src/textual/pilot.py +++ b/src/textual/pilot.py @@ -100,11 +100,11 @@ class Pilot(Generic[ReturnType]): target_widget, offset, button=1, shift=shift, meta=meta, control=control ) app.post_message(MouseDown(**message_arguments)) - await self.pause() + await self.pause(0.1) app.post_message(MouseUp(**message_arguments)) - await self.pause() + await self.pause(0.1) app.post_message(Click(**message_arguments)) - await self.pause() + await self.pause(0.1) async def hover( self, diff --git a/src/textual/screen.py b/src/textual/screen.py index b56213fbe..ddd832bfb 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -444,15 +444,12 @@ class Screen(Generic[ScreenResultType], Widget): or self._dirty_widgets ): self._update_timer.resume() + return - # The Screen is idle - a good opportunity to invoke the scheduled callbacks - - if self._callbacks: - self._on_timer_update() + await self._invoke_and_clear_callbacks() def _on_timer_update(self) -> None: """Called by the _update_timer.""" - self._update_timer.pause() if self.is_current: if self._layout_required: @@ -465,12 +462,11 @@ class Screen(Generic[ScreenResultType], Widget): self._scroll_required = False if self._repaint_required: - self._update_timer.resume() self._dirty_widgets.clear() self._dirty_widgets.add(self) self._repaint_required = False - if self._dirty_widgets and self.is_current: + if self._dirty_widgets: self._compositor.update_widgets(self._dirty_widgets) update = self._compositor.render_update( screen_stack=self.app._background_screens @@ -479,20 +475,12 @@ class Screen(Generic[ScreenResultType], Widget): self._dirty_widgets.clear() if self._callbacks: - self.post_message(events.InvokeCallbacks()) - - async def _on_invoke_callbacks(self, event: events.InvokeCallbacks) -> None: - """Handle PostScreenUpdate events, which are sent after the screen is updated""" - await self._invoke_and_clear_callbacks() + self.call_next(self._invoke_and_clear_callbacks) async def _invoke_and_clear_callbacks(self) -> None: """If there are scheduled callbacks to run, call them and clear the callback queue.""" if self._callbacks: - display_update = self._compositor.render_update( - screen_stack=self.app._background_screens - ) - self.app._display(self, display_update) callbacks = self._callbacks[:] self._callbacks.clear() for callback in callbacks: diff --git a/src/textual/scroll_view.py b/src/textual/scroll_view.py index 46dd934cb..63fd86a4e 100644 --- a/src/textual/scroll_view.py +++ b/src/textual/scroll_view.py @@ -7,6 +7,7 @@ from __future__ import annotations from rich.console import RenderableType +from ._animator import EasingFunction from .containers import ScrollableContainer from .geometry import Size @@ -111,3 +112,37 @@ class ScrollView(ScrollableContainer): from rich.panel import Panel return Panel(f"{self.scroll_offset} {self.show_vertical_scrollbar}") + + # Custom scroll to which doesn't require call_after_refresh + def scroll_to( + self, + x: float | None = None, + y: float | None = None, + *, + animate: bool = True, + speed: float | None = None, + duration: float | None = None, + easing: EasingFunction | str | None = None, + force: bool = False, + ) -> None: + """Scroll to a given (absolute) coordinate, optionally animating. + + Args: + x: X coordinate (column) to scroll to, or `None` for no change. + y: Y coordinate (row) to scroll to, or `None` for no change. + animate: Animate to new scroll position. + speed: Speed of scroll if `animate` is `True`; or `None` to use `duration`. + duration: Duration of animation, if `animate` is `True` and `speed` is `None`. + easing: An easing method for the scrolling animation. + force: Force scrolling even when prohibited by overflow styling. + """ + + self._scroll_to( + x, + y, + animate=animate, + speed=speed, + duration=duration, + easing=easing, + force=force, + ) diff --git a/src/textual/timer.py b/src/textual/timer.py index eae882bc9..c5c300266 100644 --- a/src/textual/timer.py +++ b/src/textual/timer.py @@ -131,20 +131,18 @@ class Timer: continue now = _time.get_time() wait_time = max(0, next_timer - now) - if wait_time > 1 / 1000: - await sleep(wait_time) - + await sleep(wait_time) count += 1 + try: + await self._tick(next_timer=next_timer, count=count) + except EventTargetGone: + break await self._active.wait() if self._reset: start = _time.get_time() count = 0 self._reset = False continue - try: - await self._tick(next_timer=next_timer, count=count) - except EventTargetGone: - break async def _tick(self, *, next_timer: float, count: int) -> None: """Triggers the Timer's action: either call its callback, or sends an event to its target""" diff --git a/tests/test_call_later.py b/tests/test_call_later.py index 506db93a5..98cdf4769 100644 --- a/tests/test_call_later.py +++ b/tests/test_call_later.py @@ -39,4 +39,4 @@ async def test_call_after_refresh() -> None: app.call_after_refresh(callback) await asyncio.wait_for(called_event.wait(), 1) app_display_count = app.display_count - assert app_display_count > display_count + assert app_display_count == display_count From e5033d7d23b045791f369f425e8b9975aa85fe1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?= <5621605+rodrigogiraoserrao@users.noreply.github.com> Date: Mon, 24 Apr 2023 11:21:38 +0100 Subject: [PATCH 2/2] Remove hanging lines from docstrings. (#2349) * Remove hanging lines from docstrings. Deleted hanging blank lines at the end of docstrings. Regex pattern: - find `\n\n( *)"""` - replace with `\n$1"""` --- docs/examples/getting_started/console.py | 2 -- .../layout/dock_layout3_sidebar_header.py | 2 +- docs/examples/widgets/markdown_viewer.py | 2 -- examples/code_browser.py | 1 - examples/five_by_five.py | 1 - src/textual/_animator.py | 1 - src/textual/_asyncio.py | 1 - src/textual/_cache.py | 2 -- src/textual/_compositor.py | 5 ---- src/textual/_duration.py | 1 - src/textual/_node_list.py | 1 - src/textual/_profile.py | 1 - src/textual/_spatial_map.py | 1 - src/textual/_styles_cache.py | 1 - src/textual/_win_sleep.py | 1 - src/textual/_work_decorator.py | 2 -- src/textual/_worker_manager.py | 3 -- src/textual/_xterm_parser.py | 1 - src/textual/app.py | 25 ---------------- src/textual/await_remove.py | 2 -- src/textual/binding.py | 1 - src/textual/cli/_run.py | 3 -- src/textual/cli/previews/easing.py | 1 - src/textual/color.py | 11 ------- src/textual/constants.py | 1 - src/textual/containers.py | 1 - src/textual/coordinate.py | 1 - src/textual/css/_style_properties.py | 2 -- src/textual/css/parse.py | 1 - src/textual/css/styles.py | 2 -- src/textual/css/stylesheet.py | 1 - src/textual/demo.py | 6 ---- src/textual/design.py | 5 ---- src/textual/dom.py | 20 ------------- src/textual/events.py | 30 ------------------- src/textual/geometry.py | 11 ------- src/textual/layouts/grid.py | 1 - src/textual/logging.py | 1 - src/textual/message.py | 2 -- src/textual/message_pump.py | 4 --- src/textual/pilot.py | 2 -- src/textual/reactive.py | 2 -- src/textual/renderables/text_opacity.py | 1 - src/textual/renderables/tint.py | 1 - src/textual/screen.py | 3 -- src/textual/scroll_view.py | 2 -- src/textual/timer.py | 2 -- src/textual/walk.py | 3 -- src/textual/widget.py | 23 -------------- src/textual/widgets/_button.py | 1 - src/textual/widgets/_markdown.py | 4 --- src/textual/widgets/_placeholder.py | 1 - src/textual/widgets/_tabbed_content.py | 1 - src/textual/widgets/_tabs.py | 1 - src/textual/widgets/_tree.py | 1 - src/textual/widgets/_welcome.py | 1 - src/textual/worker.py | 5 ---- .../snapshot_apps/scrollbar_thumb_height.py | 1 - tests/test_animation.py | 1 - tests/utilities/render.py | 1 - 60 files changed, 1 insertion(+), 217 deletions(-) diff --git a/docs/examples/getting_started/console.py b/docs/examples/getting_started/console.py index 051632d9f..507e6aac7 100644 --- a/docs/examples/getting_started/console.py +++ b/docs/examples/getting_started/console.py @@ -1,10 +1,8 @@ """ Simulates a screenshot of the Textual devtools - """ from textual.app import App - from textual.devtools.renderables import DevConsoleHeader from textual.widgets import Static diff --git a/docs/examples/guide/layout/dock_layout3_sidebar_header.py b/docs/examples/guide/layout/dock_layout3_sidebar_header.py index 5967bda7f..076e57c2a 100644 --- a/docs/examples/guide/layout/dock_layout3_sidebar_header.py +++ b/docs/examples/guide/layout/dock_layout3_sidebar_header.py @@ -1,5 +1,5 @@ from textual.app import App, ComposeResult -from textual.widgets import Static, Header +from textual.widgets import Header, Static TEXT = """\ Docking a widget removes it from the layout and fixes its position, aligned to either the top, right, bottom, or left edges of a container. diff --git a/docs/examples/widgets/markdown_viewer.py b/docs/examples/widgets/markdown_viewer.py index d8dbf6091..13843905a 100644 --- a/docs/examples/widgets/markdown_viewer.py +++ b/docs/examples/widgets/markdown_viewer.py @@ -45,8 +45,6 @@ class ListViewExample(App): ) yield Footer() ``` - - """ diff --git a/examples/code_browser.py b/examples/code_browser.py index 13fdf3c6d..d393be3c3 100644 --- a/examples/code_browser.py +++ b/examples/code_browser.py @@ -4,7 +4,6 @@ Code browser example. Run with: python code_browser.py PATH - """ import sys diff --git a/examples/five_by_five.py b/examples/five_by_five.py index c89bea49e..11e3f1e1f 100644 --- a/examples/five_by_five.py +++ b/examples/five_by_five.py @@ -131,7 +131,6 @@ class GameCell(Button): Args: row (int): The row of the cell. col (int): The column of the cell. - """ super().__init__("", id=self.at(row, col)) self.row = row diff --git a/src/textual/_animator.py b/src/textual/_animator.py index 8c7572446..e213e25eb 100644 --- a/src/textual/_animator.py +++ b/src/textual/_animator.py @@ -144,7 +144,6 @@ class BoundAnimator: delay: A delay (in seconds) before the animation starts. easing: An easing method. on_complete: A callable to invoke when the animation is finished. - """ start_value = getattr(self._obj, attribute) if isinstance(value, str) and hasattr(start_value, "parse"): diff --git a/src/textual/_asyncio.py b/src/textual/_asyncio.py index ea9bf0835..351ff650d 100644 --- a/src/textual/_asyncio.py +++ b/src/textual/_asyncio.py @@ -1,6 +1,5 @@ """ Compatibility layer for asyncio. - """ from __future__ import annotations diff --git a/src/textual/_cache.py b/src/textual/_cache.py index 3b7fb8f72..33be132d1 100644 --- a/src/textual/_cache.py +++ b/src/textual/_cache.py @@ -9,7 +9,6 @@ Note that stdlib's @lru_cache is implemented in C and faster! It's best to use @lru_cache where you are caching things that are fairly quick and called many times. Use LRUCache where you want increased flexibility and you are caching slow operations where the overhead of the cache is a small fraction of the total processing time. - """ from __future__ import annotations @@ -35,7 +34,6 @@ class LRUCache(Generic[CacheKey, CacheValue]): Each entry is stored as [PREV, NEXT, KEY, VALUE] where PREV is a reference to the previous entry, and NEXT is a reference to the next value. - """ __slots__ = [ diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index 76bb223e4..1ec7f5c2a 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -8,7 +8,6 @@ queries regarding the widget under an offset, or the style under an offset. Additionally, the compositor can render portions of the screen which may have updated, without having to render the entire screen. - """ from __future__ import annotations @@ -410,7 +409,6 @@ class Compositor: Returns: Set of widgets that were exposed by the scroll. - """ self._cuts = None self._layers = None @@ -790,7 +788,6 @@ class Compositor: Returns: Widget's composition information. - """ if self.root is None: raise errors.NoWidget("Widget is not in layout") @@ -932,7 +929,6 @@ class Compositor: Returns: A ChopsUpdate if there is anything to update, otherwise `None`. - """ screen_region = self.size.region update_regions = self._dirty_regions.copy() @@ -1019,7 +1015,6 @@ class Compositor: Args: widgets: Set of Widgets to update. - """ # If there are any *new* widgets we need to invalidate the full map if not self._full_map_invalidated and not widgets.issubset( diff --git a/src/textual/_duration.py b/src/textual/_duration.py index 998363ffb..bba4da0a9 100644 --- a/src/textual/_duration.py +++ b/src/textual/_duration.py @@ -25,7 +25,6 @@ def _duration_as_seconds(duration: str) -> float: DurationParseError: If the argument ``duration`` is not a valid duration string. Returns: The duration in seconds. - """ match = _match_duration(duration) diff --git a/src/textual/_node_list.py b/src/textual/_node_list.py index d5e4051cb..695276f99 100644 --- a/src/textual/_node_list.py +++ b/src/textual/_node_list.py @@ -19,7 +19,6 @@ class NodeList(Sequence["Widget"]): A container for widgets that forms one level of hierarchy. Although named a list, widgets may appear only once, making them more like a set. - """ def __init__(self) -> None: diff --git a/src/textual/_profile.py b/src/textual/_profile.py index 4a0199a6f..96bf99ee5 100644 --- a/src/textual/_profile.py +++ b/src/textual/_profile.py @@ -1,6 +1,5 @@ """ Timer context manager, only used in debug. - """ import contextlib diff --git a/src/textual/_spatial_map.py b/src/textual/_spatial_map.py index 93e8c4004..48b96ab39 100644 --- a/src/textual/_spatial_map.py +++ b/src/textual/_spatial_map.py @@ -21,7 +21,6 @@ class SpatialMap(Generic[ValueType]): The SpatialMap is able to quickly retrieve the values under a given "window" region by combining the values in the grid squares under the visible area. - """ def __init__(self, grid_width: int = 100, grid_height: int = 20) -> None: diff --git a/src/textual/_styles_cache.py b/src/textual/_styles_cache.py index 46027383e..a10170111 100644 --- a/src/textual/_styles_cache.py +++ b/src/textual/_styles_cache.py @@ -65,7 +65,6 @@ class StylesCache: ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━┛ ``` - """ def __init__(self) -> None: diff --git a/src/textual/_win_sleep.py b/src/textual/_win_sleep.py index c8dd4517a..ae2400242 100644 --- a/src/textual/_win_sleep.py +++ b/src/textual/_win_sleep.py @@ -2,7 +2,6 @@ A version of `time.sleep` that is more accurate than the standard library (even on Python 3.11). This should only be imported on Windows. - """ from time import sleep as time_sleep diff --git a/src/textual/_work_decorator.py b/src/textual/_work_decorator.py index 97c5eb714..2b47848b9 100644 --- a/src/textual/_work_decorator.py +++ b/src/textual/_work_decorator.py @@ -1,7 +1,6 @@ """ A decorator used to create [workers](/guide/workers). - """ @@ -68,7 +67,6 @@ def work( group: A short string to identify a group of workers. exit_on_error: Exit the app if the worker raises an error. Set to `False` to suppress exceptions. exclusive: Cancel all workers in the same group. - """ def decorator( diff --git a/src/textual/_worker_manager.py b/src/textual/_worker_manager.py index 1508ef5b7..8b7b069e0 100644 --- a/src/textual/_worker_manager.py +++ b/src/textual/_worker_manager.py @@ -2,7 +2,6 @@ A class to manage [workers](/guide/workers) for an app. You access this object via [App.workers][textual.app.App.workers] or [Widget.workers][textual.dom.DOMNode.workers]. - """ @@ -28,7 +27,6 @@ class WorkerManager: You will not have to construct this class manually, as widgets, screens, and apps have a worker manager accessibly via a `workers` attribute. - """ def __init__(self, app: App) -> None: @@ -163,7 +161,6 @@ class WorkerManager: Returns: List of cancelled workers. - """ workers = [worker for worker in self._workers if worker.node == node] for worker in workers: diff --git a/src/textual/_xterm_parser.py b/src/textual/_xterm_parser.py index d3977bf45..edf587a3f 100644 --- a/src/textual/_xterm_parser.py +++ b/src/textual/_xterm_parser.py @@ -231,7 +231,6 @@ class XTermParser(Parser[events.Event]): Returns: Keys - """ keys = ANSI_SEQUENCES_KEYS.get(sequence) if keys is not None: diff --git a/src/textual/app.py b/src/textual/app.py index 5efe4e380..af59ce09e 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -3,7 +3,6 @@ Here you will find the [App][textual.app.App] class, which is the base class for Textual apps. See [app basics](/guide/app) for how to build Textual apps. - """ from __future__ import annotations @@ -248,7 +247,6 @@ class App(Generic[ReturnType], DOMNode): ```python self.app.dark = not self.app.dark # Toggle dark mode ``` - """ def __init__( @@ -403,7 +401,6 @@ class App(Generic[ReturnType], DOMNode): Returns: An object to manage workers. - """ return self._workers @@ -412,7 +409,6 @@ class App(Generic[ReturnType], DOMNode): """The return value of the app, or `None` if it as not yet been set. The return value is set when calling [exit][textual.app.App.exit]. - """ return self._return_value @@ -425,7 +421,6 @@ class App(Generic[ReturnType], DOMNode): Returns: A sequence of widgets. - """ try: return (self.screen,) @@ -477,7 +472,6 @@ class App(Generic[ReturnType], DOMNode): delay: A delay (in seconds) before the animation starts. easing: An easing method. on_complete: A callable to invoke when the animation is finished. - """ self._animate( attribute, @@ -500,7 +494,6 @@ class App(Generic[ReturnType], DOMNode): """Is the driver running in 'headless' mode? Headless mode is used when running tests with [run_test][textual.app.App.run_test]. - """ return False if self._driver is None else self._driver.is_headless @@ -510,7 +503,6 @@ class App(Generic[ReturnType], DOMNode): Returns: A snapshot of the current state of the screen stack. - """ return self._screen_stack.copy() @@ -537,7 +529,6 @@ class App(Generic[ReturnType], DOMNode): Returns: The currently focused widget, or `None` if nothing is focused. - """ return self.screen.focused @@ -553,7 +544,6 @@ class App(Generic[ReturnType], DOMNode): Returns: A mapping of keys on to node + binding. - """ namespace_binding_map: dict[str, tuple[DOMNode, Binding]] = {} @@ -571,7 +561,6 @@ class App(Generic[ReturnType], DOMNode): """Yield child widgets for a container. This method should be implemented in a subclass. - """ yield from () @@ -591,7 +580,6 @@ class App(Generic[ReturnType], DOMNode): This method handles the transition between light and dark mode when you change the [dark][textual.app.App.dark] attribute. - """ self.set_class(dark, "-dark-mode") self.set_class(not dark, "-light-mode") @@ -692,7 +680,6 @@ class App(Generic[ReturnType], DOMNode): Returns: Size of the terminal. - """ if self._driver is not None and self._driver._size is not None: width, height = self._driver._size @@ -712,7 +699,6 @@ class App(Generic[ReturnType], DOMNode): Returns: A Textual logger. - """ return self._logger @@ -837,7 +823,6 @@ class App(Generic[ReturnType], DOMNode): Args: title: The title of the exported screenshot or None to use app title. - """ assert self._driver is not None, "App must be running" width, height = self.size @@ -985,8 +970,6 @@ class App(Generic[ReturnType], DOMNode): headless: Run in headless mode (no output or input). size: Force terminal size to `(WIDTH, HEIGHT)`, or None to auto-detect. - - """ from .pilot import Pilot @@ -1364,7 +1347,6 @@ class App(Generic[ReturnType], DOMNode): Returns: A screen instance and an awaitable that awaits the children mounting. - """ _screen = self.get_screen(screen) if not _screen.is_running: @@ -1385,7 +1367,6 @@ class App(Generic[ReturnType], DOMNode): Returns: The screen that was replaced. - """ if self._screen_stack: self.screen.refresh() @@ -1432,7 +1413,6 @@ class App(Generic[ReturnType], DOMNode): Args: screen: Either a Screen object or screen name (the `name` argument when installed). - """ if not isinstance(screen, (Screen, str)): raise TypeError( @@ -1770,7 +1750,6 @@ class App(Generic[ReturnType], DOMNode): """Called immediately prior to processing messages. May be used as a hook for any operations that should run first. - """ async def take_screenshot() -> None: @@ -1859,7 +1838,6 @@ class App(Generic[ReturnType], DOMNode): after: A location to mount after. Returns: List of modified widgets. - """ if not widgets: @@ -2061,8 +2039,6 @@ class App(Generic[ReturnType], DOMNode): For terminals that support a bell, this typically makes a notification or error sound. Some terminals may make no sound or display a visual bell indicator, depending on configuration. - - """ if not self.is_headless and self._driver is not None: self._driver.write("\07") @@ -2345,7 +2321,6 @@ class App(Generic[ReturnType], DOMNode): Returns: The child widgets of root. - """ stack: list[Widget] = [root] pop = stack.pop diff --git a/src/textual/await_remove.py b/src/textual/await_remove.py index c879a289d..51ba810fc 100644 --- a/src/textual/await_remove.py +++ b/src/textual/await_remove.py @@ -1,8 +1,6 @@ """ An *optionally* awaitable object returned by methods that remove widgets. - - """ from asyncio import Event, Task diff --git a/src/textual/binding.py b/src/textual/binding.py index 4873b5211..36498fd20 100644 --- a/src/textual/binding.py +++ b/src/textual/binding.py @@ -3,7 +3,6 @@ A binding maps a key press on to an action. See [bindings](/guide/input#bindings) in the guide for details. - """ diff --git a/src/textual/cli/_run.py b/src/textual/cli/_run.py index b00818e85..327cacf34 100644 --- a/src/textual/cli/_run.py +++ b/src/textual/cli/_run.py @@ -4,7 +4,6 @@ Functions to run Textual apps with an updated environment. Note that these methods will execute apps in a new process, and abandon the current process. This means that (if they succeed) they will never return. - """ from __future__ import annotations @@ -98,7 +97,6 @@ def exec_python(args: list[str], environment: dict[str, str]) -> NoReturn: Args: args: Additional arguments. environment: Environment variables. - """ _flush() os.execvpe(sys.executable, ["python", *args], environment) @@ -148,7 +146,6 @@ def exec_import( import_name: The Python import. args: Command line arguments. environment: Environment variables. - """ module, _colon, app = import_name.partition(":") app = app or "app" diff --git a/src/textual/cli/previews/easing.py b/src/textual/cli/previews/easing.py index e593bbf93..68d7cb765 100644 --- a/src/textual/cli/previews/easing.py +++ b/src/textual/cli/previews/easing.py @@ -38,7 +38,6 @@ class Bar(Widget): background: $surface; color: $success; } - """ def watch_animation_running(self, running: bool) -> None: diff --git a/src/textual/color.py b/src/textual/color.py index ca1307500..a3fca9282 100644 --- a/src/textual/color.py +++ b/src/textual/color.py @@ -26,8 +26,6 @@ for name, triplet in sorted(COLOR_NAME_TO_RGB.items()): ) output = table ``` - - """ from __future__ import annotations @@ -158,7 +156,6 @@ class Color(NamedTuple): >>> color + color_with_alpha Color(177, 25, 12) ``` - """ r: int @@ -204,7 +201,6 @@ class Color(NamedTuple): Returns: Inverse color. - """ r, g, b, a = self return Color(255 - r, 255 - g, 255 - b, a) @@ -245,7 +241,6 @@ class Color(NamedTuple): Returns: Normalized components. - """ r, g, b, _a = self return (r / 255, g / 255, b / 255) @@ -264,7 +259,6 @@ class Color(NamedTuple): Returns: Color encoded in HSL format. - """ r, g, b = self.normalized h, l, s = rgb_to_hls(r, g, b) @@ -276,7 +270,6 @@ class Color(NamedTuple): A value of 1 is returned for pure white, and 0 for pure black. Other colors lie on a gradient between the two extremes. - """ r, g, b = self.normalized brightness = (299 * r + 587 * g + 114 * b) / 1000 @@ -287,7 +280,6 @@ class Color(NamedTuple): """The color in CSS hex form, with 6 digits for RGB, and 8 digits for RGBA. For example, `"#46b3de"` for an RGB color, or `"#3342457f"` for a color with alpha. - """ r, g, b, a = self.clamped return ( @@ -301,7 +293,6 @@ class Color(NamedTuple): """The color in CSS hex form, with 6 digits for RGB. Alpha is ignored. For example, `"#46b3de"`. - """ r, g, b, _a = self.clamped return f"#{r:02X}{g:02X}{b:02X}" @@ -311,7 +302,6 @@ class Color(NamedTuple): """The color in CSS RGB or RGBA form. For example, `"rgb(10,20,30)"` for an RGB color, or `"rgb(50,70,80,0.5)"` for an RGBA color. - """ r, g, b, a = self return f"rgb({r},{g},{b})" if a == 1 else f"rgba({r},{g},{b},{a})" @@ -322,7 +312,6 @@ class Color(NamedTuple): Returns: The monochrome (black and white) version of this color. - """ r, g, b, a = self gray = round(r * 0.2126 + g * 0.7152 + b * 0.0722) diff --git a/src/textual/constants.py b/src/textual/constants.py index eae559c9b..1ea0c8f3e 100644 --- a/src/textual/constants.py +++ b/src/textual/constants.py @@ -1,6 +1,5 @@ """ Constants that we might want to expose via the public API. - """ from __future__ import annotations diff --git a/src/textual/containers.py b/src/textual/containers.py index 54aa36d50..e2a1748f3 100644 --- a/src/textual/containers.py +++ b/src/textual/containers.py @@ -1,6 +1,5 @@ """ Container widgets for quick styling. - """ from __future__ import annotations diff --git a/src/textual/coordinate.py b/src/textual/coordinate.py index f36014ff6..a230df039 100644 --- a/src/textual/coordinate.py +++ b/src/textual/coordinate.py @@ -1,6 +1,5 @@ """ A class to store a coordinate, used by the [DataTable][textual.widgets.DataTable]. - """ from __future__ import annotations diff --git a/src/textual/css/_style_properties.py b/src/textual/css/_style_properties.py index 720dc5e7d..ff09e19eb 100644 --- a/src/textual/css/_style_properties.py +++ b/src/textual/css/_style_properties.py @@ -4,7 +4,6 @@ setting attributes. This gives the developer more freedom in how to express styl Descriptors also play nicely with Mypy, which is aware that attributes can have different types when setting and getting. - """ from __future__ import annotations @@ -383,7 +382,6 @@ class BorderProperty: Args: layout: True if the layout should be refreshed after setting, False otherwise. - """ def __init__(self, layout: bool) -> None: diff --git a/src/textual/css/parse.py b/src/textual/css/parse.py index 92dd6eacf..13aeea488 100644 --- a/src/textual/css/parse.py +++ b/src/textual/css/parse.py @@ -227,7 +227,6 @@ def _unresolved(variable_name: str, variables: Iterable[str], token: Token) -> N Raises: UnresolvedVariableError: Always raises a TokenError. - """ message = f"reference to undefined variable '${variable_name}'" suggested_variable = get_suggestion(variable_name, list(variables)) diff --git a/src/textual/css/styles.py b/src/textual/css/styles.py index 2dcbb181e..6eef8b1f1 100644 --- a/src/textual/css/styles.py +++ b/src/textual/css/styles.py @@ -770,7 +770,6 @@ class Styles(StylesBase): Returns: An iterable of CSS declarations. - """ has_rule = rules.__contains__ @@ -1119,7 +1118,6 @@ class RenderStyles(StylesBase): delay: A delay (in seconds) before the animation starts. easing: An easing method. on_complete: A callable to invoke when the animation is finished. - """ if self._animate is None: assert self.node is not None diff --git a/src/textual/css/stylesheet.py b/src/textual/css/stylesheet.py index e18265d92..c998de2c1 100644 --- a/src/textual/css/stylesheet.py +++ b/src/textual/css/stylesheet.py @@ -333,7 +333,6 @@ class Stylesheet: Raises: StylesheetError: If the CSS could not be read. StylesheetParseError: If the CSS is invalid. - """ # Do this in a fresh Stylesheet so if there are errors we don't break self. stylesheet = Stylesheet(variables=self._variables) diff --git a/src/textual/demo.py b/src/textual/demo.py index 750ffe079..86922aa59 100644 --- a/src/textual/demo.py +++ b/src/textual/demo.py @@ -72,7 +72,6 @@ WELCOME_MD = """ ## Textual Demo **Welcome**! Textual is a framework for creating sophisticated applications with the terminal. - """ @@ -83,8 +82,6 @@ Textual is built on **Rich**, the popular Python library for advanced terminal o Add content to your Textual App with Rich *renderables* (this text is written in Markdown and formatted with Rich's Markdown class). Here are some examples: - - """ CSS_MD = """ @@ -95,7 +92,6 @@ Textual uses Cascading Stylesheets (CSS) to create Rich interactive User Interfa - **Live editing** - see your changes without restarting the app! Here's an example of some CSS used in this app: - """ @@ -143,7 +139,6 @@ Build your own or use the builtin widgets. - **Tree** An generic tree with expandable nodes. - **DirectoryTree** A tree of file and folders. - *... many more planned ...* - """ @@ -160,7 +155,6 @@ Here are some links. You can click these! Built with ♥ by [@click="app.open_link('https://www.textualize.io')"]Textualize.io[/] - """ diff --git a/src/textual/design.py b/src/textual/design.py index 5bf8a6c6c..4d9dde719 100644 --- a/src/textual/design.py +++ b/src/textual/design.py @@ -25,8 +25,6 @@ class ColorSystem: Primary is the main theme color Secondary is a second theme color - - """ COLOR_NAMES = [ @@ -96,7 +94,6 @@ class ColorSystem: Returns: A mapping of color name on to a CSS-style encoded color - """ primary = self.primary @@ -134,7 +131,6 @@ class ColorSystem: Returns: Iterable of tuples () - """ luminosity_step = spread / 2 for n in range(-NUMBER_OF_SHADES, +NUMBER_OF_SHADES + 1): @@ -196,7 +192,6 @@ def show_design(light: ColorSystem, dark: ColorSystem) -> Table: Returns: Table showing all colors. - """ @group() diff --git a/src/textual/dom.py b/src/textual/dom.py index 430ebeb43..d292bc38d 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -2,8 +2,6 @@ A DOMNode is a base class for any object within the Textual Document Object Model, which includes all Widgets, Screens, and Apps. - - """ @@ -74,7 +72,6 @@ def check_identifiers(description: str, *names: str) -> None: Args: description: Description of where identifier is used for error message. *names: Identifiers to check. - """ match = _re_identifier.match for name in names: @@ -203,7 +200,6 @@ class DOMNode(MessagePump): Returns: The node's children. - """ return self._nodes @@ -328,7 +324,6 @@ class DOMNode(MessagePump): """Called after styles are updated. Implement this in a subclass if you want to clear any cached data when the CSS is reloaded. - """ @property @@ -450,7 +445,6 @@ class DOMNode(MessagePump): """The parent node. All nodes have parent once added to the DOM, with the exception of the App which is the *root* node. - """ return cast("DOMNode | None", self._parent) @@ -463,7 +457,6 @@ class DOMNode(MessagePump): Raises: NoScreen: If this node isn't mounted (and has no screen). - """ # Get the node by looking up a chain of parents # Note that self.screen may not be the same as self.app.screen @@ -490,7 +483,6 @@ class DOMNode(MessagePump): Raises: ValueError: If the ID has already been set. - """ check_identifiers("id", new_id) @@ -520,7 +512,6 @@ class DOMNode(MessagePump): Returns: A Rich Text object. - """ tokens = Text.styled(self.__class__.__name__) if self.id is not None: @@ -584,7 +575,6 @@ class DOMNode(MessagePump): ```python my_widget.display = False # Hide my_widget ``` - """ return self.styles.display != "none" and not (self._closing or self._closed) @@ -616,7 +606,6 @@ class DOMNode(MessagePump): May be set to a boolean to make the node visible (`True`) or invisible (`False`), or to any valid value for the `visibility` rule. When a node is invisible, Textual will reserve space for it, but won't display anything there. - """ return self.styles.visibility != "hidden" @@ -645,7 +634,6 @@ class DOMNode(MessagePump): Returns: A Tree renderable. - """ def render_info(node: DOMNode) -> Pretty: @@ -745,7 +733,6 @@ class DOMNode(MessagePump): Returns: A Rich style. - """ background = Color(0, 0, 0, 0) color = Color(255, 255, 255, 0) @@ -775,7 +762,6 @@ class DOMNode(MessagePump): Returns: A Rich style. - """ styles = self.styles if styles.auto_border_title_color: @@ -798,7 +784,6 @@ class DOMNode(MessagePump): Returns: A Rich style. - """ styles = self.styles if styles.auto_border_subtitle_color: @@ -817,7 +802,6 @@ class DOMNode(MessagePump): Returns: `(, )` - """ base_background = background = BLACK for node in reversed(self.ancestors_with_self): @@ -832,7 +816,6 @@ class DOMNode(MessagePump): Returns: `(, , , )` - """ base_background = background = WHITE base_color = color = BLACK @@ -873,7 +856,6 @@ class DOMNode(MessagePump): Returns: A list of nodes. - """ return self.ancestors_with_self[1:] @@ -883,7 +865,6 @@ class DOMNode(MessagePump): Returns: A list of nodes. - """ return [child for child in self._nodes if child.display] @@ -995,7 +976,6 @@ class DOMNode(MessagePump): Returns: A list of nodes. - """ check_type = filter_type or DOMNode diff --git a/src/textual/events.py b/src/textual/events.py index fce28a6ea..879c155b3 100644 --- a/src/textual/events.py +++ b/src/textual/events.py @@ -9,7 +9,6 @@ Verbose events are excluded from the textual console, unless you explicit reques ``` textual console -v ``` - """ from __future__ import annotations @@ -67,7 +66,6 @@ class Load(Event, bubble=False): - [ ] Bubbles - [ ] Verbose - """ @@ -79,7 +77,6 @@ class Idle(Event, bubble=False): - [ ] Bubbles - [ ] Verbose - """ @@ -104,7 +101,6 @@ class Resize(Event, bubble=False): size: The new size of the Widget. virtual_size: The virtual size (scrollable size) of the Widget. container_size: The size of the Widget's container widget. - """ __slots__ = ["size", "virtual_size", "container_size"] @@ -134,7 +130,6 @@ class Compose(Event, bubble=False, verbose=True): - [ ] Bubbles - [X] Verbose - """ @@ -143,7 +138,6 @@ class Mount(Event, bubble=False, verbose=False): - [ ] Bubbles - [ ] Verbose - """ @@ -152,7 +146,6 @@ class Unmount(Mount, bubble=False, verbose=False): - [ ] Bubbles - [ ] Verbose - """ @@ -161,7 +154,6 @@ class Show(Event, bubble=False): - [ ] Bubbles - [ ] Verbose - """ @@ -173,7 +165,6 @@ class Hide(Event, bubble=False): A widget may be hidden by setting its `visible` flag to `False`, if it is no longer in a layout, or if it has been offset beyond the edges of the terminal. - """ @@ -182,7 +173,6 @@ class Ready(Event, bubble=False): - [ ] Bubbles - [ ] Verbose - """ @@ -197,7 +187,6 @@ class MouseCapture(Event, bubble=False): Args: mouse_position: The position of the mouse when captured. - """ def __init__(self, mouse_position: Offset) -> None: @@ -309,7 +298,6 @@ class MouseEvent(InputEvent, bubble=True): screen_x: The absolute x coordinate. screen_y: The absolute y coordinate. style: The Rich Style under the mouse cursor. - """ __slots__ = [ @@ -390,7 +378,6 @@ class MouseEvent(InputEvent, bubble=True): Returns: Mouse coordinate. - """ return Offset(self.x, self.y) @@ -409,7 +396,6 @@ class MouseEvent(InputEvent, bubble=True): Returns: Mouse coordinate. - """ return Offset(self.delta_x, self.delta_y) @@ -457,7 +443,6 @@ class MouseMove(MouseEvent, bubble=False, verbose=True): - [ ] Bubbles - [X] Verbose - """ @@ -467,7 +452,6 @@ class MouseDown(MouseEvent, bubble=True, verbose=True): - [X] Bubbles - [X] Verbose - """ @@ -477,7 +461,6 @@ class MouseUp(MouseEvent, bubble=True, verbose=True): - [X] Bubbles - [X] Verbose - """ @@ -487,7 +470,6 @@ class MouseScrollDown(MouseEvent, bubble=True): - [X] Bubbles - [ ] Verbose - """ @@ -497,7 +479,6 @@ class MouseScrollUp(MouseEvent, bubble=True): - [X] Bubbles - [ ] Verbose - """ @@ -506,7 +487,6 @@ class Click(MouseEvent, bubble=True): - [X] Bubbles - [ ] Verbose - """ @@ -516,8 +496,6 @@ class Timer(Event, bubble=False, verbose=True): - [ ] Bubbles - [X] Verbose - - """ __slots__ = ["time", "count", "callback"] @@ -545,7 +523,6 @@ class Enter(Event, bubble=False, verbose=True): - [ ] Bubbles - [X] Verbose - """ @@ -554,7 +531,6 @@ class Leave(Event, bubble=False, verbose=True): - [ ] Bubbles - [X] Verbose - """ @@ -563,7 +539,6 @@ class Focus(Event, bubble=False): - [X] Bubbles - [ ] Verbose - """ @@ -572,7 +547,6 @@ class Blur(Event, bubble=False): - [X] Bubbles - [ ] Verbose - """ @@ -581,7 +555,6 @@ class DescendantFocus(Event, bubble=True, verbose=True): - [X] Bubbles - [X] Verbose - """ @@ -590,7 +563,6 @@ class DescendantBlur(Event, bubble=True, verbose=True): - [X] Bubbles - [X] Verbose - """ @@ -622,7 +594,6 @@ class ScreenResume(Event, bubble=False): - [ ] Bubbles - [ ] Verbose - """ @@ -631,5 +602,4 @@ class ScreenSuspend(Event, bubble=False): - [ ] Bubbles - [ ] Verbose - """ diff --git a/src/textual/geometry.py b/src/textual/geometry.py index 4ebb0e17f..fb1595815 100644 --- a/src/textual/geometry.py +++ b/src/textual/geometry.py @@ -1,7 +1,6 @@ """ Functions and classes to manage terminal geometry (anything involving coordinates or dimensions). - """ from __future__ import annotations @@ -75,7 +74,6 @@ class Offset(NamedTuple): >>> -offset Offset(x=-13, y=-2) ``` - """ x: int = 0 @@ -167,7 +165,6 @@ class Size(NamedTuple): >>> size + Size(10, 20) Size(width=12, height=23) ``` - """ width: int = 0 @@ -283,7 +280,6 @@ class Region(NamedTuple): >>> region.contains(10, 8) True ``` - """ x: int = 0 @@ -407,7 +403,6 @@ class Region(NamedTuple): """A pair of integers for the start and end columns (x coordinates) in this region. The end value is *exclusive*. - """ return (self.x, self.x + self.width) @@ -416,7 +411,6 @@ class Region(NamedTuple): """A pair of integers for the start and end lines (y coordinates) in this region. The end value is *exclusive*. - """ return (self.y, self.y + self.height) @@ -441,7 +435,6 @@ class Region(NamedTuple): Returns: An offset. - """ return Offset(*self[:2]) @@ -461,7 +454,6 @@ class Region(NamedTuple): Returns: An offset. - """ x, y, width, _height = self return Offset(x + width, y) @@ -472,7 +464,6 @@ class Region(NamedTuple): Returns: An offset. - """ x, y, width, height = self return Offset(x + width, y + height) @@ -504,7 +495,6 @@ class Region(NamedTuple): Returns: A region at the origin. - """ _, _, width, height = self return Region(0, 0, width, height) @@ -894,7 +884,6 @@ class Spacing(NamedTuple): >>> spacing.css '1 2 3 4' ``` - """ top: int = 0 diff --git a/src/textual/layouts/grid.py b/src/textual/layouts/grid.py index 10e5eaa06..3ade70ab2 100644 --- a/src/textual/layouts/grid.py +++ b/src/textual/layouts/grid.py @@ -34,7 +34,6 @@ class GridLayout(Layout): Args: column_count: Number of columns - """ row = 0 while True: diff --git a/src/textual/logging.py b/src/textual/logging.py index 6f73e62cf..4c2563a23 100644 --- a/src/textual/logging.py +++ b/src/textual/logging.py @@ -4,7 +4,6 @@ A Textual Logging handler. If there is an active Textual app, then log messages will go via the app (and logged via textual console). If there is *no* active app, then log messages will go to stderr or stdout, depending on configuration. - """ diff --git a/src/textual/message.py b/src/textual/message.py index 9ff65491b..2a706b448 100644 --- a/src/textual/message.py +++ b/src/textual/message.py @@ -1,8 +1,6 @@ """ The base class for all messages (including events). - - """ from __future__ import annotations diff --git a/src/textual/message_pump.py b/src/textual/message_pump.py index 34d691199..4a3b1a41c 100644 --- a/src/textual/message_pump.py +++ b/src/textual/message_pump.py @@ -1,7 +1,6 @@ """ A message pump is a base class for any object which processes messages, which includes Widget, Screen, and App. - """ from __future__ import annotations @@ -47,7 +46,6 @@ class MessagePumpClosed(Exception): class _MessagePumpMeta(type): """Metaclass for message pump. This exists to populate a Message inner class of a Widget with the parent classes' name. - """ def __new__( @@ -122,7 +120,6 @@ class MessagePump(metaclass=_MessagePumpMeta): with self.prevent(Input.Changed): input.value = "foo" ``` - """ if message_types: prevent_stack = self._prevent_message_types_stack @@ -547,7 +544,6 @@ class MessagePump(metaclass=_MessagePumpMeta): Args: method_name: Handler method name. message: Message object. - """ private_method = f"_{method_name}" for cls in self.__class__.__mro__: diff --git a/src/textual/pilot.py b/src/textual/pilot.py index cb18223f1..3fb68c7e4 100644 --- a/src/textual/pilot.py +++ b/src/textual/pilot.py @@ -1,7 +1,6 @@ """ The pilot object is used by [App.run_test][textual.app.App.run_test] to programmatically operate an app. - """ from __future__ import annotations @@ -63,7 +62,6 @@ class Pilot(Generic[ReturnType]): Args: *keys: Keys to press. - """ if keys: await self._app._press_keys(keys) diff --git a/src/textual/reactive.py b/src/textual/reactive.py index c02c28638..aa848bb73 100644 --- a/src/textual/reactive.py +++ b/src/textual/reactive.py @@ -1,7 +1,6 @@ """ The `Reactive` class implements [reactivity](/guide/reactivity/). - """ from __future__ import annotations @@ -227,7 +226,6 @@ class Reactive(Generic[ReactiveType]): watch_function: A watch function, which may be sync or async. old_value: The old value of the attribute. value: The new value of the attribute. - """ _rich_traceback_omit = True param_count = count_parameters(watch_function) diff --git a/src/textual/renderables/text_opacity.py b/src/textual/renderables/text_opacity.py index 1ec567020..12d50d7b9 100644 --- a/src/textual/renderables/text_opacity.py +++ b/src/textual/renderables/text_opacity.py @@ -57,7 +57,6 @@ class TextOpacity: Returns: Segments with applied opacity. - """ _Segment = Segment _from_color = Style.from_color diff --git a/src/textual/renderables/tint.py b/src/textual/renderables/tint.py index 90a8fabfe..ebdd38105 100644 --- a/src/textual/renderables/tint.py +++ b/src/textual/renderables/tint.py @@ -38,7 +38,6 @@ class Tint: Returns: Segments with applied tint. - """ from_rich_color = Color.from_rich_color style_from_color = Style.from_color diff --git a/src/textual/screen.py b/src/textual/screen.py index ddd832bfb..8f9528c56 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -1,7 +1,6 @@ """ The `Screen` class is a special widget which represents the content in the terminal. See [Screens](/guide/screens/) for details. - """ from __future__ import annotations @@ -745,8 +744,6 @@ class ModalScreen(Screen[ScreenResultType]): """A screen with bindings that take precedence over the App's key bindings. The default styling of a modal screen will dim the screen underneath. - - """ DEFAULT_CSS = """ diff --git a/src/textual/scroll_view.py b/src/textual/scroll_view.py index 63fd86a4e..4b58b3548 100644 --- a/src/textual/scroll_view.py +++ b/src/textual/scroll_view.py @@ -1,6 +1,5 @@ """ `ScrollView` is a base class for [line api](/guide/widgets#line-api) widgets. - """ from __future__ import annotations @@ -16,7 +15,6 @@ class ScrollView(ScrollableContainer): """ A base class for a Widget that handles its own scrolling (i.e. doesn't rely on the compositor to render children). - """ DEFAULT_CSS = """ diff --git a/src/textual/timer.py b/src/textual/timer.py index c5c300266..f25182325 100644 --- a/src/textual/timer.py +++ b/src/textual/timer.py @@ -2,7 +2,6 @@ Timer objects are created by [set_interval][textual.message_pump.MessagePump.set_interval] or [set_timer][textual.message_pump.MessagePump.set_timer]. - """ from __future__ import annotations @@ -95,7 +94,6 @@ class Timer: """Pause the timer. A paused timer will not send events until it is resumed. - """ self._active.clear() diff --git a/src/textual/walk.py b/src/textual/walk.py index ed4b4e501..b34892d61 100644 --- a/src/textual/walk.py +++ b/src/textual/walk.py @@ -4,7 +4,6 @@ Functions for *walking* the DOM. !!! note For most purposes you would be better off using [query][textual.dom.DOMNode.query], which uses these functions internally. - """ from __future__ import annotations @@ -57,7 +56,6 @@ def walk_depth_first( Returns: An iterable of DOMNodes, or the type specified in ``filter_type``. - """ from textual.dom import DOMNode @@ -118,7 +116,6 @@ def walk_breadth_first( Returns: An iterable of DOMNodes, or the type specified in ``filter_type``. - """ from textual.dom import DOMNode diff --git a/src/textual/widget.py b/src/textual/widget.py index bfc242f91..2e72c2380 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -1,6 +1,5 @@ """ The base class for widgets. - """ from __future__ import annotations @@ -94,7 +93,6 @@ class AwaitMount: ```python await self.mount(Static("foo")) ``` - """ def __init__(self, parent: Widget, widgets: Sequence[Widget]) -> None: @@ -233,7 +231,6 @@ class Widget(DOMNode): A Widget is the base class for Textual widgets. See also [static][textual.widgets._static.Static] for starting point for your own widgets. - """ DEFAULT_CSS = """ @@ -409,7 +406,6 @@ class Widget(DOMNode): """Check if vertical scroll is permitted. May be overridden if you want different logic regarding allowing scrolling. - """ return self.is_scrollable and self.show_vertical_scrollbar @@ -418,7 +414,6 @@ class Widget(DOMNode): """Check if horizontal scroll is permitted. May be overridden if you want different logic regarding allowing scrolling. - """ return self.is_scrollable and self.show_horizontal_scrollbar @@ -635,7 +630,6 @@ class Widget(DOMNode): Returns: An iterable of Widgets. - """ if self._horizontal_scrollbar is not None: yield self._horizontal_scrollbar @@ -874,7 +868,6 @@ class Widget(DOMNode): ) yield Footer() ``` - """ yield from () @@ -1134,7 +1127,6 @@ class Widget(DOMNode): Returns: ScrollBarCorner Widget. - """ from .scrollbar import ScrollBarCorner @@ -1248,7 +1240,6 @@ class Widget(DOMNode): Returns: A tuple of (, ) - """ if not self.is_scrollable: return False, False @@ -1300,7 +1291,6 @@ class Widget(DOMNode): Returns: Additional spacing around content area. - """ return self.styles.gutter + self.scrollbar_gutter @@ -1359,7 +1349,6 @@ class Widget(DOMNode): Returns: Offset from widget's origin. - """ x, y = self.gutter.top_left return Offset(x, y) @@ -1370,7 +1359,6 @@ class Widget(DOMNode): Returns: Content area size. - """ return self.region.shrink(self.styles.gutter).size @@ -1412,7 +1400,6 @@ class Widget(DOMNode): Returns: The virtual region. - """ try: return self.screen.find_widget(self).virtual_region @@ -1461,7 +1448,6 @@ class Widget(DOMNode): Returns: List of widgets that can receive focus. - """ focusable = [child for child in self._nodes if child.display and child.visible] return sorted(focusable, key=attrgetter("_focus_sort_key")) @@ -1493,7 +1479,6 @@ class Widget(DOMNode): Returns: A Rich console object. - """ return active_app.get().console @@ -1534,7 +1519,6 @@ class Widget(DOMNode): delay: A delay (in seconds) before the animation starts. easing: An easing method. on_complete: A callable to invoke when the animation is finished. - """ if self._animate is None: self._animate = self.app.animator.bind(self) @@ -1556,7 +1540,6 @@ class Widget(DOMNode): Returns: A layout object. - """ return self.styles.layout or self._default_layout @@ -1576,7 +1559,6 @@ class Widget(DOMNode): Returns: Name of layer. - """ return self.styles.layer or "default" @@ -1600,7 +1582,6 @@ class Widget(DOMNode): Returns: Rich style. - """ styles = self.styles _, background = self.background_colors @@ -1622,7 +1603,6 @@ class Widget(DOMNode): Returns: Rich Style. - """ styles = self.styles _, background = self.background_colors @@ -1646,7 +1626,6 @@ class Widget(DOMNode): Args: *regions: Regions which require a repaint. - """ if regions: content_offset = self.content_offset @@ -2559,7 +2538,6 @@ class Widget(DOMNode): Returns: Tuples of scrollbar Widget and region. - """ show_vertical_scrollbar, show_horizontal_scrollbar = self.scrollbars_enabled @@ -2613,7 +2591,6 @@ class Widget(DOMNode): Returns: Names of the pseudo classes. - """ node: MessagePump | None = self while isinstance(node, Widget): diff --git a/src/textual/widgets/_button.py b/src/textual/widgets/_button.py index e47797ba3..5a3e2b4fc 100644 --- a/src/textual/widgets/_button.py +++ b/src/textual/widgets/_button.py @@ -143,7 +143,6 @@ class Button(Static, can_focus=True): border-bottom: tall $error-lighten-2; border-top: tall $error-darken-2; } - """ BINDINGS = [Binding("enter", "press", "Press Button", show=False)] diff --git a/src/textual/widgets/_markdown.py b/src/textual/widgets/_markdown.py index 940fb43be..19220d1c6 100644 --- a/src/textual/widgets/_markdown.py +++ b/src/textual/widgets/_markdown.py @@ -130,7 +130,6 @@ class MarkdownH1(MarkdownHeader): text-style: bold; color: $text; } - """ @@ -148,7 +147,6 @@ class MarkdownH2(MarkdownHeader): padding: 1; text-style: bold; } - """ @@ -378,7 +376,6 @@ class MarkdownTable(MarkdownBlock): background: $panel; border: wide $background; } - """ def compose(self) -> ComposeResult: @@ -830,7 +827,6 @@ class MarkdownViewer(VerticalScroll, can_focus=True, can_focus_children=True): MarkdownViewer.-show-table-of-contents > MarkdownTableOfContents { display: block; } - """ show_table_of_contents = reactive(True) diff --git a/src/textual/widgets/_placeholder.py b/src/textual/widgets/_placeholder.py index 16c3b2f9b..fb0858aaf 100644 --- a/src/textual/widgets/_placeholder.py +++ b/src/textual/widgets/_placeholder.py @@ -69,7 +69,6 @@ class Placeholder(Widget): Placeholder.-text { padding: 1; } - """ # Consecutive placeholders get assigned consecutive colors. diff --git a/src/textual/widgets/_tabbed_content.py b/src/textual/widgets/_tabbed_content.py index e942a785c..e842f56ce 100644 --- a/src/textual/widgets/_tabbed_content.py +++ b/src/textual/widgets/_tabbed_content.py @@ -36,7 +36,6 @@ class TabPane(Widget): """A container for switchable content, with additional title. This widget is intended to be used with [TabbedContent][textual.widgets.TabbedContent]. - """ DEFAULT_CSS = """ diff --git a/src/textual/widgets/_tabs.py b/src/textual/widgets/_tabs.py index e06144619..ffae8e7e2 100644 --- a/src/textual/widgets/_tabs.py +++ b/src/textual/widgets/_tabs.py @@ -42,7 +42,6 @@ class Underline(Widget): | Class | Description | | :- | :- | | `underline-bar` | Style of the bar (may be used to change the color). | - """ highlight_start = reactive(0) diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index 2e63742b4..6fb5d5b2e 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -418,7 +418,6 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True): Tree > .tree--highlight-line { background: $boost; } - """ show_root = reactive(True) diff --git a/src/textual/widgets/_welcome.py b/src/textual/widgets/_welcome.py index 72fdd90c9..9624b5e8b 100644 --- a/src/textual/widgets/_welcome.py +++ b/src/textual/widgets/_welcome.py @@ -21,7 +21,6 @@ I will face my fear. I will permit it to pass over me and through me. And when it has gone past, I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain." - """ diff --git a/src/textual/worker.py b/src/textual/worker.py index 990504171..7d3e2e912 100644 --- a/src/textual/worker.py +++ b/src/textual/worker.py @@ -1,6 +1,5 @@ """ A class to manage concurrent [work](/guide/workers). - """ from __future__ import annotations @@ -204,7 +203,6 @@ class Worker(Generic[ResultType]): """Has the work been cancelled? Note that cancelled work may still be running. - """ return self._cancelled @@ -237,7 +235,6 @@ class Worker(Generic[ResultType]): """Progress as a percentage. If the total steps is None, then this will return 0. The percentage will be clamped between 0 and 100. - """ if not self._total_steps: return 0.0 @@ -267,7 +264,6 @@ class Worker(Generic[ResultType]): Args: steps: Number of steps to advance. - """ self._completed_steps += steps @@ -278,7 +274,6 @@ class Worker(Generic[ResultType]): Returns: Return value of work. - """ if ( diff --git a/tests/snapshot_tests/snapshot_apps/scrollbar_thumb_height.py b/tests/snapshot_tests/snapshot_apps/scrollbar_thumb_height.py index 19a7bf72b..148e2443f 100644 --- a/tests/snapshot_tests/snapshot_apps/scrollbar_thumb_height.py +++ b/tests/snapshot_tests/snapshot_apps/scrollbar_thumb_height.py @@ -29,7 +29,6 @@ class ScrollViewTester(App[None]): background: $primary-darken-2; border: round red; } - """ def compose(self) -> ComposeResult: diff --git a/tests/test_animation.py b/tests/test_animation.py index 20805ae9f..4e01dea9b 100644 --- a/tests/test_animation.py +++ b/tests/test_animation.py @@ -9,7 +9,6 @@ class AnimApp(App): #foo { height: 1; } - """ def compose(self) -> ComposeResult: diff --git a/tests/utilities/render.py b/tests/utilities/render.py index f1511e53c..629aa0c07 100644 --- a/tests/utilities/render.py +++ b/tests/utilities/render.py @@ -12,7 +12,6 @@ re_link_ids = re.compile(r"id=[\d\.\-]*?;.*?\x1b") def replace_link_ids(render: str) -> str: """Link IDs have a random ID and system path which is a problem for reproducible tests. - """ return re_link_ids.sub("id=0;foo\x1b", render)