Skip to content

Commit 9589f0a

Browse files
committed
Add cache decorator example and improve docs
Introduces a basic example for the cache decorator in Flet, updates documentation to include usage and example, and refines the cache decorator implementation with improved comments and docstring. Also fixes a minor docstring typo in base_control.py.
1 parent 0897463 commit 9589f0a

File tree

4 files changed

+81
-6
lines changed

4 files changed

+81
-6
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import logging
2+
from dataclasses import dataclass, field
3+
4+
import flet as ft
5+
6+
logging.basicConfig(level=logging.DEBUG)
7+
8+
9+
@dataclass
10+
class AppState:
11+
number: int = 0
12+
items: list[int] = field(default_factory=list)
13+
14+
def __post_init__(self):
15+
for _ in range(10):
16+
self.add_item()
17+
18+
def add_item(self):
19+
self.items.append(self.number)
20+
self.number += 1
21+
22+
23+
@ft.cache
24+
def item_view(i: int):
25+
return ft.Container(
26+
ft.Text(f"Item {i}"),
27+
padding=10,
28+
bgcolor=ft.Colors.AMBER_100,
29+
key=i,
30+
)
31+
32+
33+
def main(page: ft.Page):
34+
state = AppState()
35+
36+
page.floating_action_button = ft.FloatingActionButton(
37+
icon=ft.Icons.ADD, on_click=state.add_item
38+
)
39+
page.add(
40+
ft.ControlBuilder(
41+
state,
42+
lambda state: ft.SafeArea(
43+
ft.Row([item_view(i) for i in state.items], wrap=True)
44+
),
45+
expand=True,
46+
)
47+
)
48+
49+
50+
ft.run(main)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
::: flet.cache
2+
3+
## Examples
4+
5+
### Cached item view
6+
7+
```python
8+
--8<-- "../../examples/controls/decorators/cache/basic.py"
9+
```

sdk/python/packages/flet/src/flet/controls/base_control.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def control(
6060
isolated: If `True`, marks the control as isolated. An isolated control
6161
is excluded from page updates when its parent control is updated.
6262
post_init_args: Number of InitVar arguments to pass to __post_init__.
63-
**dataclass_kwargs: Additional keyword arguments passed to @dataclass.
63+
dataclass_kwargs: Additional keyword arguments passed to @dataclass.
6464
6565
Usage:
6666
- Supports `@control` (without parentheses)

sdk/python/packages/flet/src/flet/controls/cache.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
R = TypeVar("R")
88

99

10-
# --- Utility to create a hashable signature from args ---
1110
def _hash_args(*args, **kwargs):
1211
try:
1312
# Convert args/kwargs to a string and hash it
@@ -18,7 +17,6 @@ def _hash_args(*args, **kwargs):
1817
return str(id(args)) + str(id(kwargs))
1918

2019

21-
# --- Freeze controls in the returned structure ---
2220
def _freeze_controls(control):
2321
if isinstance(control, list):
2422
return [_freeze_controls(c) for c in control]
@@ -29,9 +27,6 @@ def _freeze_controls(control):
2927
return control
3028

3129

32-
# --- Main decorator with `freeze` option ---
33-
34-
3530
@overload
3631
def cache(
3732
_fn: None = ..., *, freeze: bool = False
@@ -41,28 +36,50 @@ def cache(_fn: Callable[P, R], *, freeze: bool = False) -> Callable[P, R]: ...
4136

4237

4338
def cache(_fn: Optional[Callable[P, R]] = None, *, freeze: bool = False):
39+
"""
40+
A decorator to cache the results of a function based on its arguments.
41+
Used with Flet controls to optimize comparisons in declarative apps.
42+
43+
Args:
44+
_fn: The function to be decorated.
45+
If None, the decorator is used with arguments.
46+
freeze: If `True`, freezes the returned controls
47+
by setting a `_frozen` attribute.
48+
49+
Returns:
50+
A decorated function that caches its results.
51+
"""
52+
4453
def decorator(fn: Callable[P, R]) -> Callable[P, R]:
54+
# Use a weak reference dictionary to store cached results
4555
cache_store = weakref.WeakValueDictionary()
4656

4757
@functools.wraps(fn)
4858
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
59+
# Generate a unique hash key based on the function arguments
4960
key = _hash_args(*args, **kwargs)
5061

62+
# Return cached result if it exists
5163
if key in cache_store:
5264
return cache_store[key]
5365

66+
# Call the original function and cache the result
5467
result = fn(*args, **kwargs)
5568
if result is not None:
5669
if freeze:
70+
# Freeze the controls if the freeze flag is set
5771
_freeze_controls(result)
5872
cache_store[key] = result
5973
elif key in cache_store:
74+
# Remove the cache entry if the result is None
6075
del cache_store[key]
6176
return result
6277

6378
return wrapper
6479

80+
# If _fn is None, return the decorator itself for use with arguments
6581
if _fn is None:
6682
return decorator
6783
else:
84+
# Apply the decorator directly if _fn is provided
6885
return decorator(_fn)

0 commit comments

Comments
 (0)