Skip to main content

roz-remembers

A small, message-driven state management library for Python, inspired by the predictable state-container pattern popularized by Redux. It gives you a centralized, observable bag of state that you read and write through simple dot-path keys (e.g. "job.bins"), with change events you can subscribe to and optional JSON persistence.

It ships two front ends over the same dot-path engine:

  • Store — a synchronous store. Best for ordinary synchronous code that just wants central, observable runtime state without an event loop.
  • RozRemembers — an asyncio, Redux-style store driven by an action queue and an event queue. Best for long-running async applications.

Both share the exported helpers get_nested_value(path, data) and set_nested_value(path, value, data).

Installation

pip install roz-remembers

The import name is roz_remembers:

from roz_remembers import Store, RozRemembers, get_nested_value, set_nested_value

Dot-path convention

State is a nested dict, and every read/write addresses a value by a dot-separated path:

  • "user.theme"state["user"]["theme"]
  • numeric segments index into lists: "items.0.name"state["items"][0]["name"]
  • reads of a missing or non-traversable path return None (or your supplied default on Store.get).
  • writes auto-create intermediate dicts as needed. A write fails (returns False) only if a segment can't be traversed or assigned — e.g. a list index out of range, or trying to descend into a scalar.

Quickstart — Store (synchronous)

from roz_remembers import Store

store = Store({"job": {"bins": 10, "sorted": 0}})

# read / write by dot-path
store.set("job.sorted", 1)            # -> True
store.get("job.sorted")               # -> 1
store.get("job.missing", default=0)   # -> 0 (missing path falls back)

# writes auto-create intermediate dicts
store.set("machine.state", "CARD_READY")
store.get_state()                     # deep copy of the whole state

# subscribe to change events; subscribe() returns an unsubscribe function
def on_change(event):
    print(event["path"], event["old_value"], "->", event["new_value"])

unsubscribe = store.subscribe(on_change)
store.set("job.sorted", 2)            # -> on_change fires
unsubscribe()                         # stop receiving events

Persistence

Store reads and writes plain JSON:

store.save("state.json")                 # write current state to disk
restored = Store(state_file="state.json")  # load state at construction
restored.get("job.bins")                 # -> 10

# a Store created with state_file remembers it, so save() needs no argument
live = Store(state_file="state.json")
live.set("job.sorted", 5)
live.save()                              # persists back to state.json

Loading a missing file or malformed JSON starts from an empty state (a warning is logged) rather than raising, so a first run "just works".

Quickstart — RozRemembers (asynchronous)

RozRemembers processes actions off a queue and emits events onto another queue. You dispatch SET_STATE actions and consume STATE_CHANGED events.

import asyncio
from roz_remembers import RozRemembers

async def main():
    store = RozRemembers("initial_state.json")
    await store.load_initial_state()      # empty state if the file is absent
    store.start_processing()              # start the background action processor

    # observe state changes
    events = store.subscribe_events()     # an asyncio.Queue of event dicts

    await store.dispatch({
        "type": RozRemembers.ACTION_TYPE_SET_STATE,   # "SET_STATE"
        "path": "user.theme",
        "value": "dark",
    })

    event = await events.get()
    # {'type': 'STATE_CHANGED', 'path': 'user.theme',
    #  'old_value': None, 'new_value': 'dark', 'action_source': {...}}
    print(event["path"], "->", event["new_value"])
    print(store.get_current_state())      # deep copy of the whole state

    await store.stop_processing()

asyncio.run(main())

The subscribe / events model

  • Store notifies synchronously: each set() that changes state calls every subscriber callback with a STATE_CHANGED event ({"type", "path", "old_value", "new_value"}). A raising subscriber is logged and isolated — it won't break the store or other subscribers.
  • RozRemembers is asynchronous: subscribe_events() returns an asyncio.Queue. Each applied SET_STATE puts a STATE_CHANGED event (which also carries action_source) on that queue for your consumer coroutine to await. Actions with no path, unknown action types, and writes that can't be applied are ignored and emit no event.

Development

This is a Poetry (PEP 621) project. Tests run under pytest with a coverage gate:

pip install pytest pytest-asyncio pytest-cov
pytest        # runs the suite and enforces >=90% line coverage

pythonpath = ["src"] is set in pyproject.toml, so tests import roz_remembers directly without a manual PYTHONPATH.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

roz_remembers-0.2.0.tar.gz (7.1 kB view details)

Uploaded Source

Built Distribution

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

roz_remembers-0.2.0-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file roz_remembers-0.2.0.tar.gz.

File metadata

  • Download URL: roz_remembers-0.2.0.tar.gz
  • Upload date:
  • Size: 7.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"25.04","id":"plucky","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for roz_remembers-0.2.0.tar.gz
Algorithm Hash digest
SHA256 4d667db39dcd6e5fadbf88398e2e552e0a382839211d652c9a7103d817896a44
MD5 06c5586e3d568f11bfd9be9fac0fde45
BLAKE2b-256 10fbad8bee5042c75e3b87cd9a9c7568ef258d764e72027a976b52e32cb307fe

See more details on using hashes here.

File details

Details for the file roz_remembers-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: roz_remembers-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 7.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"25.04","id":"plucky","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for roz_remembers-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 13120f1cee4dd1d426d3509a8887140cb29f16d44f3d55f6a48f49bcd082b15e
MD5 123b8b57e6b132d5ebdc88c57f6b7af5
BLAKE2b-256 712e63a9d33d7f3960ff7ae1483591338808402552debc1984ae38a4ebea0fb9

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page