diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a43681f75..94c1489622 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Breaking change: `DOMNode.has_pseudo_class` now accepts a single name only https://github.com/Textualize/textual/pull/3970 +- Made `textual.cache` (formerly `textual._cache`) public https://github.com/Textualize/textual/pull/3976 ### Added diff --git a/docs/api/cache.md b/docs/api/cache.md new file mode 100644 index 0000000000..fe144a64c6 --- /dev/null +++ b/docs/api/cache.md @@ -0,0 +1 @@ +::: textual.cache diff --git a/mkdocs-nav.yml b/mkdocs-nav.yml index 68f1723917..2296ac92fc 100644 --- a/mkdocs-nav.yml +++ b/mkdocs-nav.yml @@ -175,6 +175,7 @@ nav: - "api/await_complete.md" - "api/await_remove.md" - "api/binding.md" + - "api/cache.md" - "api/color.md" - "api/command.md" - "api/containers.md" diff --git a/src/textual/_cache.py b/src/textual/cache.py similarity index 91% rename from src/textual/_cache.py rename to src/textual/cache.py index 79a589ff0e..3772090b17 100644 --- a/src/textual/_cache.py +++ b/src/textual/cache.py @@ -1,14 +1,9 @@ """ -A LRU (Least Recently Used) Cache container. +Containers to implement caching. -Use when you want to cache slow operations and new keys are a good predictor -of subsequent keys. +These are used in Textual to avoid recalculating expensive operations, such as rendering. -Note that stdlib's @lru_cache is implemented in C and faster! It's best to use -@lru_cache where you are caching things that are fairly quick and called many times. -Use LRUCache where you want increased flexibility and you are caching slow operations -where the overhead of the cache is a small fraction of the total processing time. """ from __future__ import annotations @@ -34,6 +29,11 @@ class LRUCache(Generic[CacheKey, CacheValue]): Each entry is stored as [PREV, NEXT, KEY, VALUE] where PREV is a reference to the previous entry, and NEXT is a reference to the next value. + + Note that stdlib's @lru_cache is implemented in C and faster! It's best to use + @lru_cache where you are caching things that are fairly quick and called many times. + Use LRUCache where you want increased flexibility and you are caching slow operations + where the overhead of the cache is a small fraction of the total processing time. """ __slots__ = [ @@ -46,6 +46,11 @@ class LRUCache(Generic[CacheKey, CacheValue]): ] def __init__(self, maxsize: int) -> None: + """Initialize a LRUCache. + + Args: + maxsize: Maximum size of the cache, before old items are discarded. + """ self._maxsize = maxsize self._cache: Dict[CacheKey, list[object]] = {} self._full = False @@ -208,8 +213,6 @@ class FIFOCache(Generic[CacheKey, CacheValue]): It is most suitable for a cache with a relatively low maximum size that is not expected to do many lookups. - Args: - maxsize: Maximum size of the cache. """ __slots__ = [ @@ -220,6 +223,11 @@ class FIFOCache(Generic[CacheKey, CacheValue]): ] def __init__(self, maxsize: int) -> None: + """Initialize a FIFOCache. + + Args: + maxsize: Maximum size of cache before discarding items. + """ self._maxsize = maxsize self._cache: dict[CacheKey, CacheValue] = {} self.hits = 0 diff --git a/src/textual/css/stylesheet.py b/src/textual/css/stylesheet.py index e56ed6a873..0728f7584d 100644 --- a/src/textual/css/stylesheet.py +++ b/src/textual/css/stylesheet.py @@ -14,7 +14,7 @@ from rich.panel import Panel from rich.text import Text -from .._cache import LRUCache +from ..cache import LRUCache from ..dom import DOMNode from ..widget import Widget from .errors import StylesheetError diff --git a/src/textual/fuzzy.py b/src/textual/fuzzy.py index 40aa35b363..236f83e32c 100644 --- a/src/textual/fuzzy.py +++ b/src/textual/fuzzy.py @@ -13,7 +13,7 @@ from rich.style import Style from rich.text import Text -from ._cache import LRUCache +from .cache import LRUCache @rich.repr.auto diff --git a/src/textual/strip.py b/src/textual/strip.py index 3f90414cae..7bad6e6c3e 100644 --- a/src/textual/strip.py +++ b/src/textual/strip.py @@ -16,8 +16,8 @@ from rich.segment import Segment from rich.style import Style, StyleType -from ._cache import FIFOCache from ._segment_tools import index_to_cell_position +from .cache import FIFOCache from .color import Color from .constants import DEBUG from .filter import LineFilter diff --git a/src/textual/suggester.py b/src/textual/suggester.py index 505993b43a..56e9cfad72 100644 --- a/src/textual/suggester.py +++ b/src/textual/suggester.py @@ -10,7 +10,7 @@ from dataclasses import dataclass from typing import Iterable -from ._cache import LRUCache +from .cache import LRUCache from .dom import DOMNode from .message import Message diff --git a/src/textual/widget.py b/src/textual/widget.py index 1f39e54588..998412d9ec 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -42,7 +42,6 @@ from . import constants, errors, events, messages from ._animator import DEFAULT_EASING, Animatable, BoundAnimator, EasingFunction from ._arrange import DockArrangeResult, arrange -from ._cache import FIFOCache from ._compose import compose from ._context import NoActiveAppError, active_app from ._easing import DEFAULT_SCROLL_EASING @@ -52,6 +51,7 @@ from .actions import SkipAction from .await_remove import AwaitRemove from .box_model import BoxModel +from .cache import FIFOCache from .css.query import NoMatches, WrongType from .css.scalar import ScalarOffset from .dom import DOMNode, NoScreen diff --git a/src/textual/widgets/_data_table.py b/src/textual/widgets/_data_table.py index e2a5a00228..55ae0b47c4 100644 --- a/src/textual/widgets/_data_table.py +++ b/src/textual/widgets/_data_table.py @@ -16,11 +16,11 @@ from typing_extensions import Literal, Self, TypeAlias from .. import events -from .._cache import LRUCache from .._segment_tools import line_crop from .._two_way_dict import TwoWayDict from .._types import SegmentLines from ..binding import Binding, BindingType +from ..cache import LRUCache from ..color import Color from ..coordinate import Coordinate from ..geometry import Region, Size, Spacing, clamp diff --git a/src/textual/widgets/_log.py b/src/textual/widgets/_log.py index 0f4a4bc6be..df5b645c4f 100644 --- a/src/textual/widgets/_log.py +++ b/src/textual/widgets/_log.py @@ -10,8 +10,8 @@ from rich.text import Text from .. import work -from .._cache import LRUCache from .._line_split import line_split +from ..cache import LRUCache from ..geometry import Size from ..reactive import var from ..scroll_view import ScrollView diff --git a/src/textual/widgets/_rich_log.py b/src/textual/widgets/_rich_log.py index a596b0e402..809a30b4d6 100644 --- a/src/textual/widgets/_rich_log.py +++ b/src/textual/widgets/_rich_log.py @@ -12,7 +12,7 @@ from rich.segment import Segment from rich.text import Text -from .._cache import LRUCache +from ..cache import LRUCache from ..geometry import Region, Size from ..reactive import var from ..scroll_view import ScrollView diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index 501efefd66..43a079a5eb 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -10,11 +10,11 @@ from rich.text import Text, TextType from .. import events -from .._cache import LRUCache from .._immutable_sequence_view import ImmutableSequenceView from .._loop import loop_last from .._segment_tools import line_pad from ..binding import Binding, BindingType +from ..cache import LRUCache from ..geometry import Region, Size, clamp from ..message import Message from ..reactive import reactive, var diff --git a/tests/test_cache.py b/tests/test_cache.py index 935c5dbfbe..2db7b73759 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -2,7 +2,7 @@ import pytest -from textual._cache import FIFOCache, LRUCache +from textual.cache import FIFOCache, LRUCache def test_lru_cache():