Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Style hash #2346

Merged
merged 7 commits into from Jun 17, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
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
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