Skip to main content

Type-safe observables and proxies for building reactive Python applications.

Project description

Observant.py

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

PyPI version License: 0BSD License: 0BSD

Installation

pip install observant

Core Types

Observant.py provides a set of observable primitives:

  • Observable[T]: Wraps a scalar value and notifies listeners on change
  • ObservableList[T]: Observable wrapper around a list
  • ObservableDict[K, V]: Observable wrapper around a dictionary
  • ObservableProxy[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

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

observant-0.1.7.tar.gz (33.0 kB view details)

Uploaded Source

Built Distribution

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

observant-0.1.7-py3-none-any.whl (35.8 kB view details)

Uploaded Python 3

File details

Details for the file observant-0.1.7.tar.gz.

File metadata

  • Download URL: observant-0.1.7.tar.gz
  • Upload date:
  • Size: 33.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for observant-0.1.7.tar.gz
Algorithm Hash digest
SHA256 78e549a35fc15b9e4d348f414847d880131667d899351110f5c6155b5651c3de
MD5 4aae8390f8bb882c34c7f97b1087ec35
BLAKE2b-256 e619a4525ec5d44c9471765269c54a4c88411c8f887d8fe8f270e4214d4a472f

See more details on using hashes here.

File details

Details for the file observant-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: observant-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 35.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for observant-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 bba82f9641b90bf8abfeb8f9eac930329853a08b14fb9bd40e0b004306742a68
MD5 2d69b2ffbf7ccb4ccd59f87aa9499191
BLAKE2b-256 a523ac10e79518d64588e5bd61927616db2213e81f008655cc17ee711651f8b9

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