Skip to content

Commit a520f0a

Browse files
committed
refactor(style_builder): StyleBuilder is a dataclass
Simplified logic of initialization, replaced repetative calls to constructor of StyleBuilder with dataclasses.replace
1 parent e0ceb16 commit a520f0a

File tree

1 file changed

+39
-79
lines changed

1 file changed

+39
-79
lines changed

src/coloredstrings/style_builder.py

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

3+
import dataclasses
34
import warnings
45
from typing import (
56
Any,
67
Dict,
7-
Iterable,
8+
FrozenSet,
89
Optional,
910
Tuple,
1011
Union,
@@ -13,26 +14,31 @@
1314
from coloredstrings import color_support, stylize, types, utils
1415

1516

17+
@dataclasses.dataclass(frozen=True)
1618
class StyleBuilder:
17-
def __init__(
18-
self,
19-
fg: Optional[types.Color] = None,
20-
bg: Optional[types.Color] = None,
21-
attrs: Iterable[types.Attribute] = (),
22-
next_color_for_bg: bool = False,
23-
mode: Optional[types.ColorMode] = None,
24-
visible_if_colors: bool = False,
25-
extensions: Optional[
26-
Dict[str, Union[str, Tuple[int, int, int], StyleBuilder]]
27-
] = None,
28-
) -> None:
29-
self.fg = fg
30-
self.bg = bg
31-
self.attrs = frozenset(attrs)
32-
self.next_color_for_bg = next_color_for_bg
33-
self.mode = mode
34-
self.visible_if_colors = visible_if_colors
35-
self.extensions = {} if extensions is None else extensions
19+
fg: Optional[types.Color] = None
20+
"""Foreground color."""
21+
22+
bg: Optional[types.Color] = None
23+
"""Background color."""
24+
25+
attrs: FrozenSet[types.Attribute] = dataclasses.field(default_factory=frozenset)
26+
"""Styling attributes (bold, italic, etc.)."""
27+
28+
next_color_for_bg: bool = False
29+
"""Whether the next `color` method should be treated as setting the background color."""
30+
31+
mode: Optional[types.ColorMode] = None
32+
"""Color mode."""
33+
34+
visible_if_colors: bool = False
35+
"""Used for `visible` style: whether the text should be replaced with an empty string when colors are not available."""
36+
37+
# This annotation hurts me very much...
38+
extensions: Dict[str, Union[str, Tuple[int, int, int], StyleBuilder]] = (
39+
dataclasses.field(default_factory=dict)
40+
)
41+
"""User-defined extension styles."""
3642

3743
def __call__(
3844
self,
@@ -56,27 +62,11 @@ def __call__(
5662
)
5763

5864
def color_mode(self, mode: types.ColorMode) -> StyleBuilder:
59-
return StyleBuilder(
60-
fg=self.fg,
61-
bg=self.bg,
62-
attrs=self.attrs,
63-
next_color_for_bg=self.next_color_for_bg,
64-
mode=mode,
65-
visible_if_colors=self.visible_if_colors,
66-
extensions=self.extensions,
67-
)
65+
return dataclasses.replace(self, mode=mode)
6866

6967
@property
7068
def on(self) -> StyleBuilder:
71-
return StyleBuilder(
72-
fg=self.fg,
73-
bg=self.bg,
74-
attrs=self.attrs,
75-
next_color_for_bg=True,
76-
mode=self.mode,
77-
visible_if_colors=self.visible_if_colors,
78-
extensions=self.extensions,
79-
)
69+
return dataclasses.replace(self, next_color_for_bg=True)
8070

8171
@property
8272
def black(self) -> StyleBuilder:
@@ -329,15 +319,7 @@ def double_underline(self) -> StyleBuilder:
329319

330320
@property
331321
def visible(self) -> StyleBuilder:
332-
return StyleBuilder(
333-
fg=self.fg,
334-
bg=self.bg,
335-
attrs=self.attrs,
336-
next_color_for_bg=self.next_color_for_bg,
337-
mode=self.mode,
338-
visible_if_colors=True,
339-
extensions=self.extensions,
340-
)
322+
return dataclasses.replace(self, visible_if_colors=True)
341323

342324
def extend(
343325
self,
@@ -380,36 +362,20 @@ def extend(
380362
StyleBuilder
381363
A new `StyleBuilder` instance with the merged extensions.
382364
"""
383-
extensions = {
384-
**self.extensions,
385-
**(style_dict or {}),
386-
**styles,
387-
}
388-
389-
return StyleBuilder(
390-
fg=self.fg,
391-
bg=self.bg,
392-
attrs=self.attrs,
393-
next_color_for_bg=self.next_color_for_bg,
394-
mode=self.mode,
395-
visible_if_colors=self.visible_if_colors,
396-
extensions=extensions,
365+
return dataclasses.replace(
366+
self,
367+
extensions={
368+
**self.extensions,
369+
**(style_dict or {}),
370+
**styles,
371+
},
397372
)
398373

399374
def __repr__(self) -> str:
400375
return f"StyleBuilder(fg={self.fg!r}, bg={self.bg!r}, attrs={set(self.attrs)!r}, on={self.next_color_for_bg})"
401376

402377
def _with_attrs(self, *attrs: types.Attribute) -> StyleBuilder:
403-
new_attrs = self.attrs.union(attrs)
404-
return StyleBuilder(
405-
fg=self.fg,
406-
bg=self.bg,
407-
attrs=new_attrs,
408-
next_color_for_bg=self.next_color_for_bg,
409-
mode=self.mode,
410-
visible_if_colors=self.visible_if_colors,
411-
extensions=self.extensions,
412-
)
378+
return dataclasses.replace(self, attrs=self.attrs.union(attrs))
413379

414380
def _with_color(
415381
self, color: Union[types.Ansi16Color, types.Extended256, types.Rgb]
@@ -424,12 +390,6 @@ def _with_color(
424390
else:
425391
fg = color
426392

427-
return StyleBuilder(
428-
fg=fg,
429-
bg=bg,
430-
attrs=self.attrs,
431-
next_color_for_bg=next_color_for_bg,
432-
mode=self.mode,
433-
visible_if_colors=self.visible_if_colors,
434-
extensions=self.extensions,
393+
return dataclasses.replace(
394+
self, fg=fg, bg=bg, next_color_for_bg=next_color_for_bg
435395
)

0 commit comments

Comments
 (0)