Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow exceptions that are raised while a Live is rendered to be displayed and/or processed https://github.com/Textualize/rich/pull/2305
- Fix crashes that can happen with `inspect` when docstrings contain some special control codes https://github.com/Textualize/rich/pull/2294
- Fix edges used in first row of tables when `show_header=False` https://github.com/Textualize/rich/pull/2330
- Fixed hash issue in Styles class https://github.com/Textualize/rich/pull/2346

## [12.4.4] - 2022-05-24

Expand Down
71 changes: 28 additions & 43 deletions rich/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class Style:
_bgcolor: Optional[Color]
_attributes: int
_set_attributes: int
_hash: int
_hash: Optional[int]
_null: bool
_meta: Optional[bytes]

Expand Down Expand Up @@ -190,16 +190,7 @@ def _make_color(color: Union[Color, str]) -> Color:
self._link = link
self._link_id = f"{randint(0, 999999)}" if link else ""
self._meta = None if meta is None else dumps(meta)
self._hash = hash(
(
self._color,
self._bgcolor,
self._attributes,
self._set_attributes,
link,
self._meta,
)
)
self._hash: Optional[int] = None
self._null = not (self._set_attributes or color or bgcolor or link or meta)

@classmethod
Expand Down Expand Up @@ -227,17 +218,8 @@ def from_color(
style._link = None
style._link_id = ""
style._meta = None
style._hash = hash(
(
color,
bgcolor,
None,
None,
None,
None,
)
)
style._null = not (color or bgcolor)
style._hash = None
return style

@classmethod
Expand All @@ -257,16 +239,7 @@ def from_meta(cls, meta: Optional[Dict[str, Any]]) -> "Style":
style._link = None
style._link_id = ""
style._meta = dumps(meta)
style._hash = hash(
(
None,
None,
None,
None,
None,
style._meta,
)
)
style._hash = None
style._null = not (meta)
return style

Expand Down Expand Up @@ -366,6 +339,7 @@ def _make_ansi_codes(self, color_system: ColorSystem) -> str:
Returns:
str: String containing codes.
"""

if self._ansi is None:
sgr: List[str] = []
append = sgr.append
Expand Down Expand Up @@ -446,16 +420,26 @@ def __rich_repr__(self) -> Result:
def __eq__(self, other: Any) -> bool:
if not isinstance(other, Style):
return NotImplemented
return (
self._color == other._color
and self._bgcolor == other._bgcolor
and self._set_attributes == other._set_attributes
and self._attributes == other._attributes
and self._link == other._link
and self._meta == other._meta
)
return self.__hash__() == other.__hash__()

def __ne__(self, other: Any) -> bool:
if not isinstance(other, Style):
return NotImplemented
return self.__hash__() != other.__hash__()

def __hash__(self) -> int:
if self._hash is not None:
return self._hash
self._hash = hash(
(
self._color,
self._bgcolor,
self._attributes,
self._set_attributes,
self._link,
self._meta,
)
)
return self._hash

@property
Expand Down Expand Up @@ -502,9 +486,9 @@ def without_color(self) -> "Style":
style._set_attributes = self._set_attributes
style._link = self._link
style._link_id = f"{randint(0, 999999)}" if self._link else ""
style._hash = self._hash
style._null = False
style._meta = None
style._hash = None
return style

@classmethod
Expand Down Expand Up @@ -677,7 +661,7 @@ def update_link(self, link: Optional[str] = None) -> "Style":
style._set_attributes = self._set_attributes
style._link = link
style._link_id = f"{randint(0, 999999)}" if link else ""
style._hash = self._hash
style._hash = None
style._null = False
style._meta = self._meta
return style
Expand All @@ -700,7 +684,7 @@ def render(
"""
if not text or color_system is None:
return text
attrs = self._make_ansi_codes(color_system)
attrs = self._ansi or self._make_ansi_codes(color_system)
rendered = f"\x1b[{attrs}m{text}\x1b[0m" if attrs else text
if self._link and not legacy_windows:
rendered = (
Expand All @@ -720,6 +704,7 @@ def test(self, text: Optional[str] = None) -> None:
text = text or str(self)
sys.stdout.write(f"{self.render(text)}\n")

@lru_cache(maxsize=4096)
def __add__(self, style: Optional["Style"]) -> "Style":
if not (isinstance(style, Style) or style is None):
return NotImplemented
Expand All @@ -738,12 +723,12 @@ def __add__(self, style: Optional["Style"]) -> "Style":
new_style._set_attributes = self._set_attributes | style._set_attributes
new_style._link = style._link or self._link
new_style._link_id = style._link_id or self._link_id
new_style._hash = style._hash
new_style._null = style._null
if self._meta and style._meta:
new_style._meta = dumps({**self.meta, **style.meta})
else:
new_style._meta = self._meta or style._meta
new_style._hash = None
return new_style


Expand Down