Skip to main content

A lightweight utility for simplified client-side storage management in Flet applications.

Project description

Flet Storage

DOI PyPI Downloads

🌐 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.

Requirements

  • Python 3.10+
  • Flet >= 0.81.0

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flet_storage-1.1.2.tar.gz (10.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flet_storage-1.1.2-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

Details for the file flet_storage-1.1.2.tar.gz.

File metadata

  • Download URL: flet_storage-1.1.2.tar.gz
  • Upload date:
  • Size: 10.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.19

File hashes

Hashes for flet_storage-1.1.2.tar.gz
Algorithm Hash digest
SHA256 fc47405ef930e88ac579f716d136fe13abbd3c587142c6ae70b562e16cfbeebd
MD5 72e103f9406b2c7d1d14b279ea7ecdf4
BLAKE2b-256 ceb9767301ce8a2eac84024e5342f2adac52a268e73834b6efc9bcade71db077

See more details on using hashes here.

File details

Details for the file flet_storage-1.1.2-py3-none-any.whl.

File metadata

  • Download URL: flet_storage-1.1.2-py3-none-any.whl
  • Upload date:
  • Size: 8.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.19

File hashes

Hashes for flet_storage-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 48aa0823a8ae1e815cb7426c0bb72cfab8591093853ecece979104307d61c121
MD5 5ea25d999711c1d4e68808b3c91a12d4
BLAKE2b-256 37f7060052d73f6d0661b81f070fc907607fa7be63963b4b4e0b2c31129b1639

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page