Observant.py
Reactive state management for Python.
Track changes, validate data, implement undo/redo, and build reactive UIs with ease.
📚 Full documentation: https://mrowrlib.github.io/observant.py
Installation
pip install observant
Core Types
Observant.py provides a set of observable primitives:
Observable[T]: Wraps a scalar value and notifies listeners on changeObservableList[T]: Observable wrapper around a listObservableDict[K, V]: Observable wrapper around a dictionaryObservableProxy[T]: Wraps a dataclass or object and exposes its fields as observables
Quick Examples
Observable
from observant import Observable
count = Observable(0)
count.on_change(lambda v: print(f"Count is now {v}"))
count.set(1) # → Count is now 1
ObservableList
from observant import ObservableList
items = ObservableList(["a", "b"])
items.on_change(lambda change: print(f"List changed: {change.type.name}"))
items.append("c") # → List changed: ADD
ObservableDict
from observant import ObservableDict
settings = ObservableDict({"theme": "dark"})
settings.on_change(lambda change: print(f"Settings changed: {change.key}"))
settings["theme"] = "light" # → Settings changed: theme
ObservableProxy
from observant import ObservableProxy
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
user = User(name="Ada", age=36)
proxy = ObservableProxy(user)
name = proxy.observable(str, "name")
name.on_change(lambda v: print(f"Name changed to {v}"))
name.set("Grace") # → Name changed to Grace
# Save changes back to the original object
proxy.save_to(user)
print(user.name) # → Grace
Features
- ✅ Type-safe observables: Full type hints and generics support
- 🔁 Undo/Redo support: Track and revert changes
- 🧠 Computed properties: Create derived values that update automatically
- 🧪 Validation: Add validators to ensure data integrity
- 🔄 Dirty state tracking: Know which fields have been modified
- 🔗 Sync back to original objects: Optionally sync changes immediately
Advanced Example: MVVM Pattern
from observant import ObservableProxy
from dataclasses import dataclass
from typing import List
@dataclass
class TodoItem:
text: str
completed: bool
@dataclass
class TodoListModel:
items: List[TodoItem]
class TodoListViewModel:
def __init__(self, model: TodoListModel):
self.model = model
self.proxy = ObservableProxy(model)
# Get observable list of items
self.items = self.proxy.observable_list(TodoItem, "items")
# Register computed properties
self.proxy.register_computed(
"completed_count",
lambda: sum(1 for item in self.items if item.completed),
["items"]
)
def add_item(self, text: str):
self.items.append(TodoItem(text=text, completed=False))
def toggle_item(self, index: int):
item = self.items[index]
item_proxy = ObservableProxy(item)
completed_obs = item_proxy.observable(bool, "completed")
completed_obs.set(not completed_obs.get())
item_proxy.save_to(item)
def save(self):
self.proxy.save_to(self.model)
# Usage
model = TodoListModel(items=[])
view_model = TodoListViewModel(model)
# Listen for changes
view_model.proxy.computed(int, "completed_count").on_change(
lambda count: print(f"Completed: {count}")
)
# Add and toggle items
view_model.add_item("Learn Python")
view_model.add_item("Learn Observant.py")
view_model.toggle_item(0) # → Completed: 1
Learn More
Check out the full documentation and examples at https://mrowrlib.github.io/observant.py
Metadata
Release files for observant 0.1.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| observant-0.1.7.tar.gz | 33.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| observant-0.1.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 68.9 kB
Release files / observant-0.1.7.tar.gz
| Download URL | observant-0.1.7.tar.gz |
|---|---|
| Size | 33.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
78e549a35fc15b9e4d348f414847d880131667d899351110f5c6155b5651c3de
|
|
BLAKE2b-256 checksum How to use checksums |
e619a4525ec5d44c9471765269c54a4c88411c8f887d8fe8f270e4214d4a472f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Release files / observant-0.1.7-py3-none-any.whl
| Download URL | observant-0.1.7-py3-none-any.whl |
|---|---|
| Size | 35.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bba82f9641b90bf8abfeb8f9eac930329853a08b14fb9bd40e0b004306742a68
|
|
BLAKE2b-256 checksum How to use checksums |
a523ac10e79518d64588e5bd61927616db2213e81f008655cc17ee711651f8b9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|