From 5ec2e17e5efbdd625391982818dc9d24dc13e01e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 27 Feb 2025 10:40:06 +0000 Subject: [PATCH 1/4] preflight checks --- src/textual/app.py | 2 +- src/textual/widget.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/textual/app.py b/src/textual/app.py index 0dc77cae30..e5544f3be1 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -1026,7 +1026,7 @@ def is_attached(self) -> bool: @property def debug(self) -> bool: """Is debug mode enabled?""" - return "debug" in self.features + return "debug" in self.features or constants.DEBUG @property def is_headless(self) -> bool: diff --git a/src/textual/widget.py b/src/textual/widget.py index 2d56a37ff9..769bb99e90 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -504,6 +504,8 @@ def __init__( """Time of last scroll.""" self._user_scroll_interrupt: bool = False """Has the user interrupted a scroll to end?""" + if self.app.debug: + self._preflight() @property def is_mounted(self) -> bool: @@ -651,6 +653,19 @@ def text_selection(self) -> Selection | None: """Text selection information, or `None` if no text is selected in this widget.""" return self.screen.selections.get(self, None) + def _preflight(self) -> None: + """Called in debug mode to do preflight checks. + + Errors are reported via self.log. + + """ + from textual.screen import Screen + + if not isinstance(self, Screen) and hasattr(self, "CSS"): + self.log.warning( + f"'{self.__class__.__name__}.CSS' will be ignored (use 'DEFAULT_CSS' class variable for widgets)" + ) + def _cover(self, widget: Widget) -> None: """Set a widget used to replace the visuals of this widget (used for loading indicator). From 7b22c6c7d8cf117fab86e3b59a135686d48bd6b8 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 27 Feb 2025 10:42:54 +0000 Subject: [PATCH 2/4] optimize check --- src/textual/widget.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/textual/widget.py b/src/textual/widget.py index 769bb99e90..ca5d7731dc 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -659,12 +659,14 @@ def _preflight(self) -> None: Errors are reported via self.log. """ - from textual.screen import Screen - if not isinstance(self, Screen) and hasattr(self, "CSS"): - self.log.warning( - f"'{self.__class__.__name__}.CSS' will be ignored (use 'DEFAULT_CSS' class variable for widgets)" - ) + if hasattr(self, "CSS"): + from textual.screen import Screen + + if not isinstance(self, Screen): + self.log.warning( + f"'{self.__class__.__name__}.CSS' will be ignored (use 'DEFAULT_CSS' class variable for widgets)" + ) def _cover(self, widget: Widget) -> None: """Set a widget used to replace the visuals of this widget (used for loading indicator). From aaeb54929076fa7030e078243c22d83259acfe36 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 27 Feb 2025 10:47:52 +0000 Subject: [PATCH 3/4] check later --- CHANGELOG.md | 6 ++++++ src/textual/widget.py | 9 +++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12a35b5138..bc747de3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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/). +## Unreleased + +### Added + +- Added Widget.preflight_checks to perform some debug checks after a widget is instantiated, to catch common errors. + ## [2.1.2] - 2025-02-26 ### Fixed diff --git a/src/textual/widget.py b/src/textual/widget.py index ca5d7731dc..39b99e66c0 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -504,8 +504,6 @@ def __init__( """Time of last scroll.""" self._user_scroll_interrupt: bool = False """Has the user interrupted a scroll to end?""" - if self.app.debug: - self._preflight() @property def is_mounted(self) -> bool: @@ -653,10 +651,11 @@ def text_selection(self) -> Selection | None: """Text selection information, or `None` if no text is selected in this widget.""" return self.screen.selections.get(self, None) - def _preflight(self) -> None: + def preflight_checks(self) -> None: """Called in debug mode to do preflight checks. - Errors are reported via self.log. + This is used by Textual to log some common errors, but you could implement this + in custom widgets to perform additional checks. """ @@ -1492,6 +1491,8 @@ def _post_register(self, app: App) -> None: tie_breaker=tie_breaker, scope=scope, ) + if app.debug: + app.call_next(self.preflight_checks) def _get_box_model( self, From f2ac6ae5a1a79804dc1c8dc85b8f0b742d26d558 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 27 Feb 2025 10:49:57 +0000 Subject: [PATCH 4/4] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc747de3f5..1dfdf28e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added -- Added Widget.preflight_checks to perform some debug checks after a widget is instantiated, to catch common errors. +- Added Widget.preflight_checks to perform some debug checks after a widget is instantiated, to catch common errors. https://github.com/Textualize/textual/pull/5588 ## [2.1.2] - 2025-02-26