From 81e81f4f984bc552163b18cb99a2cdb82acb31ef Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 22 Feb 2023 15:39:00 +0000 Subject: [PATCH 1/4] Cache internals --- src/textual/dom.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/textual/dom.py b/src/textual/dom.py index e68939b39..100aed965 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -1,12 +1,12 @@ from __future__ import annotations import re +from functools import lru_cache from inspect import getfile from typing import ( TYPE_CHECKING, ClassVar, Iterable, - Iterator, Sequence, Type, TypeVar, @@ -224,13 +224,14 @@ class DOMNode(MessagePump): Reactive._initialize_object(self) @property - def _node_bases(self) -> Iterator[Type[DOMNode]]: + def _node_bases(self) -> Sequence[Type[DOMNode]]: """The DOMNode bases classes (including self.__class__)""" # Node bases are in reversed order so that the base class is lower priority return self._css_bases(self.__class__) @classmethod - def _css_bases(cls, base: Type[DOMNode]) -> Iterator[Type[DOMNode]]: + @lru_cache(maxsize=None) + def _css_bases(cls, base: Type[DOMNode]) -> Sequence[Type[DOMNode]]: """Get the DOMNode base classes, which inherit CSS. Args: @@ -239,9 +240,10 @@ class DOMNode(MessagePump): Returns: An iterable of DOMNode classes. """ + classes = [] _class = base while True: - yield _class + classes.append(_class) if not _class._inherit_css: break for _base in _class.__bases__: @@ -250,6 +252,7 @@ class DOMNode(MessagePump): break else: break + return classes @classmethod def _merge_bindings(cls) -> Bindings: @@ -314,7 +317,9 @@ class DOMNode(MessagePump): return css_stack - def _get_component_classes(self) -> set[str]: + @classmethod + @lru_cache(maxsize=None) + def _get_component_classes(cls) -> Sequence[str]: """Gets the component classes for this class and inherited from bases. Component classes are inherited from base classes, unless @@ -325,12 +330,12 @@ class DOMNode(MessagePump): """ component_classes: set[str] = set() - for base in self._node_bases: + for base in cls._css_bases(cls): component_classes.update(base.__dict__.get("COMPONENT_CLASSES", set())) if not base.__dict__.get("_inherit_component_classes", True): break - return component_classes + return sorted(component_classes) @property def parent(self) -> DOMNode | None: From 32eb6ee07532387e283c875c66c82519ec7bff17 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 22 Feb 2023 15:47:28 +0000 Subject: [PATCH 2/4] test fix --- src/textual/dom.py | 4 ++-- tests/test_dom.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/textual/dom.py b/src/textual/dom.py index 100aed965..2adebdafe 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -319,7 +319,7 @@ class DOMNode(MessagePump): @classmethod @lru_cache(maxsize=None) - def _get_component_classes(cls) -> Sequence[str]: + def _get_component_classes(cls) -> frozenset[str]: """Gets the component classes for this class and inherited from bases. Component classes are inherited from base classes, unless @@ -335,7 +335,7 @@ class DOMNode(MessagePump): if not base.__dict__.get("_inherit_component_classes", True): break - return sorted(component_classes) + return frozenset(component_classes) @property def parent(self) -> DOMNode | None: diff --git a/tests/test_dom.py b/tests/test_dom.py index f366d0706..3553a4443 100644 --- a/tests/test_dom.py +++ b/tests/test_dom.py @@ -157,13 +157,13 @@ def test_component_classes_inheritance(): f = F() f_cc = f._get_component_classes() - assert node_cc == set() - assert a_cc == {"a-1", "a-2"} - assert b_cc == {"b-1"} - assert c_cc == {"b-1", "c-1", "c-2"} + assert node_cc == [] + assert a_cc == ["a-1", "a-2"] + assert b_cc == ["b-1"] + assert c_cc == ["b-1", "c-1", "c-2"] assert d_cc == c_cc - assert e_cc == {"b-1", "c-1", "c-2", "e-1"} - assert f_cc == {"f-1"} + assert e_cc == ["b-1", "c-1", "c-2", "e-1"] + assert f_cc == ["f-1"] @pytest.fixture From 07d728382d9f0efab067920a461026aa56a1cc2e Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 22 Feb 2023 15:59:34 +0000 Subject: [PATCH 3/4] fix test --- tests/test_dom.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_dom.py b/tests/test_dom.py index 3553a4443..b78a958c9 100644 --- a/tests/test_dom.py +++ b/tests/test_dom.py @@ -157,13 +157,13 @@ def test_component_classes_inheritance(): f = F() f_cc = f._get_component_classes() - assert node_cc == [] - assert a_cc == ["a-1", "a-2"] - assert b_cc == ["b-1"] - assert c_cc == ["b-1", "c-1", "c-2"] + assert node_cc == frozenset() + assert a_cc == {"a-1", "a-2"} + assert b_cc == {"b-1"} + assert c_cc == {"b-1", "c-1", "c-2"} assert d_cc == c_cc - assert e_cc == ["b-1", "c-1", "c-2", "e-1"] - assert f_cc == ["f-1"] + assert e_cc == {"b-1", "c-1", "c-2", "e-1"} + assert f_cc == {"f-1"} @pytest.fixture From 497fff91356c8fd02d5e802aa90c602e6429bad1 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Wed, 22 Feb 2023 16:00:41 +0000 Subject: [PATCH 4/4] typing --- src/textual/dom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textual/dom.py b/src/textual/dom.py index 2adebdafe..56b9e8770 100644 --- a/src/textual/dom.py +++ b/src/textual/dom.py @@ -240,7 +240,7 @@ class DOMNode(MessagePump): Returns: An iterable of DOMNode classes. """ - classes = [] + classes: list[type[DOMNode]] = [] _class = base while True: classes.append(_class)