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

Uploaded Python 3

File details

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

File metadata

  • Download URL: observant-0.1.3.tar.gz
  • Upload date:
  • Size: 32.2 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.3.tar.gz
Algorithm Hash digest
SHA256 1578bef948f7ca206e8cdc1077b9dda2157111ea0b33f208fd4642162ab985d1
MD5 58511e85099b248823b103638197702d
BLAKE2b-256 d8edea8c8f2cba89df9c38a658dfbc54bfd5918e25265b63a2e58eb60c7538cb

See more details on using hashes here.

File details

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

File metadata

  • Download URL: observant-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 34.9 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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 af59d3e3930db9e093dcabbdbf5bcc840fc317b68beb10c29cb51dc342762772
MD5 6d517e4e1e4514321dced0f8bb9d4907
BLAKE2b-256 a5cccf42c6276593649c6c4e9cbbd7116413b7ce0994f99d5d0c229d7455c9a7

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