Skip to main content

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

Project description

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

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.3.tar.gz (11.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.3-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: flet_storage-1.1.3.tar.gz
  • Upload date:
  • Size: 11.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.3.tar.gz
Algorithm Hash digest
SHA256 bedd141037a54124346bc33c6f0006f741c8a743bd48e7bb18fbca12dacfdc51
MD5 c946c8ea6a554d59a2d1b1d6723bbc1f
BLAKE2b-256 0ad914798ea64a4b9bca19e315b49903a2b47f21f3c9abbafe60b51fb29e347a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: flet_storage-1.1.3-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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 0fc45519ee231c7ff03d8ff0e61ede50062c0ef9e318d667b5b61505552349a7
MD5 6b7f511a7878e2128a8fda0cd9addc8a
BLAKE2b-256 a0fbb9138f2cb96224afc0d0d7e09d1174280e7ff42bdb887eca7eef7383b740

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