Skip to content

Commit 3fe08c1

Browse files
authored
Merge pull request #4837 from Textualize/micro-op
micro optimizations
2 parents f0c90e1 + 2957539 commit 3fe08c1

File tree

5 files changed

+35
-47
lines changed

5 files changed

+35
-47
lines changed

src/textual/_compositor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,8 @@ def add_widget(
593593
if not widget._is_mounted:
594594
return
595595
styles = widget.styles
596-
visibility = styles.get_rule("visibility")
597-
if visibility is not None:
596+
597+
if (visibility := styles.get_rule("visibility")) is not None:
598598
visible = visibility == "visible"
599599

600600
if visible:

src/textual/css/_style_properties.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def __set_name__(self, owner: StylesBase, name: str) -> None:
9999
def __get__(
100100
self, obj: StylesBase, objtype: type[StylesBase] | None = None
101101
) -> PropertyGetType:
102-
return cast(PropertyGetType, obj.get_rule(self.name, self.default))
102+
return obj.get_rule(self.name, self.default) # type: ignore[return-value]
103103

104104
def __set__(self, obj: StylesBase, value: PropertySetType | None) -> None:
105105
_rich_traceback_omit = True
@@ -156,7 +156,7 @@ def __get__(
156156
Returns:
157157
The Scalar object or ``None`` if it's not set.
158158
"""
159-
return cast("Scalar | None", obj.get_rule(self.name))
159+
return obj.get_rule(self.name) # type: ignore[return-value]
160160

161161
def __set__(
162162
self, obj: StylesBase, value: float | int | Scalar | str | None
@@ -236,7 +236,7 @@ def __set_name__(self, owner: StylesBase, name: str) -> None:
236236
def __get__(
237237
self, obj: StylesBase, objtype: type[StylesBase] | None = None
238238
) -> tuple[Scalar, ...] | None:
239-
return cast("tuple[Scalar, ...]", obj.get_rule(self.name))
239+
return obj.get_rule(self.name) # type: ignore[return-value]
240240

241241
def __set__(
242242
self, obj: StylesBase, value: str | Iterable[str | float] | None
@@ -292,10 +292,7 @@ def __get__(
292292
A ``tuple[EdgeType, Style]`` containing the string type of the box and
293293
it's style. Example types are "rounded", "solid", and "dashed".
294294
"""
295-
return cast(
296-
"tuple[EdgeType, Color]",
297-
obj.get_rule(self.name) or ("", self._default_color),
298-
)
295+
return obj.get_rule(self.name) or ("", self._default_color) # type: ignore[return-value]
299296

300297
def __set__(self, obj: StylesBase, border: tuple[EdgeType, str | Color] | None):
301298
"""Set the box property.
@@ -506,10 +503,7 @@ class KeylineProperty:
506503
def __get__(
507504
self, obj: StylesBase, objtype: type[StylesBase] | None = None
508505
) -> tuple[CanvasLineType, Color]:
509-
return cast(
510-
"tuple[CanvasLineType, Color]",
511-
obj.get_rule("keyline", ("none", Color.parse("transparent"))),
512-
)
506+
return obj.get_rule("keyline", ("none", TRANSPARENT)) # type: ignore[return-value]
513507

514508
def __set__(self, obj: StylesBase, keyline: tuple[str, Color] | None):
515509
if keyline is None:
@@ -538,7 +532,7 @@ def __get__(
538532
Returns:
539533
The Spacing. If unset, returns the null spacing ``(0, 0, 0, 0)``.
540534
"""
541-
return cast(Spacing, obj.get_rule(self.name, NULL_SPACING))
535+
return obj.get_rule(self.name, NULL_SPACING) # type: ignore[return-value]
542536

543537
def __set__(self, obj: StylesBase, spacing: SpacingDimensions | None):
544538
"""Set the Spacing.
@@ -591,7 +585,7 @@ def __get__(
591585
Returns:
592586
The dock name as a string, or "" if the rule is not set.
593587
"""
594-
return cast(DockEdge, obj.get_rule("dock", ""))
588+
return obj.get_rule("dock", "") # type: ignore[return-value]
595589

596590
def __set__(self, obj: StylesBase, dock_name: str | None):
597591
"""Set the Dock property.
@@ -621,7 +615,7 @@ def __get__(
621615
Returns:
622616
The ``Layout`` object.
623617
"""
624-
return cast("Layout | None", obj.get_rule(self.name))
618+
return obj.get_rule(self.name) # type: ignore[return-value]
625619

626620
def __set__(self, obj: StylesBase, layout: str | Layout | None):
627621
"""
@@ -675,7 +669,7 @@ def __get__(
675669
The ``ScalarOffset`` indicating the adjustment that
676670
will be made to widget position prior to it being rendered.
677671
"""
678-
return cast("ScalarOffset", obj.get_rule(self.name, NULL_SCALAR))
672+
return obj.get_rule(self.name, NULL_SCALAR) # type: ignore[return-value]
679673

680674
def __set__(
681675
self, obj: StylesBase, offset: tuple[int | str, int | str] | ScalarOffset | None
@@ -832,7 +826,7 @@ def __get__(self, obj: StylesBase, objtype: type[StylesBase] | None) -> str:
832826
Returns:
833827
The name.
834828
"""
835-
return cast(str, obj.get_rule(self.name, ""))
829+
return obj.get_rule(self.name, "") # type: ignore[return-value]
836830

837831
def __set__(self, obj: StylesBase, name: str | None):
838832
"""Set the name property.
@@ -862,7 +856,7 @@ def __set_name__(self, owner: StylesBase, name: str) -> None:
862856
def __get__(
863857
self, obj: StylesBase, objtype: type[StylesBase] | None = None
864858
) -> tuple[str, ...]:
865-
return cast("tuple[str, ...]", obj.get_rule(self.name, ()))
859+
return obj.get_rule(self.name, ()) # type: ignore[return-value]
866860

867861
def __set__(self, obj: StylesBase, names: str | tuple[str] | None = None):
868862
_rich_traceback_omit = True
@@ -900,7 +894,7 @@ def __get__(
900894
Returns:
901895
The Color.
902896
"""
903-
return cast(Color, obj.get_rule(self.name, self._default_color))
897+
return obj.get_rule(self.name, self._default_color) # type: ignore[return-value]
904898

905899
def __set__(self, obj: StylesBase, color: Color | str | None) -> None:
906900
"""Set the Color.
@@ -987,7 +981,7 @@ def __get__(
987981
Returns:
988982
The ``Style`` object.
989983
"""
990-
return cast(Style, obj.get_rule(self.name, Style.null()))
984+
return obj.get_rule(self.name, Style.null()) # type: ignore[return-value]
991985

992986
def __set__(self, obj: StylesBase, style_flags: Style | str | None) -> None:
993987
"""Set the style using a style flag string.
@@ -1050,7 +1044,7 @@ def __get__(
10501044
e.g. ``{"offset": Transition(...), ...}``. If no transitions have been set, an empty ``dict``
10511045
is returned.
10521046
"""
1053-
return cast("dict[str, Transition]", obj.get_rule("transitions", {}))
1047+
return obj.get_rule("transitions", {}) # type: ignore[return-value]
10541048

10551049
def __set__(
10561050
self, obj: StylesBase, transitions: dict[str, Transition] | None
@@ -1090,7 +1084,7 @@ def __get__(self, obj: StylesBase, type: type[StylesBase]) -> float:
10901084
Returns:
10911085
The value of the property (in the range (0, 1)).
10921086
"""
1093-
return cast(float, obj.get_rule(self.name, self.default))
1087+
return obj.get_rule(self.name, self.default) # type: ignore[return-value]
10941088

10951089
def __set__(self, obj: StylesBase, value: float | str | None) -> None:
10961090
"""Set the property value, clamping it between 0 and 1.
@@ -1146,7 +1140,7 @@ class HatchProperty:
11461140
"""Property to expose hatch style."""
11471141

11481142
def __get__(self, obj: StylesBase, type: type[StylesBase]) -> tuple[str, Color]:
1149-
return cast("tuple[str, Color]", obj.get_rule("hatch", (" ", TRANSPARENT)))
1143+
return obj.get_rule("hatch", (" ", TRANSPARENT)) # type: ignore[return-value]
11501144

11511145
def __set__(self, obj: StylesBase, value: tuple[str, Color | str] | None) -> None:
11521146
_rich_traceback_omit = True

src/textual/css/scalar.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Unit(Enum):
5050
SYMBOL_UNIT = {v: k for k, v in UNIT_SYMBOL.items()}
5151

5252
_MATCH_SCALAR = re.compile(r"^(-?\d+\.?\d*)(fr|%|w|h|vw|vh)?$").match
53+
_FRACTION_ONE = Fraction(1)
5354

5455

5556
def _resolve_cells(
@@ -284,7 +285,7 @@ def resolve(
284285
unit = percent_unit
285286
try:
286287
dimension = RESOLVE_MAP[unit](
287-
value, size, viewport, fraction_unit or Fraction(1)
288+
value, size, viewport, fraction_unit or _FRACTION_ONE
288289
)
289290
except KeyError:
290291
raise ScalarResolveError(f"expected dimensions; found {str(self)!r}")

src/textual/css/styles.py

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
from __future__ import annotations
22

3-
from abc import ABC, abstractmethod
43
from dataclasses import dataclass, field
54
from functools import lru_cache, partial
65
from operator import attrgetter
7-
from typing import TYPE_CHECKING, Any, Iterable, NamedTuple, cast
6+
from typing import TYPE_CHECKING, Any, Callable, Iterable, NamedTuple, cast
87

98
import rich.repr
109
from rich.style import Style
@@ -204,7 +203,7 @@ class DockGroup(NamedTuple):
204203
z: int
205204

206205

207-
class StylesBase(ABC):
206+
class StylesBase:
208207
"""A common base class for Styles and RenderStyles"""
209208

210209
ANIMATABLE = {
@@ -458,7 +457,6 @@ def is_auto_height(self) -> bool:
458457
height = self.height
459458
return height is not None and height.unit == Unit.AUTO
460459

461-
@abstractmethod
462460
def has_rule(self, rule: str) -> bool:
463461
"""Check if a rule is set on this Styles object.
464462
@@ -468,8 +466,8 @@ def has_rule(self, rule: str) -> bool:
468466
Returns:
469467
``True`` if the rules is present, otherwise ``False``.
470468
"""
469+
raise NotImplementedError()
471470

472-
@abstractmethod
473471
def clear_rule(self, rule: str) -> bool:
474472
"""Removes the rule from the Styles object, as if it had never been set.
475473
@@ -479,16 +477,16 @@ def clear_rule(self, rule: str) -> bool:
479477
Returns:
480478
``True`` if a rule was cleared, or ``False`` if the rule is already not set.
481479
"""
480+
raise NotImplementedError()
482481

483-
@abstractmethod
484482
def get_rules(self) -> RulesMap:
485483
"""Get the rules in a mapping.
486484
487485
Returns:
488486
A TypedDict of the rules.
489487
"""
488+
raise NotImplementedError()
490489

491-
@abstractmethod
492490
def set_rule(self, rule: str, value: object | None) -> bool:
493491
"""Set a rule.
494492
@@ -499,8 +497,8 @@ def set_rule(self, rule: str, value: object | None) -> bool:
499497
Returns:
500498
``True`` if the rule changed, otherwise ``False``.
501499
"""
500+
raise NotImplementedError()
502501

503-
@abstractmethod
504502
def get_rule(self, rule: str, default: object = None) -> object:
505503
"""Get an individual rule.
506504
@@ -511,8 +509,8 @@ def get_rule(self, rule: str, default: object = None) -> object:
511509
Returns:
512510
Rule value or default.
513511
"""
512+
raise NotImplementedError()
514513

515-
@abstractmethod
516514
def refresh(
517515
self, *, layout: bool = False, children: bool = False, parent: bool = False
518516
) -> None:
@@ -524,19 +522,16 @@ def refresh(
524522
parent: Also refresh the parent.
525523
"""
526524

527-
@abstractmethod
528525
def reset(self) -> None:
529526
"""Reset the rules to initial state."""
530527

531-
@abstractmethod
532528
def merge(self, other: StylesBase) -> None:
533529
"""Merge values from another Styles.
534530
535531
Args:
536532
other: A Styles object.
537533
"""
538534

539-
@abstractmethod
540535
def merge_rules(self, rules: RulesMap) -> None:
541536
"""Merge rules in to Styles.
542537
@@ -686,6 +681,10 @@ class Styles(StylesBase):
686681

687682
important: set[str] = field(default_factory=set)
688683

684+
def __post_init__(self) -> None:
685+
self.get_rule: Callable[[str, object], object] = self._rules.get # type: ignore[assignment]
686+
self.has_rule: Callable[[str], bool] = self._rules.__contains__ # type: ignore[assignment]
687+
689688
def copy(self) -> Styles:
690689
"""Get a copy of this Styles object."""
691690
return Styles(
@@ -694,10 +693,6 @@ def copy(self) -> Styles:
694693
important=self.important,
695694
)
696695

697-
def has_rule(self, rule: str) -> bool:
698-
assert rule in RULE_NAMES_SET, f"no such rule {rule!r}"
699-
return rule in self._rules
700-
701696
def clear_rule(self, rule: str) -> bool:
702697
"""Removes the rule from the Styles object, as if it had never been set.
703698
@@ -737,9 +732,6 @@ def set_rule(self, rule: str, value: object | None) -> bool:
737732
self._updates += 1
738733
return changed
739734

740-
def get_rule(self, rule: str, default: object = None) -> object:
741-
return self._rules.get(rule, default)
742-
743735
def refresh(
744736
self, *, layout: bool = False, children: bool = False, parent: bool = False
745737
) -> None:

src/textual/dom.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -994,16 +994,17 @@ def rich_style(self) -> Style:
994994

995995
for node in reversed(self.ancestors_with_self):
996996
styles = node.styles
997+
has_rule = styles.has_rule
997998
opacity *= styles.opacity
998-
if styles.has_rule("background"):
999+
if has_rule("background"):
9991000
text_background = background + styles.background
10001001
background += styles.background.multiply_alpha(opacity)
10011002
else:
10021003
text_background = background
1003-
if styles.has_rule("color"):
1004+
if has_rule("color"):
10041005
color = styles.color
10051006
style += styles.text_style
1006-
if styles.has_rule("auto_color") and styles.auto_color:
1007+
if has_rule("auto_color") and styles.auto_color:
10071008
color = text_background.get_contrast_text(color.a)
10081009

10091010
style += Style.from_color(

0 commit comments

Comments
 (0)