From 351d157ccf3df7727c7e3969915a902c3673bd8e 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: Fri, 9 Dec 2022 15:58:29 +0000 Subject: [PATCH 1/6] Add test for get_default_css. --- tests/test_dom.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/test_dom.py b/tests/test_dom.py index e925c5c14..620984361 100644 --- a/tests/test_dom.py +++ b/tests/test_dom.py @@ -45,6 +45,43 @@ def test_validate(): node.toggle_class("1") +def test_get_default_css(): + class A(DOMNode): + pass + class B(A): + pass + class C(B): + DEFAULT_CSS = "C" + class D(C): + pass + class E(D): + DEFAULT_CSS = "E" + node = DOMNode() + node_css = node.get_default_css() + a = A() + a_css = a.get_default_css() + b = B() + b_css = b.get_default_css() + c = C() + c_css = c.get_default_css() + d = D() + d_css = d.get_default_css() + e = E() + e_css = e.get_default_css() + + # Descendants that don't assign to DEFAULT_CSS don't add new CSS to the stack. + assert len(node_css) == len(a_css) == len(b_css) == 0 + assert len(c_css) == len(d_css) == 1 + assert len(e_css) == 2 + + # Descendants do push the priority of the ancestors' rules down. + assert c_css[0][2] == d_css[0][2] + 1 == 0 + + # The CSS on the stack is the correct one. + assert e_css[0][1:] == ("E", 0) + assert e_css[1][1:] == ("C", -2) + + @pytest.fixture def search(): """ From 4c7b04d68b21b71ef0d0de29263e01c1e49b04d7 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: Fri, 9 Dec 2022 15:59:22 +0000 Subject: [PATCH 2/6] Fix default css retrieval. --- src/textual/dom.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/textual/dom.py b/src/textual/dom.py index 1b56b750a..49edde70c 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -265,9 +265,12 @@ class DOMNode(MessagePump): except TypeError: return f"{base.__name__}" - for tie_breaker, base in enumerate(self._node_bases): - css = base.DEFAULT_CSS.strip() - if css: + default_css = [base.DEFAULT_CSS.strip() for base in self._node_bases] + parent_default_css = default_css[1:] + [""] + for tie_breaker, (base, css, next_css) in enumerate( + zip(self._node_bases, default_css, parent_default_css) + ): + if css and css != next_css: css_stack.append((get_path(base), css, -tie_breaker)) return css_stack From 0c708de72019b0010b1d1618b32ad83e9b3f639d 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: Fri, 9 Dec 2022 16:02:22 +0000 Subject: [PATCH 3/6] Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0801fb9b7..0d10bc97b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Type selectors can now contain numbers https://github.com/Textualize/textual/issues/1253 - Fixed visibility not affecting children https://github.com/Textualize/textual/issues/1313 +- Fixed default CSS retrieval for widgets with no `DEFAULT_CSS` that inherited from widgets with `DEFAULT_CSS` https://github.com/Textualize/textual/issues/1335 ## [0.5.0] - 2022-11-20 From ea72755c364dfa39dbdbab9f314fb5d9b6559676 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: Fri, 9 Dec 2022 16:16:23 +0000 Subject: [PATCH 4/6] Better naming --- src/textual/dom.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/textual/dom.py b/src/textual/dom.py index 0a371de45..731c35a56 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -266,11 +266,11 @@ class DOMNode(MessagePump): return f"{base.__name__}" default_css = [base.DEFAULT_CSS.strip() for base in self._node_bases] - parent_default_css = default_css[1:] + [""] - for tie_breaker, (base, css, next_css) in enumerate( - zip(self._node_bases, default_css, parent_default_css) + ancestor_default_css = default_css[1:] + [""] + for tie_breaker, (base, css, ancestor_css) in enumerate( + zip(self._node_bases, default_css, ancestor_default_css) ): - if css and css != next_css: + if css and css != ancestor_css: css_stack.append((get_path(base), css, -tie_breaker)) return css_stack From 966c4d0db942e77b92322b264c5ec4808716c6a6 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 13 Dec 2022 10:35:22 +0000 Subject: [PATCH 5/6] move refresh --- src/textual/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textual/app.py b/src/textual/app.py index 19e7b4c10..ef1260032 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -1996,9 +1996,9 @@ class App(Generic[ReturnType], DOMNode): await self._prune_nodes(widgets) finally: finished_event.set() + self.refresh(layout=True) removed_widgets = self._detach_from_dom(widgets) - self.refresh(layout=True) finished_event = asyncio.Event() asyncio.create_task(prune_widgets_task(removed_widgets, finished_event)) From 37dec514326f80a95ff4077b240ab3c2e48e7f1e 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: Tue, 13 Dec 2022 15:06:47 +0000 Subject: [PATCH 6/6] Simplify default css retrieval. By making use of __dict__ we have a simpler way of determining if the class defines its own default_css which does not involve comparing with the base class's default_css. --- src/textual/dom.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/textual/dom.py b/src/textual/dom.py index 731c35a56..0bd45fcce 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -265,12 +265,9 @@ class DOMNode(MessagePump): except TypeError: return f"{base.__name__}" - default_css = [base.DEFAULT_CSS.strip() for base in self._node_bases] - ancestor_default_css = default_css[1:] + [""] - for tie_breaker, (base, css, ancestor_css) in enumerate( - zip(self._node_bases, default_css, ancestor_default_css) - ): - if css and css != ancestor_css: + for tie_breaker, base in enumerate(self._node_bases): + css = base.__dict__.get("DEFAULT_CSS", "").strip() + if css: css_stack.append((get_path(base), css, -tie_breaker)) return css_stack