Skip to main content

Flet Storage

DOI PyPI Downloads PyPI - License PyPI - Version

🌐 Translations: 🇺🇦 Українська

A lightweight, asynchronous, namespaced storage utility for Flet applications.

FletStorage is a powerful wrapper around Flet's built-in SharedPreferences. It simplifies client-side data persistence by adding automatic JSON serialization, allowing you to store and retrieve complex Python objects without manual conversion, while keeping your data organized and isolated.

This repository also includes an agent skill for Flet Storage. See the skill file.

Features

  • Automatic JSON serialization: Store and retrieve dict, list, int, bool, str, and set directly without manual conversion.
  • Namespaced storage: Automatically prefixes keys with app_name to prevent data collisions between different applications on the same device.
  • Asynchronous and parallel: Fully asynchronous API with parallel deletion in the clear() method for maximum performance.
  • Robust error handling: Clear KeyError and ValueError exceptions for predictable data management.
  • Set support: Python sets are automatically preserved during serialization and deserialization.

Installation

pip install flet-storage

Quick Start

import flet as ft
from flet_storage import FletStorage


async def main(page: ft.Page):
    # Initialize storage with a unique namespace
    storage = FletStorage("my_app")

    # Save data
    await storage.set("user", {"name": "Ivan", "age": 25})
    await storage.set("settings", {"theme": "dark", "language": "en"})

    # Retrieve data
    user = await storage.get("user")
    print(user)  # {'name': 'Ivan', 'age': 25}

    # Get with default value
    config = await storage.get_or_default("config", {"version": "1.0"})
    print(config)  # {'version': '1.0'}

    # Check if key exists
    exists = await storage.contains_key("user")
    print(exists)  # True

    # Get all keys
    keys = await storage.get_keys()
    print(keys)  # ['user', 'settings']

    # Remove a key
    await storage.remove("settings")

    # Clear entire storage
    await storage.clear()

ft.run(main)

Supported Data Types

FletStorage automatically serializes and deserializes the following Python types:

Type Description Example
dict Dictionaries {"key": "value"}
list Lists [1, 2, 3]
set Sets (preserved) {"a", "b", "c"}
str Strings "hello"
int, float Numbers 42, 3.14
bool Booleans True, False
None None value None

Working with Sets

Sets are automatically preserved during storage and retrieval:

# Storing a set
tags = {"python", "flet", "async"}
await storage.set("tags", tags)

# Retrieving (returns a set, not a list!)
tags = await storage.get("tags")
print(type(tags))  # <class 'set'> ✅
print(tags)  # {'python', 'flet', 'async'}

# Sets in nested structures work too
data = {
    "user": "Ivan",
    "tags": {"web", "mobile"},
    "categories": ["tech", "programming"]
}
await storage.set("profile", data)
profile = await storage.get("profile")
# profile["tags"] is a set ✅
# profile["categories"] is a list ✅

Technical Note: Sets are stored internally as {"__type__": "set", "values": [...]}. If you need to store a dictionary with a "__type__" key that equals "set", it may be incorrectly interpreted as a set marker during deserialization.

API Reference

__init__(app_name: str)

Initializes the storage with a unique namespace.

Parameters:

  • app_name (str): The unique namespace for the application.

Example:

storage = FletStorage("todo_app")

async set(key: str, obj: object) -> bool

Serializes an object to JSON and stores it under a namespaced key.

Parameters:

  • key (str): The unique key identifier (without namespace).
  • obj (object): Any JSON-serializable object (dict, list, set, str, int, etc.).

Returns:

  • bool: True if the operation was successful.

Example:

await storage.set("preferences", {"notifications": True})
await storage.set("tags", {"python", "flet"})  # Sets are supported!

async get(key: str) -> Any

Retrieves and deserializes an object by its key.

Parameters:

  • key (str): The key identifier to look up.

Returns:

  • Any: The deserialized Python object.

Raises:

  • KeyError: If the key does not exist in the storage.
  • ValueError: If the stored data is not valid JSON.

Example:

try:
    data = await storage.get("preferences")
except KeyError:
    print("Key not found")

async get_or_default(key: str, default: Any = None) -> Any

Gets the value for the given key or returns a default value if not found.

Parameters:

  • key (str): The key identifier to look up.
  • default (Any): The value to return if the key does not exist. Defaults to None.

Returns:

  • Any: The deserialized object if found, otherwise the default value.

Raises:

  • ValueError: If the stored data is not valid JSON.

Example:

config = await storage.get_or_default("config", {"version": "1.0"})

async contains_key(key: str) -> bool

Checks if a specific key exists within the application namespace.

Parameters:

  • key (str): The key identifier to check.

Returns:

  • bool: True if the key exists, False otherwise.

Example:

if await storage.contains_key("user_token"):
    token = await storage.get("user_token")

async remove(key: str) -> bool

Removes a specific key and its value from the storage.

Parameters:

  • key (str): The key identifier to remove.

Returns:

  • bool: True if the operation was successful.

Example:

await storage.remove("temp_data")

async get_keys() -> list[str]

Retrieves all keys belonging to the current application namespace.

Returns:

  • list[str]: A list of keys with the app_name. prefix removed.

Example:

all_keys = await storage.get_keys()
print(f"Stored {len(all_keys)} keys")

async clear() -> None

Deletes all keys and values associated with the current application namespace. Other namespaces in SharedPreferences remain untouched.

Example:

await storage.clear()  # Removes all app data

Usage Examples

Saving User Settings

async def save_user_settings(storage: FletStorage, settings: dict):
    await storage.set("settings", settings)
    print("Settings saved")

async def load_user_settings(storage: FletStorage) -> dict:
    return await storage.get_or_default("settings", {
        "theme": "light",
        "language": "en",
        "notifications": True
    })

Managing a Todo List

async def add_todo(storage: FletStorage, task: str):
    todos = await storage.get_or_default("todos", [])
    todos.append({"task": task, "completed": False})
    await storage.set("todos", todos)

async def get_all_todos(storage: FletStorage) -> list:
    return await storage.get_or_default("todos", [])

async def clear_completed_todos(storage: FletStorage):
    todos = await storage.get_or_default("todos", [])
    active_todos = [t for t in todos if not t["completed"]]
    await storage.set("todos", active_todos)

Working with Tags (Sets)

async def add_tag(storage: FletStorage, tag: str):
    tags = await storage.get_or_default("tags", set())
    tags.add(tag)
    await storage.set("tags", tags)

async def remove_tag(storage: FletStorage, tag: str):
    tags = await storage.get_or_default("tags", set())
    tags.discard(tag)
    await storage.set("tags", tags)

async def get_all_tags(storage: FletStorage) -> set:
    return await storage.get_or_default("tags", set())

Data Caching

import time

async def cache_data(storage: FletStorage, key: str, data: Any, ttl: int = 3600):
    cache_entry = {
        "data": data,
        "expires_at": time.time() + ttl
    }
    await storage.set(f"cache_{key}", cache_entry)

async def get_cached_data(storage: FletStorage, key: str) -> Any | None:
    try:
        cache_entry = await storage.get(f"cache_{key}")
        if time.time() < cache_entry["expires_at"]:
            return cache_entry["data"]
        else:
            await storage.remove(f"cache_{key}")
            return None
    except KeyError:
        return None

Error Handling

async def safe_get_data(storage: FletStorage, key: str):
    try:
        data = await storage.get(key)
        return data
    except KeyError:
        print(f"Key '{key}' not found")
        return None
    except ValueError as e:
        print(f"JSON error: {e}")
        return None

Best Practices

  1. Use descriptive namespace names: Choose a unique app_name to avoid conflicts with other applications.

  2. Handle exceptions: Always handle KeyError and ValueError when working with get().

  3. Use get_or_default(): For optional data, this is more convenient than exception handling.

  4. Structure your data: Store related data together in dictionaries for better organization.

  5. Clean up stale data: Regularly remove unnecessary keys to keep storage clean.

  6. Use sets for unique collections: Sets are automatically preserved and are perfect for storing unique items like tags or categories.

License

MIT License

Contributing

Contributions are welcome! Please submit pull requests on GitHub.

Support

If you encounter any issues or have questions:


Made with ❤️ for the Flet community

Metadata

Release files for flet-storage 1.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flet-storage 1.1.3
File Size Uploaded Provenance
flet_storage-1.1.3.tar.gz 11.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for flet-storage 1.1.3
File Interpreter ABI Platform
flet_storage-1.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 19.5 kB

Release files / flet_storage-1.1.3.tar.gz

Download URL flet_storage-1.1.3.tar.gz
Size 11.5 kB
Tags Source
SHA-256 checksum
How to use checksums
bedd141037a54124346bc33c6f0006f741c8a743bd48e7bb18fbca12dacfdc51
BLAKE2b-256 checksum
How to use checksums
0ad914798ea64a4b9bca19e315b49903a2b47f21f3c9abbafe60b51fb29e347a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.19

Release files / flet_storage-1.1.3-py3-none-any.whl

Download URL flet_storage-1.1.3-py3-none-any.whl
Size 8.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0fc45519ee231c7ff03d8ff0e61ede50062c0ef9e318d667b5b61505552349a7
BLAKE2b-256 checksum
How to use checksums
a0fbb9138f2cb96224afc0d0d7e09d1174280e7ff42bdb887eca7eef7383b740
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.19

Security for flet-storage 1.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page