Skip to content

Commit

Permalink
fix: escape cell contents if bad Rich markup; improve tooltip formatt…
Browse files Browse the repository at this point in the history
…ing (#119)
  • Loading branch information
tconbeer authored Jul 10, 2024
1 parent 373f01d commit 169bee9
Show file tree
Hide file tree
Showing 9 changed files with 637 additions and 692 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ jobs:
- name: Run analysis
run: |
source .venv/bin/activate
black . --check
ruff .
ruff format --check
ruff check .
mypy
11 changes: 4 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
repos:
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.1.4
rev: v0.5.1
hooks:
- id: ruff-format
- id: ruff
args: [ --fix, --exit-non-zero-on-fix ]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
rev: v1.10.1
hooks:
- id: mypy
additional_dependencies:
- textual>=0.48.1
- textual>=0.72.0
- pytest
- pyarrow-stubs
- pandas-stubs
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

- Fixes a crash when cell contents contained bad Rich Markdown ([tconbeer/harlequin#569](https://github.com/tconbeer/harlequin/issues/569)).
- Improves the appearance of data tooltips.

## [0.7.1] - 2024-02-09

- Adds a `backend.source_data` property to exposue the underlying Arrow table, before slicing.
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
.PHONY: check
check:
black .
ruff format .
pytest
ruff . --fix
ruff check . --fix
mypy

.PHONY: lint
lint:
black .
ruff . --fix
ruff format .
ruff check . --fix
mypy

.PHONY: serve
Expand Down
722 changes: 325 additions & 397 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ numpy = { version="^1", python=">=3.9,<3.13" }
pyinstrument = "^4.6.0"

[tool.poetry.group.static.dependencies]
black = "^23.3.0"
ruff = ">=0.2,<0.5"
mypy = "^1.2.0"
ruff = "^0.5"
mypy = "^1.10.0"
pandas-stubs = { version="^2.1.1", python=">=3.9,<3.13" }

[tool.poetry.group.test.dependencies]
Expand Down
30 changes: 21 additions & 9 deletions src/textual_fastdatatable/data_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from __future__ import annotations

import functools
from datetime import date, datetime, time, timedelta
from decimal import Decimal
from itertools import chain, zip_longest
from typing import Any, ClassVar, Iterable, NamedTuple, Tuple, Union

Expand Down Expand Up @@ -557,7 +559,9 @@ def __init__(
backend
if backend is not None
else create_backend(
data, max_rows=max_rows, has_header=(column_labels is None) # type: ignore
data, # type: ignore[arg-type]
max_rows=max_rows,
has_header=(column_labels is None), # type: ignore
)
)
except (TypeError, OSError) as e:
Expand All @@ -584,9 +588,9 @@ def __init__(
"""Cache for individual cells."""
self._line_cache: LRUCache[LineCacheKey, Strip] = LRUCache(1000)
"""Cache for lines within rows."""
self._tooltip_cache: LRUCache[
TooltipCacheKey, RenderableType | None
] = LRUCache(1000)
self._tooltip_cache: LRUCache[TooltipCacheKey, RenderableType | None] = (
LRUCache(1000)
)
"""Cache for values for the tooltip"""
# self._offset_cache: LRUCache[int, list[tuple[RowKey, int]]] = LRUCache(1)
"""Cached y_offset - key is update_count - see y_offsets property for more
Expand Down Expand Up @@ -2424,7 +2428,9 @@ async def move_cursor_to_mouse_down(self, event: events.MouseDown) -> None:
# TODO: support row labels.
# row = self.ordered_rows[row_index]
row_message = DataTable.RowLabelSelected(
self, row_index, label=Text() # label=row.label
self,
row_index,
label=Text(), # label=row.label
)
self.post_message(row_message)
elif self.show_cursor and self.cursor_type != "none":
Expand Down Expand Up @@ -2499,9 +2505,10 @@ def set_hover_or_cursor_from_mouse(self, event: events.MouseMove) -> None:
def _set_tooltip_from_cell_at(self, coordinate: Coordinate) -> None:
# TODO: support row labels
cache_key = (coordinate.row, coordinate.column, self._update_count)
column = self.ordered_columns[coordinate.column]
if cache_key not in self._tooltip_cache:
if coordinate.row == -1: # hover over header
raw_value = self.ordered_columns[coordinate.column].label
raw_value = column.label
else:
raw_value = self.get_cell_at(coordinate)
if raw_value is None:
Expand All @@ -2510,11 +2517,16 @@ def _set_tooltip_from_cell_at(self, coordinate: Coordinate) -> None:
if (
self.max_column_content_width is not None
and measured_width > self.max_column_content_width
) or (
measured_width > self.ordered_columns[coordinate.column].render_width
):
) or (measured_width > column.render_width):
if isinstance(raw_value, Text):
self._tooltip_cache[cache_key] = raw_value
elif isinstance(
raw_value,
(str, float, Decimal, int, datetime, time, date, timedelta),
):
self._tooltip_cache[cache_key] = cell_formatter(
raw_value, null_rep=self.null_rep, col=column
)
else:
self._tooltip_cache[cache_key] = Pretty(raw_value)
else:
Expand Down
8 changes: 7 additions & 1 deletion src/textual_fastdatatable/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from rich.align import Align
from rich.console import Console, RenderableType
from rich.errors import MarkupError
from rich.markup import escape
from rich.protocol import is_renderable
from rich.text import Text

Expand All @@ -29,7 +31,11 @@ def cell_formatter(
if obj is None:
return Align(null_rep, align="center")
elif isinstance(obj, str):
return Text.from_markup(obj)
try:
rich_text: Text | str = Text.from_markup(obj)
except MarkupError:
rich_text = escape(obj)
return rich_text
elif isinstance(obj, bool):
return Align(
f"[dim]{'✓' if obj else 'X'}[/] {obj}{' ' if obj else ''}",
Expand Down
538 changes: 269 additions & 269 deletions tests/snapshot_tests/__snapshots__/test_snapshots.ambr

Large diffs are not rendered by default.

0 comments on commit 169bee9

Please sign in to comment.