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.4.tar.gz (30.7 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.4-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: observant-0.1.4.tar.gz
  • Upload date:
  • Size: 30.7 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.4.tar.gz
Algorithm Hash digest
SHA256 d67d2bbba805fc74ab74127e8c9e37786330e627dd0f57c55905e0178505eb17
MD5 9cee50456c6abc6d9d781f267b1425d3
BLAKE2b-256 e893ab7c993fbed5971a8bba3c279a995aaa512536599f5fe309868005773847

See more details on using hashes here.

File details

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

File metadata

  • Download URL: observant-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 33.4 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.4-py3-none-any.whl
Algorithm Hash digest
SHA256 e77526be1ea74b24103ce52ebadf2b1e36eb63dea93a6e0d638138c26b0da283
MD5 67ff63cb95ee8e5c25495088042ddafa
BLAKE2b-256 52b928c536f4f209e5dc4e13ae27205dd8a5de56d1871ca3c6debf8d72a43d95

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