pypi-streamlit

Description
A faster way to build and share data apps
Author
tessl
Last updated

How to use

npx @tessl/cli registry install tessl/pypi-streamlit@1.49.0

state-caching.md docs/

1
# State and Caching
2
3
State management, caching mechanisms, and performance optimization tools for maintaining application state and improving performance through intelligent data persistence.
4
5
## Capabilities
6
7
### Session State Management
8
9
Persistent state storage across user interactions and app reruns.
10
11
```python { .api }
12
# Session state proxy object
13
session_state: SessionStateProxy
14
15
# Access patterns:
16
# st.session_state.key = value # Set value
17
# value = st.session_state.key # Get value
18
# st.session_state["key"] = value # Dictionary-style set
19
# value = st.session_state["key"] # Dictionary-style get
20
# del st.session_state.key # Delete key
21
# "key" in st.session_state # Check existence
22
# st.session_state.clear() # Clear all state
23
```
24
25
### Query Parameters Management
26
27
URL query parameter handling for shareable application state.
28
29
```python { .api }
30
# Query parameters proxy object
31
query_params: QueryParamsProxy
32
33
# Access patterns:
34
# st.query_params.key = value # Set parameter
35
# value = st.query_params.key # Get parameter
36
# st.query_params["key"] = value # Dictionary-style set
37
# value = st.query_params["key"] # Dictionary-style get
38
# del st.query_params.key # Delete parameter
39
# st.query_params.clear() # Clear all parameters
40
# dict(st.query_params) # Convert to dictionary
41
```
42
43
### Data Caching
44
45
Cache function execution results to improve performance and reduce redundant computations.
46
47
```python { .api }
48
def cache_data(func=None, *, ttl=None, max_entries=None, show_spinner=True, persist=None, experimental_allow_widgets=False, hash_funcs=None, max_entries_per_session=None, validate=None):
49
"""
50
Function decorator to cache the result of function calls.
51
52
Parameters:
53
- func (callable): Function to cache (auto-filled when used as decorator)
54
- ttl (float): Time to live in seconds (None for no expiration)
55
- max_entries (int): Maximum number of cached entries (None for unlimited)
56
- show_spinner (bool): Show spinner while function executes
57
- persist (bool): Persist cache across app restarts (experimental)
58
- experimental_allow_widgets (bool): Allow widgets inside cached function
59
- hash_funcs (dict): Custom hash functions for parameters
60
- max_entries_per_session (int): Maximum entries per session
61
- validate (callable): Function to validate cached values
62
63
Returns:
64
callable: Decorated function with caching capability
65
"""
66
```
67
68
### Resource Caching
69
70
Cache global resources like database connections, models, and expensive objects.
71
72
```python { .api }
73
def cache_resource(func=None, *, ttl=None, max_entries=None, show_spinner=True, validate=None, experimental_allow_widgets=False, hash_funcs=None):
74
"""
75
Function decorator to cache global resources.
76
77
Parameters:
78
- func (callable): Function to cache (auto-filled when used as decorator)
79
- ttl (float): Time to live in seconds (None for no expiration)
80
- max_entries (int): Maximum number of cached resources (None for unlimited)
81
- show_spinner (bool): Show spinner while function executes
82
- validate (callable): Function to validate cached resources
83
- experimental_allow_widgets (bool): Allow widgets inside cached function
84
- hash_funcs (dict): Custom hash functions for parameters
85
86
Returns:
87
callable: Decorated function with resource caching capability
88
"""
89
```
90
91
### Legacy Caching
92
93
Deprecated caching decorator for backward compatibility.
94
95
```python { .api }
96
def cache(func=None, **kwargs):
97
"""
98
Legacy caching decorator (deprecated).
99
100
Note: This function is deprecated. Use st.cache_data or st.cache_resource instead.
101
102
Parameters:
103
- func (callable): Function to cache
104
- **kwargs: Cache configuration options
105
106
Returns:
107
callable: Decorated function with caching
108
"""
109
```
110
111
## Usage Examples
112
113
### Basic Session State
114
115
```python
116
import streamlit as st
117
118
# Initialize session state
119
if 'count' not in st.session_state:
120
st.session_state.count = 0
121
122
if 'user_name' not in st.session_state:
123
st.session_state.user_name = ''
124
125
# Display current state
126
st.write(f"Count: {st.session_state.count}")
127
st.write(f"User: {st.session_state.user_name}")
128
129
# Modify state with buttons
130
col1, col2, col3 = st.columns(3)
131
132
with col1:
133
if st.button('Increment'):
134
st.session_state.count += 1
135
136
with col2:
137
if st.button('Decrement'):
138
st.session_state.count -= 1
139
140
with col3:
141
if st.button('Reset'):
142
st.session_state.count = 0
143
144
# Update user name
145
new_name = st.text_input('Enter your name:', value=st.session_state.user_name)
146
if new_name != st.session_state.user_name:
147
st.session_state.user_name = new_name
148
```
149
150
### Advanced Session State Patterns
151
152
```python
153
# Session state with complex data structures
154
if 'shopping_cart' not in st.session_state:
155
st.session_state.shopping_cart = []
156
157
if 'user_preferences' not in st.session_state:
158
st.session_state.user_preferences = {
159
'theme': 'light',
160
'notifications': True,
161
'language': 'en'
162
}
163
164
# Add item to cart
165
def add_to_cart(item, price):
166
st.session_state.shopping_cart.append({
167
'item': item,
168
'price': price,
169
'quantity': 1
170
})
171
172
# Display cart
173
st.subheader("Shopping Cart")
174
if st.session_state.shopping_cart:
175
for i, item in enumerate(st.session_state.shopping_cart):
176
col1, col2, col3 = st.columns([2, 1, 1])
177
with col1:
178
st.write(item['item'])
179
with col2:
180
st.write(f"${item['price']:.2f}")
181
with col3:
182
if st.button('Remove', key=f'remove_{i}'):
183
st.session_state.shopping_cart.pop(i)
184
st.rerun()
185
186
total = sum(item['price'] for item in st.session_state.shopping_cart)
187
st.write(f"**Total: ${total:.2f}**")
188
else:
189
st.write("Cart is empty")
190
191
# Add new items
192
st.subheader("Add Items")
193
item_name = st.text_input("Item name:")
194
item_price = st.number_input("Price:", min_value=0.01, format="%.2f")
195
196
if st.button("Add to Cart") and item_name:
197
add_to_cart(item_name, item_price)
198
st.success(f"Added {item_name} to cart!")
199
```
200
201
### Query Parameters for Shareable State
202
203
```python
204
# Initialize from query parameters
205
if 'page' not in st.query_params:
206
st.query_params.page = 'home'
207
208
if 'filter' not in st.query_params:
209
st.query_params.filter = 'all'
210
211
# Navigation that updates URL
212
st.sidebar.title("Navigation")
213
214
pages = ['home', 'analytics', 'settings']
215
current_page = st.sidebar.selectbox(
216
"Select page:",
217
pages,
218
index=pages.index(st.query_params.page) if st.query_params.page in pages else 0
219
)
220
221
# Update query params when page changes
222
if current_page != st.query_params.page:
223
st.query_params.page = current_page
224
st.rerun()
225
226
# Filters that update URL
227
filters = ['all', 'active', 'inactive']
228
current_filter = st.sidebar.selectbox(
229
"Filter:",
230
filters,
231
index=filters.index(st.query_params.filter) if st.query_params.filter in filters else 0
232
)
233
234
if current_filter != st.query_params.filter:
235
st.query_params.filter = current_filter
236
st.rerun()
237
238
# Display content based on query params
239
st.title(f"Page: {st.query_params.page}")
240
st.write(f"Filter: {st.query_params.filter}")
241
242
# Show shareable URL
243
st.info(f"Share this URL: {st.query_params}")
244
```
245
246
### Data Caching
247
248
```python
249
import pandas as pd
250
import time
251
import requests
252
253
@st.cache_data
254
def load_data(url):
255
"""Load data from URL with caching."""
256
st.info(f"Loading data from {url}...")
257
response = requests.get(url)
258
return pd.read_csv(response.content)
259
260
@st.cache_data(ttl=300) # Cache for 5 minutes
261
def expensive_computation(n):
262
"""Simulate expensive computation with TTL."""
263
st.info("Running expensive computation...")
264
time.sleep(2) # Simulate processing time
265
return sum(i**2 for i in range(n))
266
267
@st.cache_data(max_entries=10)
268
def process_data(data, operation):
269
"""Process data with limited cache size."""
270
st.info(f"Processing data with {operation}...")
271
if operation == 'sum':
272
return data.sum()
273
elif operation == 'mean':
274
return data.mean()
275
elif operation == 'max':
276
return data.max()
277
else:
278
return data
279
280
# Use cached functions
281
st.subheader("Cached Data Loading")
282
283
# This will only run once per URL
284
try:
285
df = load_data("https://raw.githubusercontent.com/datasets/iris/master/data/iris.csv")
286
st.dataframe(df.head())
287
except Exception as e:
288
st.error(f"Failed to load data: {e}")
289
290
# Expensive computation with TTL
291
st.subheader("Cached Computation")
292
n = st.slider("Computation size:", 1000, 10000, 5000)
293
result = expensive_computation(n)
294
st.write(f"Result: {result}")
295
296
# Data processing with limited cache
297
if 'df' in locals():
298
operation = st.selectbox("Operation:", ['sum', 'mean', 'max'])
299
numeric_cols = df.select_dtypes(include=['number']).columns
300
if len(numeric_cols) > 0:
301
processed = process_data(df[numeric_cols[0]], operation)
302
st.write(f"Result: {processed}")
303
```
304
305
### Resource Caching
306
307
```python
308
import sqlite3
309
from datetime import datetime
310
311
@st.cache_resource
312
def init_database():
313
"""Initialize database connection (cached resource)."""
314
st.info("Initializing database connection...")
315
conn = sqlite3.connect(':memory:')
316
317
# Create sample table
318
conn.execute('''
319
CREATE TABLE users (
320
id INTEGER PRIMARY KEY,
321
name TEXT,
322
email TEXT,
323
created_at TIMESTAMP
324
)
325
''')
326
327
# Insert sample data
328
sample_users = [
329
('Alice', 'alice@example.com'),
330
('Bob', 'bob@example.com'),
331
('Charlie', 'charlie@example.com')
332
]
333
334
for name, email in sample_users:
335
conn.execute(
336
'INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)',
337
(name, email, datetime.now())
338
)
339
340
conn.commit()
341
return conn
342
343
@st.cache_resource
344
def load_model():
345
"""Load ML model (simulated)."""
346
st.info("Loading machine learning model...")
347
time.sleep(1) # Simulate model loading time
348
return {"model_type": "random_forest", "accuracy": 0.95, "loaded_at": datetime.now()}
349
350
# Use cached resources
351
st.subheader("Cached Database Connection")
352
db = init_database()
353
354
# Query database
355
users = db.execute('SELECT * FROM users').fetchall()
356
st.write("Users in database:")
357
for user in users:
358
st.write(f"- {user[1]} ({user[2]})")
359
360
st.subheader("Cached Model")
361
model = load_model()
362
st.json(model)
363
```
364
365
### Cache Management
366
367
```python
368
# Cache inspection and management
369
st.subheader("Cache Management")
370
371
col1, col2, col3 = st.columns(3)
372
373
with col1:
374
if st.button("Clear Data Cache"):
375
st.cache_data.clear()
376
st.success("Data cache cleared!")
377
378
with col2:
379
if st.button("Clear Resource Cache"):
380
st.cache_resource.clear()
381
st.success("Resource cache cleared!")
382
383
with col3:
384
if st.button("Clear All Caches"):
385
st.cache_data.clear()
386
st.cache_resource.clear()
387
st.success("All caches cleared!")
388
389
# Custom hash function example
390
@st.cache_data(
391
hash_funcs={pd.DataFrame: lambda df: df.shape},
392
show_spinner="Processing dataframe..."
393
)
394
def analyze_dataframe(df, analysis_type):
395
"""Analyze dataframe with custom hashing."""
396
time.sleep(1) # Simulate analysis
397
398
if analysis_type == "describe":
399
return df.describe()
400
elif analysis_type == "info":
401
return f"Shape: {df.shape}, Columns: {list(df.columns)}"
402
else:
403
return "Unknown analysis type"
404
405
# Use function with custom hashing
406
if 'df' in locals():
407
analysis = st.selectbox("Analysis type:", ["describe", "info"])
408
result = analyze_dataframe(df, analysis)
409
st.write(result)
410
```
411
412
### State Persistence Patterns
413
414
```python
415
# Multi-step form with state persistence
416
if 'form_step' not in st.session_state:
417
st.session_state.form_step = 1
418
419
if 'form_data' not in st.session_state:
420
st.session_state.form_data = {}
421
422
st.subheader(f"Multi-step Form - Step {st.session_state.form_step}/3")
423
424
# Progress bar
425
progress = st.session_state.form_step / 3
426
st.progress(progress)
427
428
if st.session_state.form_step == 1:
429
st.write("**Personal Information**")
430
name = st.text_input("Name:", value=st.session_state.form_data.get('name', ''))
431
email = st.text_input("Email:", value=st.session_state.form_data.get('email', ''))
432
433
if st.button("Next") and name and email:
434
st.session_state.form_data.update({'name': name, 'email': email})
435
st.session_state.form_step = 2
436
st.rerun()
437
438
elif st.session_state.form_step == 2:
439
st.write("**Preferences**")
440
theme = st.selectbox("Theme:", ["Light", "Dark"],
441
index=["Light", "Dark"].index(st.session_state.form_data.get('theme', 'Light')))
442
notifications = st.checkbox("Enable notifications",
443
value=st.session_state.form_data.get('notifications', False))
444
445
col1, col2 = st.columns(2)
446
with col1:
447
if st.button("Back"):
448
st.session_state.form_step = 1
449
st.rerun()
450
451
with col2:
452
if st.button("Next"):
453
st.session_state.form_data.update({'theme': theme, 'notifications': notifications})
454
st.session_state.form_step = 3
455
st.rerun()
456
457
elif st.session_state.form_step == 3:
458
st.write("**Review & Submit**")
459
st.json(st.session_state.form_data)
460
461
col1, col2 = st.columns(2)
462
with col1:
463
if st.button("Back"):
464
st.session_state.form_step = 2
465
st.rerun()
466
467
with col2:
468
if st.button("Submit"):
469
st.success("Form submitted successfully!")
470
st.balloons()
471
# Reset form
472
st.session_state.form_step = 1
473
st.session_state.form_data = {}
474
```
475
476
### Cache Validation
477
478
```python
479
@st.cache_data(
480
validate=lambda cached_value: len(cached_value) > 0,
481
ttl=60
482
)
483
def get_api_data(endpoint):
484
"""Fetch API data with validation."""
485
# Simulate API call
486
time.sleep(0.5)
487
if endpoint == "valid":
488
return ["item1", "item2", "item3"]
489
else:
490
return [] # This will invalidate the cache
491
492
# Use validated cache
493
endpoint = st.selectbox("API Endpoint:", ["valid", "empty"])
494
data = get_api_data(endpoint)
495
496
if data:
497
st.success(f"Got {len(data)} items from cache/API")
498
st.write(data)
499
else:
500
st.warning("No data available (cache invalidated)")
501
```