Observ 👁
Vue.js-style reactivity for Python. Wrap your state in a reactive proxy, and observ tracks every read and write for you: computed values invalidate themselves, watchers fire when something they depend on changes. No dirty flags, no manual invalidation, no dependency bookkeeping.
📖 Documentation · 📦 PyPI · 🧪 Examples (Qt, rendercanvas)
🖼️ Building a GUI?
Head straight to Collagraph — a full-featured, Vue-inspired declarative UI framework built on top of observ. If you're looking for a strong reactive GUI framework for your Python Qt/PySide applications, Collagraph is the main entrypoint; observ is the reactivity engine underneath it.
Why observ?
- Automatic dependency tracking — computed state knows exactly what it depends on and lazily re-evaluates only when needed.
- React to any change — watch plain state or computed state and build unidirectional data flow: state changes drive view changes, input events drive state changes.
- Zero dependencies, framework agnostic — a pure Python library (≥ 3.9) that plugs into any event loop: asyncio, Qt, or your own.
- Fully typed — a PEP 561 typed package, checked with ty in CI.
Quick start
pip install observ
from observ import computed, reactive, watch
state = reactive({
"todos": [
{"title": "groceries", "done": False},
{"title": "dishes", "done": True},
],
})
@computed
def progress():
done = sum(todo["done"] for todo in state["todos"])
return f"{done}/{len(state['todos'])} done"
watcher = watch(progress, lambda new: print(new), sync=True)
# Mutate the plain dicts and lists you already have —
# observ sees every change, no matter how deeply nested:
state["todos"][0]["done"] = True # prints: 2/2 done
state["todos"].append({"title": "laundry", "done": False}) # prints: 2/3 done
# ...but you only ever react when a *result* actually changes:
state["todos"][1]["title"] = "do the dishes" # (no print)
No subclasses to inherit, no observable fields to declare, no signals to wire up: reactive() takes your existing data, and dependencies are tracked automatically simply by using it.
Continue with the Quick Start tutorial, or dive into the Guide and API Reference.
Related projects
- Collagraph: reactive user interfaces in Python, built on top of observ.
- Reliev: the store (with undo/redo support) that used to be part of observ.
- Patchdiff: diffing and patching for plain Python data structures — the same dicts, lists and sets you'd wrap with observ.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file observ-1.0.0.tar.gz.
File metadata
- Download URL: observ-1.0.0.tar.gz
- Upload date:
- Size: 67.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
290bf5a45009ecc5d48e6d2b0a9b47e103e56948045be1237974298f55c170fd
|
|
| MD5 |
4640d9edeeb2ef3b6ac746888b12578e
|
|
| BLAKE2b-256 |
103cc37c12be0c46745f82f7994bedb9302b69a9014e4711589c1ebf6328ebdc
|
Provenance
The following attestation bundles were made for observ-1.0.0.tar.gz:
Publisher:
ci.yml on fork-tongue/observ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
observ-1.0.0.tar.gz -
Subject digest:
290bf5a45009ecc5d48e6d2b0a9b47e103e56948045be1237974298f55c170fd - Sigstore transparency entry: 2138864556
- Sigstore integration time:
-
Permalink:
fork-tongue/observ@c2954e97d85ccd25ccfd88e026f4290dce37acd4 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/fork-tongue
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@c2954e97d85ccd25ccfd88e026f4290dce37acd4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file observ-1.0.0-py3-none-any.whl.
File metadata
- Download URL: observ-1.0.0-py3-none-any.whl
- Upload date:
- Size: 26.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
179b7520723420150789d965394a970c31a2f455d4700e3108315130b1110f38
|
|
| MD5 |
ae9119f62dfc12ab37460d1cbb7786de
|
|
| BLAKE2b-256 |
f90b55c42220c691f6458ff713603a12c6e800cc0f4770e6b8441aaad56ec541
|
Provenance
The following attestation bundles were made for observ-1.0.0-py3-none-any.whl:
Publisher:
ci.yml on fork-tongue/observ
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
observ-1.0.0-py3-none-any.whl -
Subject digest:
179b7520723420150789d965394a970c31a2f455d4700e3108315130b1110f38 - Sigstore transparency entry: 2138864564
- Sigstore integration time:
-
Permalink:
fork-tongue/observ@c2954e97d85ccd25ccfd88e026f4290dce37acd4 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/fork-tongue
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@c2954e97d85ccd25ccfd88e026f4290dce37acd4 -
Trigger Event:
push
-
Statement type: