StateStorage
The StateStorage class provides persistent key-value storage that survives
across Qtile config reloads and restarts. This solves the problem that Qtile
does not natively persist state across config reloads.
Basic Usage
from qtile_expanded import StateStorage
# Create a storage instance with a namespace
storage = StateStorage("my_widget")
# Set values
storage.set("counter", 42)
storage["theme"] = "dark" # Bracket notation also works
# Get values
counter = storage.get("counter", default=0)
theme = storage["theme"]
# Check if key exists
if "counter" in storage:
print(f"Counter: {storage['counter']}")
Automatic Saving
By default, StateStorage automatically saves after each write:
storage = StateStorage("auto_save")
storage.set("key", "value") # Automatically saved
You can disable auto-save and save manually:
storage = StateStorage("manual_save", auto_save=False)
storage.set("key", "value")
storage.save() # Manual save
Convenience Methods
StateStorage provides several convenience methods for common operations:
# Increment a value
storage.increment("counter") # +1
storage.increment("counter", 5) # +5
# Decrement a value
storage.decrement("counter") # -1
storage.decrement("counter", 2) # -2
# Toggle a boolean
storage.toggle("enabled") # True -> False -> True
storage.toggle("flag", default=True) # Start with True if not set
# Update multiple values
storage.update({"key1": "value1", "key2": "value2"})
Context Manager
StateStorage can be used as a context manager for automatic saving:
storage = StateStorage("context_test", auto_save=False)
with storage:
storage["temp"] = "value"
# Other operations...
# Automatically saved when exiting the context
Dict-like Interface
StateStorage supports a dict-like interface:
storage = StateStorage("dict_like")
# Set using bracket notation
storage["key"] = "value"
# Get using bracket notation
value = storage["key"]
# Check if key exists
if "key" in storage:
print("Key exists")
# Delete
del storage["key"]
# Get all keys, values, or items
keys = storage.keys()
values = storage.values()
items = storage.items()
# Get length
count = len(storage)
# Clear all
storage.clear()
Multiple Namespaces
Use different namespaces to organize state by component:
# State for widget1
widget1_state = StateStorage("widget1")
widget1_state.set("setting", "value")
# State for widget2
widget2_state = StateStorage("widget2")
widget2_state.set("setting", "different value")
# Each has its own storage
print(widget1_state.get("setting")) # "value"
print(widget2_state.get("setting")) # "different value"
Hook Integration
For automatic state saving on Qtile config reload and shutdown, use
setup_qtile_hooks:
from qtile_expanded import StateStorage, setup_qtile_hooks
def main(q):
setup_qtile_hooks(q) # Auto-save on reload/shutdown
storage = StateStorage("my_widget")
# ... your config
return []
Storage Location
Data is stored as JSON in:
~/.cache/qtile/qtile_expanded/{namespace}.json
You can specify a custom cache directory:
from pathlib import Path
custom_dir = Path.home() / ".my_cache"
storage = StateStorage("my_widget", cache_dir=custom_dir)
Thread Safety
StateStorage is thread-safe and uses locks for concurrent access, making it safe to use from multiple threads.
Singleton Pattern
You can use get_instance to get or create a singleton instance:
from qtile_expanded import StateStorage
# Get or create singleton instance
storage1 = StateStorage.get_instance("shared")
storage2 = StateStorage.get_instance("shared")
# Both variables reference the same instance
assert storage1 is storage2
This is useful when you want multiple components to share the same state.
API Reference
StateStorage - Persistent state storage for Qtile.
This module provides a simple key-value storage that persists across Qtile config reloads and restarts. Data is stored as JSON in the Qtile cache directory.
Features: - Automatic loading/saving of state - Thread-safe operations - Support for primitive types (str, int, float, bool, list, dict) - Namespace support for organizing state - Hook integration for automatic save on config reload
- Usage:
from qtile_expanded.storage import StateStorage
# Create a storage instance storage = StateStorage(“my_app”)
# Set values storage.set(“counter”, 42) storage.set(“settings”, {“theme”: “dark”, “notifications”: True})
# Get values counter = storage.get(“counter”, default=0) settings = storage.get(“settings”, default={})
# Delete values storage.delete(“counter”)
# Save explicitly storage.save()
# Use as context manager (auto-saves) with storage:
storage.set(“temporary”, “value”)
- class qtile_expanded.storage.StateStorage(namespace: str, cache_dir: str | Path | None = None, auto_save: bool = True)[source]
Bases:
objectPersistent key-value storage for Qtile that survives config reloads.
Data is stored as JSON in ~/.cache/qtile/qtile_expanded/{namespace}.json
- Args:
namespace: Unique identifier for this storage (e.g., “my_widget”) cache_dir: Override the Qtile cache directory (default: ~/.cache/qtile) auto_save: Whether to automatically save after each write (default: True)
- Attributes:
data: The loaded state dictionary
- __init__(namespace: str, cache_dir: str | Path | None = None, auto_save: bool = True)[source]
Initialize StateStorage with a namespace.
- decrement(key: str, amount: int = 1) int[source]
Decrement a numeric value in the storage.
- Args:
key: The key to decrement amount: The amount to decrement by (default: 1)
- Returns:
The new value
- delete(key: str) bool[source]
Delete a value from the storage.
- Args:
key: The key to delete
- Returns:
True if the key existed and was deleted, False otherwise
- get(key: str, default: Any | None = None) Any[source]
Get a value from the storage.
- Args:
key: The key to retrieve default: Default value if key doesn’t exist
- Returns:
The stored value, or default if not found
- classmethod get_instance(namespace: str, **kwargs) StateStorage[source]
Get or create a StateStorage instance with the given namespace.
This ensures only one instance per namespace exists.
- Args:
namespace: The storage namespace **kwargs: Additional arguments passed to StateStorage constructor
- Returns:
The StateStorage instance
- increment(key: str, amount: int = 1) int[source]
Increment a numeric value in the storage.
- Args:
key: The key to increment amount: The amount to increment by (default: 1)
- Returns:
The new value
- set(key: str, value: Any) None[source]
Set a value in the storage.
- Args:
key: The key to store the value under value: The value to store (must be JSON-serializable)
- toggle(key: str, default: bool = False) bool[source]
Toggle a boolean value in the storage.
- Args:
key: The key to toggle default: Default value if key doesn’t exist
- Returns:
The new value
- qtile_expanded.storage.setup_qtile_hooks(qtile) None[source]
Set up Qtile hooks to automatically save state before reload/shutdown.
This function should be called from your Qtile config:
from qtile_expanded.storage import setup_qtile_hooks
- def main(q):
setup_qtile_hooks(q) # … rest of your config
- Args:
qtile: The Qtile instance (usually ‘q’ in config.py)