0
# Utilities and Platform
1
2
This document covers Flet's utility functions, platform detection capabilities, file operations, network utilities, storage systems, and helper classes for cross-platform development.
3
4
## Import
5
6
```python
7
import flet as ft
8
import flet.utils as flet_utils
9
```
10
11
## Platform Detection
12
13
### Platform Detection Functions
14
15
```python { .api }
16
def is_mobile() -> bool:
17
"""Check if running on mobile platform (Android or iOS)."""
18
19
def is_android() -> bool:
20
"""Check if running on Android."""
21
22
def is_ios() -> bool:
23
"""Check if running on iOS."""
24
25
def is_windows() -> bool:
26
"""Check if running on Windows."""
27
28
def is_macos() -> bool:
29
"""Check if running on macOS."""
30
31
def is_linux() -> bool:
32
"""Check if running on Linux."""
33
34
def is_linux_server() -> bool:
35
"""Check if running on Linux server (no GUI)."""
36
37
def is_embedded() -> bool:
38
"""Check if running in embedded mode."""
39
40
def is_pyodide() -> bool:
41
"""Check if running in Pyodide (web assembly)."""
42
43
def is_asyncio() -> bool:
44
"""Check if asyncio is available and running."""
45
46
def get_platform() -> str:
47
"""Get platform name (windows, macos, linux, android, ios, web)."""
48
49
def get_arch() -> str:
50
"""Get architecture name (x86, x64, arm64, etc.)."""
51
```
52
53
**Example:**
54
```python
55
def configure_for_platform():
56
if flet_utils.is_mobile():
57
# Mobile-specific configuration
58
page.window_width = None # Use full width
59
page.window_height = None # Use full height
60
elif flet_utils.is_windows():
61
# Windows-specific configuration
62
page.window_width = 800
63
page.window_height = 600
64
page.window_center()
65
elif flet_utils.is_macos():
66
# macOS-specific configuration
67
page.window_width = 900
68
page.window_height = 700
69
70
platform_info = ft.Text(
71
f"Platform: {flet_utils.get_platform()} ({flet_utils.get_arch()})"
72
)
73
74
# Conditional UI based on platform
75
if flet_utils.is_mobile():
76
return create_mobile_ui()
77
else:
78
return create_desktop_ui()
79
```
80
81
### Environment Variables
82
83
```python { .api }
84
def get_bool_env_var(name: str, default_value: bool = False) -> bool:
85
"""Get boolean environment variable with default fallback."""
86
```
87
88
**Example:**
89
```python
90
debug_mode = flet_utils.get_bool_env_var("DEBUG", False)
91
production = flet_utils.get_bool_env_var("PRODUCTION", True)
92
93
if debug_mode:
94
page.add(ft.Text("Debug mode enabled"))
95
```
96
97
## File and Directory Utilities
98
99
### Path Operations
100
101
```python { .api }
102
def get_current_script_dir() -> str:
103
"""Get directory of the currently executing script."""
104
105
def cleanup_path(path: str) -> str:
106
"""Clean and normalize file path."""
107
108
def is_within_directory(directory: str, target: str) -> bool:
109
"""Check if target path is within directory (security check)."""
110
```
111
112
**Example:**
113
```python
114
# Get assets directory relative to script
115
script_dir = flet_utils.get_current_script_dir()
116
assets_dir = os.path.join(script_dir, "assets")
117
118
# Clean user-provided path
119
safe_path = flet_utils.cleanup_path(user_input_path)
120
121
# Security check for file access
122
if flet_utils.is_within_directory(allowed_dir, requested_file):
123
# Safe to access file
124
with open(requested_file, 'r') as f:
125
content = f.read()
126
```
127
128
### Directory Operations
129
130
```python { .api }
131
def copy_tree(src: str, dst: str, ignore: callable = None) -> None:
132
"""Copy directory tree with optional ignore function."""
133
```
134
135
**Example:**
136
```python
137
# Copy assets directory, ignoring cache files
138
def ignore_cache(path, names):
139
return [name for name in names if name.startswith('.cache')]
140
141
flet_utils.copy_tree("src/assets", "dist/assets", ignore=ignore_cache)
142
```
143
144
### Archive Operations
145
146
```python { .api }
147
def safe_tar_extractall(tar_file, path: str = ".", members=None) -> None:
148
"""Safely extract tar archive preventing directory traversal attacks."""
149
```
150
151
**Example:**
152
```python
153
import tarfile
154
155
# Safely extract uploaded tar file
156
with tarfile.open(uploaded_file) as tar:
157
flet_utils.safe_tar_extractall(tar, "extracted_files/")
158
```
159
160
## Network Utilities
161
162
### Port and Network Detection
163
164
```python { .api }
165
def get_free_tcp_port() -> int:
166
"""Get available TCP port number."""
167
168
def get_local_ip() -> str:
169
"""Get local IP address."""
170
171
def which(command: str) -> str:
172
"""Find executable in PATH (cross-platform 'which' command)."""
173
```
174
175
**Example:**
176
```python
177
# Dynamic port allocation
178
free_port = flet_utils.get_free_tcp_port()
179
print(f"Starting server on port {free_port}")
180
181
# Network information
182
local_ip = flet_utils.get_local_ip()
183
print(f"Server accessible at: http://{local_ip}:{free_port}")
184
185
# Check for required executables
186
git_path = flet_utils.which("git")
187
if git_path:
188
print(f"Git found at: {git_path}")
189
else:
190
print("Git not available")
191
```
192
193
## String and Hash Utilities
194
195
### String Operations
196
197
```python { .api }
198
def slugify(text: str) -> str:
199
"""Convert string to URL-friendly slug."""
200
201
def random_string(length: int = 10, chars: str = None) -> str:
202
"""Generate random string of specified length."""
203
```
204
205
**Example:**
206
```python
207
# Create URL-friendly identifiers
208
title = "My Blog Post: Special Characters & Symbols!"
209
slug = flet_utils.slugify(title) # "my-blog-post-special-characters-symbols"
210
211
# Generate session IDs
212
session_id = flet_utils.random_string(16) # Random 16-character string
213
api_key = flet_utils.random_string(32, "ABCDEF0123456789") # Hex string
214
```
215
216
### Hash Functions
217
218
```python { .api }
219
def sha1(text: str) -> str:
220
"""Calculate SHA1 hash of text."""
221
222
def calculate_file_hash(file_path: str, algorithm: str = "sha256") -> str:
223
"""Calculate hash of file contents."""
224
```
225
226
**Example:**
227
```python
228
# Content hashing
229
content_hash = flet_utils.sha1("Hello, World!")
230
print(f"SHA1: {content_hash}")
231
232
# File integrity checking
233
file_hash = flet_utils.calculate_file_hash("important_file.dat", "sha256")
234
expected_hash = "abc123..."
235
if file_hash == expected_hash:
236
print("File integrity verified")
237
else:
238
print("File may be corrupted")
239
```
240
241
## Browser Integration
242
243
### Browser Operations
244
245
```python { .api }
246
def open_in_browser(url: str) -> None:
247
"""Open URL in default browser."""
248
```
249
250
**Example:**
251
```python
252
def open_help(e):
253
flet_utils.open_in_browser("https://flet.dev/docs")
254
255
def open_external_link(e):
256
flet_utils.open_in_browser("https://example.com")
257
258
ft.Row([
259
ft.ElevatedButton("Help", on_click=open_help),
260
ft.ElevatedButton("External Link", on_click=open_external_link)
261
])
262
```
263
264
## Storage Systems
265
266
### ClientStorage
267
268
```python { .api }
269
class ClientStorage:
270
"""Client-side storage (localStorage in web, file-based elsewhere)."""
271
272
def get(self, key: str) -> str:
273
"""Get value by key."""
274
275
def set(self, key: str, value: str) -> None:
276
"""Set key-value pair."""
277
278
def contains_key(self, key: str) -> bool:
279
"""Check if key exists."""
280
281
def remove(self, key: str) -> None:
282
"""Remove key."""
283
284
def clear(self) -> None:
285
"""Clear all stored data."""
286
287
def get_keys(self, prefix: str = "") -> List[str]:
288
"""Get all keys with optional prefix filter."""
289
```
290
291
**Example:**
292
```python
293
# Store user preferences
294
def save_preferences(theme, language):
295
page.client_storage.set("theme", theme)
296
page.client_storage.set("language", language)
297
298
def load_preferences():
299
theme = page.client_storage.get("theme") or "light"
300
language = page.client_storage.get("language") or "en"
301
return theme, language
302
303
# Settings UI
304
def toggle_theme(e):
305
current_theme = page.client_storage.get("theme") or "light"
306
new_theme = "dark" if current_theme == "light" else "light"
307
page.client_storage.set("theme", new_theme)
308
apply_theme(new_theme)
309
310
ft.Switch(
311
label="Dark Theme",
312
value=page.client_storage.get("theme") == "dark",
313
on_change=toggle_theme
314
)
315
```
316
317
### SessionStorage
318
319
```python { .api }
320
class SessionStorage:
321
"""Session-scoped storage (sessionStorage in web, memory elsewhere)."""
322
323
# Same API as ClientStorage but data persists only for session
324
def get(self, key: str) -> str: ...
325
def set(self, key: str, value: str) -> None: ...
326
def contains_key(self, key: str) -> bool: ...
327
def remove(self, key: str) -> None: ...
328
def clear(self) -> None: ...
329
def get_keys(self, prefix: str = "") -> List[str]: ...
330
```
331
332
**Example:**
333
```python
334
# Temporary session data
335
def store_form_data():
336
page.session.set("form_step", "2")
337
page.session.set("user_input", text_field.value)
338
339
def restore_form_data():
340
step = page.session.get("form_step") or "1"
341
user_input = page.session.get("user_input") or ""
342
return int(step), user_input
343
344
# Form wizard with session persistence
345
current_step, saved_input = restore_form_data()
346
```
347
348
## Utility Classes
349
350
### Vector
351
352
```python { .api }
353
class Vector:
354
"""2D vector utility class."""
355
356
def __init__(self, x: float, y: float):
357
self.x = x
358
self.y = y
359
360
def magnitude(self) -> float:
361
"""Calculate vector magnitude."""
362
363
def normalize(self) -> "Vector":
364
"""Get normalized vector."""
365
366
def dot(self, other: "Vector") -> float:
367
"""Dot product with another vector."""
368
369
def distance_to(self, other: "Vector") -> float:
370
"""Distance to another vector."""
371
372
def __add__(self, other: "Vector") -> "Vector":
373
"""Vector addition."""
374
375
def __sub__(self, other: "Vector") -> "Vector":
376
"""Vector subtraction."""
377
378
def __mul__(self, scalar: float) -> "Vector":
379
"""Scalar multiplication."""
380
```
381
382
**Example:**
383
```python
384
# Physics calculations
385
pos = flet_utils.Vector(100, 200)
386
velocity = flet_utils.Vector(5, -2)
387
388
# Update position
389
new_pos = pos + velocity
390
391
# Calculate distance between points
392
distance = pos.distance_to(target_pos)
393
394
# Normalize direction vector
395
direction = (target_pos - pos).normalize()
396
```
397
398
### Decorators
399
400
#### classproperty
401
402
```python { .api }
403
class classproperty:
404
"""Decorator for class-level properties."""
405
406
def __init__(self, func):
407
self.func = func
408
409
def __get__(self, instance, owner):
410
return self.func(owner)
411
```
412
413
**Example:**
414
```python
415
class AppConfig:
416
_theme = "light"
417
418
@flet_utils.classproperty
419
def current_theme(cls):
420
return cls._theme
421
422
@current_theme.setter
423
def current_theme(cls, value):
424
cls._theme = value
425
426
# Usage
427
print(AppConfig.current_theme) # Access as class property
428
```
429
430
#### deprecated
431
432
```python { .api }
433
def deprecated(reason: str = None):
434
"""Decorator to mark functions as deprecated."""
435
def decorator(func):
436
def wrapper(*args, **kwargs):
437
import warnings
438
warnings.warn(
439
f"{func.__name__} is deprecated. {reason or ''}",
440
DeprecationWarning,
441
stacklevel=2
442
)
443
return func(*args, **kwargs)
444
return wrapper
445
return decorator
446
```
447
448
**Example:**
449
```python
450
@flet_utils.deprecated("Use new_function() instead")
451
def old_function():
452
return "old implementation"
453
454
# Usage will show deprecation warning
455
result = old_function()
456
```
457
458
### Once
459
460
```python { .api }
461
class Once:
462
"""Execute-once utility."""
463
464
def __init__(self):
465
self._called = False
466
467
def __call__(self, func):
468
def wrapper(*args, **kwargs):
469
if not self._called:
470
self._called = True
471
return func(*args, **kwargs)
472
return wrapper
473
```
474
475
**Example:**
476
```python
477
# Ensure initialization happens only once
478
initialize_once = flet_utils.Once()
479
480
@initialize_once
481
def initialize_app():
482
print("App initialized")
483
# Expensive initialization code
484
485
# Multiple calls, but initialization runs only once
486
initialize_app() # Runs initialization
487
initialize_app() # Skipped
488
initialize_app() # Skipped
489
```
490
491
## Query and Routing Utilities
492
493
### QueryString
494
495
```python { .api }
496
class QueryString:
497
"""URL query string handler."""
498
499
def __init__(self, query_string: str = ""):
500
self.params = {}
501
502
def get(self, key: str, default: str = None) -> str:
503
"""Get query parameter value."""
504
505
def set(self, key: str, value: str) -> None:
506
"""Set query parameter."""
507
508
def remove(self, key: str) -> None:
509
"""Remove query parameter."""
510
511
def to_string(self) -> str:
512
"""Convert to query string."""
513
```
514
515
### TemplateRoute
516
517
```python { .api }
518
class TemplateRoute:
519
"""Template-based routing system."""
520
521
def __init__(self, route_template: str):
522
self.template = route_template
523
524
def match(self, route: str) -> dict:
525
"""Match route against template and extract parameters."""
526
527
def build(self, **params) -> str:
528
"""Build route from template with parameters."""
529
```
530
531
**Example:**
532
```python
533
# URL parameter handling
534
def handle_route_change(e):
535
route = e.route
536
query = flet_utils.QueryString(page.route.split('?')[1] if '?' in page.route else "")
537
538
# Extract query parameters
539
user_id = query.get('user_id')
540
tab = query.get('tab', 'profile')
541
542
if user_id:
543
load_user_profile(user_id, tab)
544
545
# Template routing
546
user_route = flet_utils.TemplateRoute("/user/{user_id}/tab/{tab}")
547
548
# Match incoming route
549
params = user_route.match("/user/123/tab/settings")
550
# Returns: {"user_id": "123", "tab": "settings"}
551
552
# Build route from parameters
553
new_route = user_route.build(user_id="456", tab="profile")
554
# Returns: "/user/456/tab/profile"
555
```
556
557
## Cross-Platform Patterns
558
559
### Adaptive UI Components
560
561
```python
562
def create_adaptive_button(text, on_click):
563
"""Create platform-appropriate button."""
564
if flet_utils.is_ios():
565
return ft.CupertinoButton(text=text, on_click=on_click)
566
else:
567
return ft.ElevatedButton(text=text, on_click=on_click)
568
569
def create_adaptive_dialog(title, content, actions):
570
"""Create platform-appropriate dialog."""
571
if flet_utils.is_ios():
572
return ft.CupertinoAlertDialog(
573
title=ft.Text(title),
574
content=ft.Text(content),
575
actions=actions
576
)
577
else:
578
return ft.AlertDialog(
579
title=ft.Text(title),
580
content=ft.Text(content),
581
actions=actions
582
)
583
```
584
585
### Platform-Specific Configuration
586
587
```python
588
class PlatformConfig:
589
"""Platform-specific configuration manager."""
590
591
def __init__(self):
592
self.config = self._load_platform_config()
593
594
def _load_platform_config(self):
595
base_config = {
596
"window_width": 800,
597
"window_height": 600,
598
"font_family": "default"
599
}
600
601
if flet_utils.is_mobile():
602
base_config.update({
603
"window_width": None,
604
"window_height": None,
605
"font_size": 16
606
})
607
elif flet_utils.is_macos():
608
base_config.update({
609
"font_family": "SF Pro Display",
610
"window_width": 900
611
})
612
elif flet_utils.is_windows():
613
base_config.update({
614
"font_family": "Segoe UI",
615
"window_width": 850
616
})
617
618
return base_config
619
620
def get(self, key, default=None):
621
return self.config.get(key, default)
622
623
# Usage
624
config = PlatformConfig()
625
page.window_width = config.get("window_width")
626
page.window_height = config.get("window_height")
627
```
628
629
### Resource Management
630
631
```python
632
def get_platform_asset(asset_name):
633
"""Get platform-specific asset path."""
634
platform = flet_utils.get_platform()
635
636
# Try platform-specific asset first
637
platform_asset = f"assets/{platform}/{asset_name}"
638
if os.path.exists(platform_asset):
639
return platform_asset
640
641
# Fall back to generic asset
642
return f"assets/{asset_name}"
643
644
def load_platform_strings():
645
"""Load platform-appropriate localized strings."""
646
if flet_utils.is_ios():
647
return load_strings("ios_strings.json")
648
elif flet_utils.is_android():
649
return load_strings("android_strings.json")
650
else:
651
return load_strings("desktop_strings.json")
652
```
653
654
### Performance Utilities
655
656
```python
657
def optimize_for_platform():
658
"""Apply platform-specific optimizations."""
659
if flet_utils.is_mobile():
660
# Mobile optimizations
661
page.scroll = ft.ScrollMode.AUTO
662
page.auto_scroll = True
663
elif flet_utils.is_web():
664
# Web optimizations
665
page.web_renderer = ft.WebRenderer.HTML
666
667
# Memory management
668
if flet_utils.is_linux_server():
669
# Server environment optimizations
670
disable_animations()
671
reduce_ui_complexity()
672
673
def create_efficient_list_for_platform(items):
674
"""Create optimized list based on platform capabilities."""
675
if flet_utils.is_mobile() and len(items) > 100:
676
# Use virtual scrolling for large lists on mobile
677
return create_virtual_list(items)
678
else:
679
# Standard list for desktop/smaller lists
680
return ft.ListView(controls=[
681
ft.ListTile(title=ft.Text(item)) for item in items
682
])
683
```
684
685
This covers Flet's comprehensive utility system and platform detection capabilities, enabling you to create truly cross-platform applications that adapt to different environments and provide optimal user experiences across all supported platforms.