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

advanced-features.md docs/

1
# Advanced Features
2
3
Advanced Streamlit functionality including authentication, navigation, fragments, dialogs, custom components, and data connections for sophisticated application development.
4
5
## Capabilities
6
7
### Multi-page Navigation
8
9
Navigate between multiple pages in a Streamlit application.
10
11
```python { .api }
12
def navigation(pages, position="sidebar"):
13
"""
14
Render a navigation widget for multipage apps.
15
16
Parameters:
17
- pages (list): List of Page objects or page configuration dicts
18
- position (str): Navigation position ('sidebar' or 'main')
19
20
Returns:
21
Page: Currently selected page object
22
"""
23
24
class Page:
25
"""
26
Configure a page for st.navigation in a multipage app.
27
28
Parameters:
29
- page: Callable function or file path for the page
30
- title (str): Page title (optional, inferred from function name or filename)
31
- icon (str): Page icon (emoji or icon name)
32
- url_path (str): Custom URL path for the page
33
- default (bool): Whether this is the default page
34
"""
35
def __init__(self, page, title=None, icon=None, url_path=None, default=False):
36
pass
37
```
38
39
### Fragments
40
41
Create independently rerunning code sections for improved performance.
42
43
```python { .api }
44
def fragment(func=None, *, run_every=None, rerun_on_update=True):
45
"""
46
Turn a function into a fragment that can rerun independently of the main app.
47
48
Parameters:
49
- func (callable): Function to turn into a fragment
50
- run_every (float): Auto-rerun interval in seconds
51
- rerun_on_update (bool): Rerun fragment when its state changes
52
53
Returns:
54
callable: Fragment function decorator
55
"""
56
```
57
58
### Dialog Modals
59
60
Create modal dialog overlays for focused user interactions.
61
62
```python { .api }
63
def dialog(title, *, width="large"):
64
"""
65
Create a modal dialog overlay.
66
67
Parameters:
68
- title (str): Dialog title
69
- width (str): Dialog width ('small', 'medium', 'large')
70
71
Returns:
72
ContextManager: Dialog context manager
73
"""
74
```
75
76
### Authentication
77
78
User authentication and session management.
79
80
```python { .api }
81
def login(user_info_provider=None, **kwargs):
82
"""
83
Display a login widget and authenticate the user.
84
85
Parameters:
86
- user_info_provider: Custom user information provider
87
- **kwargs: Additional authentication configuration
88
89
Returns:
90
bool: True if login was successful
91
"""
92
93
def logout(button_text="Logout"):
94
"""
95
Display a logout button.
96
97
Parameters:
98
- button_text (str): Text for the logout button
99
100
Returns:
101
bool: True if logout button was clicked
102
"""
103
104
# User information proxy
105
user: UserInfoProxy
106
```
107
108
### Data Connections
109
110
Connect to external data sources and databases.
111
112
```python { .api }
113
def connection(name, type=None, **kwargs):
114
"""
115
Create or retrieve a connection to a data source.
116
117
Parameters:
118
- name (str): Connection name
119
- type (str): Connection type ('sql', 'snowflake', etc.)
120
- **kwargs: Connection-specific configuration parameters
121
122
Returns:
123
BaseConnection: Connection object
124
"""
125
```
126
127
### Connection Classes
128
129
Base classes for creating custom data connections.
130
131
```python { .api }
132
class BaseConnection:
133
"""Base class for creating data connections."""
134
135
def query(self, query, **kwargs):
136
"""Execute a query against the connection."""
137
pass
138
139
def reset(self):
140
"""Reset the connection."""
141
pass
142
143
class SQLConnection(BaseConnection):
144
"""Connection for SQL databases."""
145
146
def query(self, query, params=None, ttl=None, **kwargs):
147
"""Execute SQL query with optional caching."""
148
pass
149
150
class SnowflakeConnection(BaseConnection):
151
"""Connection for Snowflake data warehouse."""
152
153
def query(self, query, params=None, ttl=None, **kwargs):
154
"""Execute Snowflake query."""
155
pass
156
157
def write_pandas(self, df, table_name, **kwargs):
158
"""Write pandas DataFrame to Snowflake."""
159
pass
160
161
class SnowparkConnection(BaseConnection):
162
"""Connection for Snowpark operations."""
163
164
def session(self):
165
"""Get Snowpark session."""
166
pass
167
```
168
169
### Custom Components
170
171
Integration with custom HTML/JavaScript components.
172
173
```python { .api }
174
# Access via st.components.v1
175
def declare_component(name, path=None, url=None):
176
"""
177
Create and register a custom component.
178
179
Parameters:
180
- name (str): Component name
181
- path (str): Local component directory path
182
- url (str): URL to hosted component
183
184
Returns:
185
callable: Component function
186
"""
187
188
def html(html, width=None, height=None, scrolling=False):
189
"""
190
Render arbitrary HTML in an iframe.
191
192
Parameters:
193
- html (str): HTML content to render
194
- width (int): iframe width in pixels
195
- height (int): iframe height in pixels
196
- scrolling (bool): Enable scrolling
197
198
Returns:
199
Any: Component return value
200
"""
201
202
def iframe(src, width=None, height=None, scrolling=False):
203
"""
204
Render an iframe with specified source.
205
206
Parameters:
207
- src (str): iframe source URL
208
- width (int): iframe width in pixels
209
- height (int): iframe height in pixels
210
- scrolling (bool): Enable scrolling
211
212
Returns:
213
Any: Component return value
214
"""
215
```
216
217
### Chat Interface
218
219
Specialized widgets for building chat applications.
220
221
```python { .api }
222
def chat_message(name, avatar=None):
223
"""
224
Insert a chat message container.
225
226
Parameters:
227
- name (str): Message sender name
228
- avatar (str): Avatar image URL or emoji
229
230
Returns:
231
ContextManager: Chat message context manager
232
"""
233
234
def chat_input(placeholder=None, disabled=False, key=None, max_chars=None, on_submit=None, args=None, kwargs=None):
235
"""
236
Display a chat input widget at the bottom of the app.
237
238
Parameters:
239
- placeholder (str): Placeholder text
240
- disabled (bool): Disable the input
241
- key (str): Unique key for the widget
242
- max_chars (int): Maximum character limit
243
- on_submit (callable): Function to call on message submit
244
- args (tuple): Arguments to pass to on_submit function
245
- kwargs (dict): Keyword arguments to pass to on_submit function
246
247
Returns:
248
str or None: Submitted message text
249
"""
250
```
251
252
## Usage Examples
253
254
### Multi-page Navigation
255
256
```python
257
import streamlit as st
258
259
# Define page functions
260
def home_page():
261
st.title("🏠 Home Page")
262
st.write("Welcome to the home page!")
263
264
st.subheader("Quick Stats")
265
col1, col2, col3 = st.columns(3)
266
267
with col1:
268
st.metric("Users", "1,234", "12%")
269
with col2:
270
st.metric("Revenue", "$56.7K", "8%")
271
with col3:
272
st.metric("Growth", "23%", "2%")
273
274
def analytics_page():
275
st.title("πŸ“Š Analytics")
276
st.write("Analytics dashboard")
277
278
import pandas as pd
279
import numpy as np
280
281
# Sample chart
282
chart_data = pd.DataFrame(
283
np.random.randn(20, 3),
284
columns=['A', 'B', 'C']
285
)
286
st.line_chart(chart_data)
287
288
def settings_page():
289
st.title("βš™οΈ Settings")
290
st.write("Application settings")
291
292
theme = st.selectbox("Theme", ["Light", "Dark", "Auto"])
293
notifications = st.checkbox("Enable notifications", value=True)
294
language = st.selectbox("Language", ["English", "Spanish", "French"])
295
296
if st.button("Save Settings"):
297
st.success("Settings saved!")
298
299
# Configure pages
300
pages = [
301
st.Page(home_page, title="Home", icon="🏠", default=True),
302
st.Page(analytics_page, title="Analytics", icon="πŸ“Š"),
303
st.Page(settings_page, title="Settings", icon="βš™οΈ")
304
]
305
306
# Render navigation
307
current_page = st.navigation(pages)
308
current_page.run()
309
```
310
311
### Fragment Usage
312
313
```python
314
@st.fragment(run_every=5) # Auto-refresh every 5 seconds
315
def live_metrics():
316
"""Fragment that updates independently."""
317
import random
318
import time
319
320
st.subheader("πŸ“Š Live Metrics (Auto-refreshing)")
321
322
col1, col2, col3 = st.columns(3)
323
324
with col1:
325
cpu_usage = random.randint(20, 80)
326
st.metric("CPU Usage", f"{cpu_usage}%", f"{random.randint(-5, 5)}%")
327
328
with col2:
329
memory_usage = random.randint(40, 90)
330
st.metric("Memory", f"{memory_usage}%", f"{random.randint(-3, 3)}%")
331
332
with col3:
333
active_users = random.randint(100, 500)
334
st.metric("Active Users", active_users, random.randint(-20, 50))
335
336
st.caption(f"Last updated: {time.strftime('%H:%M:%S')}")
337
338
@st.fragment
339
def user_feedback():
340
"""Independent feedback fragment."""
341
st.subheader("πŸ’¬ User Feedback")
342
343
if 'feedback_messages' not in st.session_state:
344
st.session_state.feedback_messages = []
345
346
# Feedback form
347
with st.form("feedback_form", clear_on_submit=True):
348
message = st.text_area("Your feedback:")
349
rating = st.slider("Rating:", 1, 5, 3)
350
351
if st.form_submit_button("Submit Feedback"):
352
if message:
353
st.session_state.feedback_messages.append({
354
'message': message,
355
'rating': rating,
356
'timestamp': time.strftime('%H:%M:%S')
357
})
358
st.success("Thank you for your feedback!")
359
360
# Display recent feedback
361
if st.session_state.feedback_messages:
362
st.write("**Recent Feedback:**")
363
for feedback in st.session_state.feedback_messages[-3:]:
364
with st.expander(f"Rating: {feedback['rating']}/5 - {feedback['timestamp']}"):
365
st.write(feedback['message'])
366
367
# Use fragments
368
st.title("Fragment Demo")
369
370
# These fragments update independently
371
live_metrics()
372
st.divider()
373
user_feedback()
374
375
# Regular content (reruns with main app)
376
st.subheader("πŸ”„ Main App Content")
377
st.write("This content reruns with the main app.")
378
if st.button("Refresh Main App"):
379
st.success("Main app refreshed!")
380
```
381
382
### Dialog Modals
383
384
```python
385
# Dialog for user confirmation
386
@st.dialog("Confirm Delete")
387
def confirm_delete_dialog(item_name):
388
st.write(f"Are you sure you want to delete **{item_name}**?")
389
st.warning("This action cannot be undone!")
390
391
col1, col2 = st.columns(2)
392
393
with col1:
394
if st.button("Cancel", use_container_width=True):
395
st.rerun()
396
397
with col2:
398
if st.button("Delete", type="primary", use_container_width=True):
399
st.session_state.deleted_item = item_name
400
st.rerun()
401
402
# Dialog for data input
403
@st.dialog("Add New Item", width="medium")
404
def add_item_dialog():
405
st.write("Enter item details:")
406
407
name = st.text_input("Item name:")
408
category = st.selectbox("Category:", ["Electronics", "Books", "Clothing"])
409
price = st.number_input("Price:", min_value=0.01, format="%.2f")
410
description = st.text_area("Description:")
411
412
col1, col2 = st.columns(2)
413
414
with col1:
415
if st.button("Cancel", use_container_width=True):
416
st.rerun()
417
418
with col2:
419
if st.button("Add Item", type="primary", use_container_width=True):
420
if name and price:
421
if 'items' not in st.session_state:
422
st.session_state.items = []
423
424
st.session_state.items.append({
425
'name': name,
426
'category': category,
427
'price': price,
428
'description': description
429
})
430
st.rerun()
431
else:
432
st.error("Please fill in required fields")
433
434
# Main interface
435
st.title("Dialog Demo")
436
437
# Items list
438
if 'items' not in st.session_state:
439
st.session_state.items = [
440
{'name': 'Laptop', 'category': 'Electronics', 'price': 999.99, 'description': 'Gaming laptop'},
441
{'name': 'Book', 'category': 'Books', 'price': 19.99, 'description': 'Programming guide'}
442
]
443
444
# Add item button
445
if st.button("βž• Add Item"):
446
add_item_dialog()
447
448
# Display items
449
st.subheader("Items")
450
for i, item in enumerate(st.session_state.items):
451
col1, col2, col3, col4 = st.columns([2, 1, 1, 1])
452
453
with col1:
454
st.write(f"**{item['name']}**")
455
st.caption(item['description'])
456
457
with col2:
458
st.write(item['category'])
459
460
with col3:
461
st.write(f"${item['price']:.2f}")
462
463
with col4:
464
if st.button("πŸ—‘οΈ", key=f"delete_{i}", help="Delete item"):
465
confirm_delete_dialog(item['name'])
466
467
# Handle deletion
468
if 'deleted_item' in st.session_state:
469
st.session_state.items = [
470
item for item in st.session_state.items
471
if item['name'] != st.session_state.deleted_item
472
]
473
st.success(f"Deleted {st.session_state.deleted_item}")
474
del st.session_state.deleted_item
475
st.rerun()
476
```
477
478
### Authentication
479
480
```python
481
# Basic authentication example
482
if 'authenticated' not in st.session_state:
483
st.session_state.authenticated = False
484
485
if not st.session_state.authenticated:
486
st.title("πŸ” Login Required")
487
488
# Simple login form
489
with st.form("login_form"):
490
username = st.text_input("Username:")
491
password = st.text_input("Password:", type="password")
492
493
if st.form_submit_button("Login"):
494
# Simple authentication (replace with real auth)
495
if username == "admin" and password == "password":
496
st.session_state.authenticated = True
497
st.session_state.username = username
498
st.success("Login successful!")
499
st.rerun()
500
else:
501
st.error("Invalid credentials")
502
else:
503
# Authenticated content
504
col1, col2 = st.columns([3, 1])
505
506
with col1:
507
st.title(f"Welcome, {st.session_state.username}!")
508
509
with col2:
510
if st.button("Logout"):
511
st.session_state.authenticated = False
512
del st.session_state.username
513
st.rerun()
514
515
# Protected content
516
st.subheader("Protected Dashboard")
517
st.write("This content is only visible to authenticated users.")
518
519
# Sample dashboard
520
col1, col2, col3 = st.columns(3)
521
522
with col1:
523
st.metric("Total Sales", "$45,231", "12%")
524
with col2:
525
st.metric("New Users", "156", "8%")
526
with col3:
527
st.metric("Conversion Rate", "3.2%", "0.5%")
528
```
529
530
### Chat Interface
531
532
```python
533
# Initialize chat history
534
if 'chat_history' not in st.session_state:
535
st.session_state.chat_history = [
536
{"role": "assistant", "content": "Hello! How can I help you today?"}
537
]
538
539
st.title("πŸ’¬ Chat Interface")
540
541
# Display chat history
542
for message in st.session_state.chat_history:
543
with st.chat_message(message["role"]):
544
st.write(message["content"])
545
546
# Chat input
547
if prompt := st.chat_input("Type your message here..."):
548
# Add user message to history
549
st.session_state.chat_history.append({"role": "user", "content": prompt})
550
551
# Display user message
552
with st.chat_message("user"):
553
st.write(prompt)
554
555
# Generate response (simulate AI response)
556
import random
557
responses = [
558
"That's an interesting question!",
559
"I understand what you're asking.",
560
"Let me help you with that.",
561
"That's a great point!",
562
"I see what you mean."
563
]
564
565
response = random.choice(responses) + f" You said: '{prompt}'"
566
567
# Add assistant response to history
568
st.session_state.chat_history.append({"role": "assistant", "content": response})
569
570
# Display assistant response
571
with st.chat_message("assistant"):
572
st.write(response)
573
574
# Chat controls
575
col1, col2 = st.columns([1, 1])
576
577
with col1:
578
if st.button("Clear Chat"):
579
st.session_state.chat_history = [
580
{"role": "assistant", "content": "Hello! How can I help you today?"}
581
]
582
st.rerun()
583
584
with col2:
585
if st.button("Export Chat"):
586
chat_text = "\n".join([
587
f"{msg['role'].title()}: {msg['content']}"
588
for msg in st.session_state.chat_history
589
])
590
st.download_button(
591
"Download Chat",
592
chat_text,
593
file_name="chat_history.txt",
594
mime="text/plain"
595
)
596
```
597
598
### Custom Components
599
600
```python
601
# HTML component example
602
st.subheader("Custom HTML Component")
603
604
html_content = """
605
<div style="
606
background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
607
padding: 20px;
608
border-radius: 10px;
609
color: white;
610
text-align: center;
611
font-family: Arial, sans-serif;
612
">
613
<h2>🎨 Custom HTML Widget</h2>
614
<p>This is a custom HTML component with styling!</p>
615
<button onclick="alert('Hello from custom component!')"
616
style="
617
background: white;
618
color: #333;
619
border: none;
620
padding: 10px 20px;
621
border-radius: 5px;
622
cursor: pointer;
623
">
624
Click Me!
625
</button>
626
</div>
627
"""
628
629
st.components.v1.html(html_content, height=200)
630
631
# Iframe component example
632
st.subheader("Embedded Content")
633
634
# Embed external content
635
st.components.v1.iframe(
636
"https://www.openstreetmap.org/export/embed.html?bbox=-0.1,51.5,-0.05,51.52",
637
width=700,
638
height=400
639
)
640
```
641
642
### Data Connections
643
644
```python
645
# SQL Connection example (conceptual - requires actual database)
646
try:
647
# Create connection
648
conn = st.connection("my_database", type="sql", url="sqlite:///example.db")
649
650
# Query with caching
651
@st.cache_data
652
def get_user_data():
653
return conn.query("SELECT * FROM users LIMIT 10")
654
655
# Use connection
656
st.subheader("Database Connection")
657
data = get_user_data()
658
st.dataframe(data)
659
660
except Exception as e:
661
st.info("Database connection example (requires actual database setup)")
662
st.code("""
663
# SQL Connection usage:
664
conn = st.connection("my_db", type="sql", url="postgresql://...")
665
data = conn.query("SELECT * FROM table", ttl=600)
666
""")
667
668
# File-based connection example
669
st.subheader("File Connection Simulation")
670
671
@st.cache_data
672
def load_sample_data():
673
import pandas as pd
674
import numpy as np
675
676
# Simulate loading from external source
677
return pd.DataFrame({
678
'id': range(1, 101),
679
'name': [f'User_{i}' for i in range(1, 101)],
680
'value': np.random.randn(100),
681
'category': np.random.choice(['A', 'B', 'C'], 100)
682
})
683
684
data = load_sample_data()
685
st.dataframe(data.head())
686
687
# Connection refresh
688
if st.button("Refresh Data"):
689
st.cache_data.clear()
690
st.rerun()
691
```