From 655b5210cb1403100a646d167cf027eec760dd9f Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 9 Oct 2025 09:35:09 +0100 Subject: [PATCH] test fixes --- CHANGELOG.md | 2 +- rich/style.py | 18 +++++++----------- tests/test_inspect.py | 10 ++++++++++ tests/test_pretty.py | 5 +++++ tests/test_text.py | 7 ++++++- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 803ad41d..8d53b8d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Python3.14 compatibility +- Python3.14 compatibility https://github.com/Textualize/rich/pull/3861 ## [14.1.0] - 2025-06-25 diff --git a/rich/style.py b/rich/style.py index 835d06f3..52942418 100644 --- a/rich/style.py +++ b/rich/style.py @@ -1,6 +1,7 @@ import sys from functools import lru_cache -from marshal import dumps, loads +from operator import attrgetter +from pickle import dumps, loads from random import randint from typing import Any, Dict, Iterable, List, Optional, Type, Union, cast @@ -9,6 +10,10 @@ from .color import Color, ColorParseError, ColorSystem, blend_rgb from .repr import Result, rich_repr from .terminal_theme import DEFAULT_TERMINAL_THEME, TerminalTheme +_hash_getter = attrgetter( + "_color", "_bgcolor", "_attributes", "_set_attributes", "_link", "_meta" +) + # Style instances and style definitions are often interchangeable StyleType = Union[str, "Style"] @@ -432,16 +437,7 @@ class Style: 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, - ) - ) + self._hash = hash(_hash_getter(self)) return self._hash @property diff --git a/tests/test_inspect.py b/tests/test_inspect.py index 130e8df1..3f6e5b9f 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -43,6 +43,12 @@ skip_py313 = pytest.mark.skipif( reason="rendered differently on py3.13", ) +skip_py314 = pytest.mark.skipif( + sys.version_info.minor == 14 and sys.version_info.major == 3, + reason="rendered differently on py3.14", +) + + skip_pypy3 = pytest.mark.skipif( hasattr(sys, "pypy_version_info"), reason="rendered differently on pypy3", @@ -139,6 +145,7 @@ def test_inspect_empty_dict(): assert render({}).startswith(expected) +@skip_py314 @skip_py313 @skip_py312 @skip_py311 @@ -219,6 +226,7 @@ def test_inspect_integer_with_value(): @skip_py311 @skip_py312 @skip_py313 +@skip_py314 def test_inspect_integer_with_methods_python38_and_python39(): expected = ( "╭──────────────── ─────────────────╮\n" @@ -257,6 +265,7 @@ def test_inspect_integer_with_methods_python38_and_python39(): @skip_py311 @skip_py312 @skip_py313 +@skip_py314 def test_inspect_integer_with_methods_python310only(): expected = ( "╭──────────────── ─────────────────╮\n" @@ -299,6 +308,7 @@ def test_inspect_integer_with_methods_python310only(): @skip_py310 @skip_py312 @skip_py313 +@skip_py314 def test_inspect_integer_with_methods_python311(): # to_bytes and from_bytes methods on int had minor signature change - # they now, as of 3.11, have default values for all of their parameters diff --git a/tests/test_pretty.py b/tests/test_pretty.py index 90be42f8..29331d9d 100644 --- a/tests/test_pretty.py +++ b/tests/test_pretty.py @@ -38,6 +38,10 @@ skip_py313 = pytest.mark.skipif( sys.version_info.minor == 13 and sys.version_info.major == 3, reason="rendered differently on py3.13", ) +skip_py314 = pytest.mark.skipif( + sys.version_info.minor == 14 and sys.version_info.major == 3, + reason="rendered differently on py3.14", +) def test_install() -> None: @@ -639,6 +643,7 @@ def test_attrs_empty() -> None: @skip_py311 @skip_py312 @skip_py313 +@skip_py314 def test_attrs_broken() -> None: @attr.define class Foo: diff --git a/tests/test_text.py b/tests/test_text.py index fee7302f..92580334 100644 --- a/tests/test_text.py +++ b/tests/test_text.py @@ -843,7 +843,12 @@ def test_assemble(): def test_assemble_meta(): text = Text.assemble("foo", ("bar", "bold"), meta={"foo": "bar"}) assert str(text) == "foobar" - assert text._spans == [Span(3, 6, "bold"), Span(0, 6, Style(meta={"foo": "bar"}))] + + spans = text._spans + expected = [Span(3, 6, "bold"), Span(0, 6, Style(meta={"foo": "bar"}))] + + assert spans == expected + console = Console() assert text.get_style_at_offset(console, 0).meta == {"foo": "bar"}