From 8e821d41131c1324a64eff4d446ac26de917fac3 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 29 Apr 2022 10:34:35 +0100 Subject: [PATCH] lazy parse_rules --- src/textual/css/stylesheet.py | 14 +++++++++----- tests/css/test_parse.py | 9 +++++++-- tests/css/test_stylesheet.py | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/textual/css/stylesheet.py b/src/textual/css/stylesheet.py index 7b8606cc1..52993f02c 100644 --- a/src/textual/css/stylesheet.py +++ b/src/textual/css/stylesheet.py @@ -101,17 +101,19 @@ class StylesheetErrors: @rich.repr.auto class Stylesheet: def __init__(self, *, variables: dict[str, str] | None = None) -> None: - self._rules: list[RuleSet] | None = None + self._rules: list[RuleSet] = [] self.variables = variables or {} self.source: dict[str, str] = {} + self._require_parse = False def __rich_repr__(self) -> rich.repr.Result: yield self.rules @property def rules(self) -> list[RuleSet]: - if self._rules is None: + if self._require_parse: self.parse() + self._require_parse = False assert self._rules is not None return self._rules @@ -171,7 +173,7 @@ class Stylesheet: except Exception as error: raise StylesheetError(f"unable to read {filename!r}; {error}") self.source[path] = css - self._rules = None + self._require_parse = True def add_source(self, css: str, path: str | None = None) -> None: """Parse CSS from a string. @@ -192,7 +194,7 @@ class Stylesheet: return self.source[path] = css - self._rules = None + self._require_parse = True def parse(self) -> None: """Parse the source in the stylesheet. @@ -208,6 +210,7 @@ class Stylesheet: raise StylesheetParseError(self.error_renderable) add_rules(css_rules) self._rules = rules + self._require_parse = False def reparse(self) -> None: """Re-parse source, applying new variables. @@ -221,7 +224,8 @@ class Stylesheet: stylesheet = Stylesheet(variables=self.variables) for path, css in self.source.items(): stylesheet.add_source(css, path) - self._rules = None + stylesheet.parse() + self.rules = stylesheet.rules self.source = stylesheet.source @classmethod diff --git a/tests/css/test_parse.py b/tests/css/test_parse.py index f0c05dc2d..ccf7a75f4 100644 --- a/tests/css/test_parse.py +++ b/tests/css/test_parse.py @@ -875,6 +875,7 @@ class TestParseLayout: stylesheet = Stylesheet() with pytest.raises(StylesheetParseError) as ex: stylesheet.add_source(css) + stylesheet.parse() assert ex.value.errors is not None @@ -1033,8 +1034,10 @@ class TestParseTransition: stylesheet = Stylesheet() with pytest.raises(StylesheetParseError) as ex: stylesheet.add_source(css) + stylesheet.parse() - stylesheet_errors = stylesheet.rules[0].errors + rules = stylesheet._parse_rules(css, "foo") + stylesheet_errors = rules[0].errors assert len(stylesheet_errors) == 1 assert stylesheet_errors[0][0].value == invalid_func_name @@ -1067,7 +1070,9 @@ class TestParseOpacity: with pytest.raises(StylesheetParseError): stylesheet.add_source(css) - assert stylesheet.rules[0].errors + stylesheet.parse() + rules = stylesheet._parse_rules(css, "foo") + assert rules[0].errors class TestParseMargin: diff --git a/tests/css/test_stylesheet.py b/tests/css/test_stylesheet.py index b31633504..718446a43 100644 --- a/tests/css/test_stylesheet.py +++ b/tests/css/test_stylesheet.py @@ -43,6 +43,7 @@ def test_color_property_parsing(css_value, expectation, expected_color): with expectation: stylesheet.add_source(css) + stylesheet.parse() if expected_color: css_rule = stylesheet.rules[0]