From 29dc5a9768346c791980ce928ba12dcb63d69430 Mon Sep 17 00:00:00 2001 From: Noa Levi <275430404+lphuc2250gma@users.noreply.github.com> Date: Wed, 20 May 2026 20:42:29 +0000 Subject: [PATCH] chore: improve rich maintenance path --- rich/cells.py | 6 +++--- tests/test_cells.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/rich/cells.py b/rich/cells.py index 9d590b04e8..edafb439a6 100644 --- a/rich/cells.py +++ b/rich/cells.py @@ -2,11 +2,11 @@ from functools import lru_cache from operator import itemgetter -from typing import Callable, NamedTuple, Sequence, Tuple +from typing import Callable, NamedTuple, Sequence from rich._unicode_data import load as load_cell_table -CellSpan = Tuple[int, int, int] +CellSpan = tuple[int, int, int] _span_get_cell_len = itemgetter(2) @@ -160,7 +160,7 @@ def _cell_len(text: str, unicode_version: str) -> int: def split_graphemes( text: str, unicode_version: str = "auto" -) -> "tuple[list[CellSpan], int]": +) -> tuple[list[CellSpan], int]: """Divide text into spans that define a single grapheme, and additionally return the cell length of the whole string. The returned spans will cover every index in the string, with no gaps. It is possible for some graphemes to have a cell length of zero. diff --git a/tests/test_cells.py b/tests/test_cells.py index 0aff1159bf..814013a86e 100644 --- a/tests/test_cells.py +++ b/tests/test_cells.py @@ -11,6 +11,7 @@ cell_len, chop_cells, get_character_cell_size, + set_cell_size, split_graphemes, split_text, ) @@ -252,3 +253,31 @@ def test_non_printable(): for ordinal in range(31): character = chr(ordinal) assert cell_len(character) == 0 + + +def test_cell_len_edge_cases() -> None: + """cell_len for empty strings, ZWJ sequences, and mixed CJK.""" + assert cell_len("") == 0 + assert cell_len("👩\u200d🔧") == 2 + assert cell_len("👩\u200d👩\u200d👧\u200d👧") == 2 + assert cell_len("あ1り2") == 6 + + +def test_set_cell_size_edge_cases() -> None: + """set_cell_size for empty strings and exact-boundary cases.""" + assert set_cell_size("", 0) == "" + assert set_cell_size("", 3) == " " + assert set_cell_size("foo", 3) == "foo" + assert set_cell_size("あい", 4) == "あい" + assert set_cell_size("あ1り2", 6) == "あ1り2" + assert set_cell_size("👩\u200d🔧", 2) == "👩\u200d🔧" + assert set_cell_size("👩\u200d🔧", 1) == " " + + +def test_chop_cells_edge_cases() -> None: + """chop_cells for empty strings, ZWJ sequences, and mixed CJK boundaries.""" + assert chop_cells("", 3) == [] + assert chop_cells("👩\u200d🔧", 2) == ["👩\u200d🔧"] + assert chop_cells("👩\u200d🔧👩\u200d🔧", 2) == ["👩\u200d🔧", "👩\u200d🔧"] + assert chop_cells("あ1り2", 3) == ["あ1", "り2"] + assert chop_cells("あ1り2", 6) == ["あ1り2"]