Files
hooked-containers/README.md
T
2026-10-08 20:50:52 -05:00

3.4 KiB

Hooked Containers

Hooked Containers provides an abstract container foundation that calls a function hook whenever its contents are changed through its API. The aim is to retain familiar Python container operations while letting application code react to additions, replacements, and removals.

Mixin Design

The design follows Python's collections.abc abstract base classes. Separate mixin classes should build up functionality in layers, so a custom container can compose the behavior it needs:

Layer Responsibility
Container Membership testing through __contains__.
Collection Iteration and size through __iter__ and __len__, alongside membership.
Hook support A shared callback and change-event reporting for mutation methods.
Sequence Indexed access through __getitem__, with sequence helpers such as index and count.
Mutable sequence Assignment, deletion, and insertion, supporting helpers such as append, extend, and pop.
Mapping Key-based access, iteration over keys, and helpers such as keys, items, and values.
Mutable mapping Assignment and deletion, supporting helpers such as update, setdefault, and pop.

Sequences and mappings are separate branches built on the common container foundation, not successive steps in a single inheritance chain. Mutation hooks belong in the primitive operations so inherited ABC mixin methods also report changes. A compound operation may therefore invoke the hook more than once.

This layered separation is the intended architecture. Currently, HookedContainer combines shared container and hook behavior; HookedList and HookedMapping extend it with the standard library's MutableSequence and MutableMapping mixins, respectively.

Change Hooks

A hook receives one change-event object after a mutation. The event identifies the root container (root), the index or key path (path), and the affected value (item). The current event types are AddItemEvent, SetItemEvent, and RemoveItemEvent.

from hooked_containers.mapping import HookedMapping
from hooked_containers.sequence import HookedList


def on_change(event):
	print(type(event).__name__, event.path, event.item)


items = HookedList(["first"], hook=on_change)
items.append("second")       # AddItemEvent (1,) second
items[0] = "updated"         # SetItemEvent (0,) updated
del items[1]                 # RemoveItemEvent (1,) second

settings = HookedMapping({}, hook=on_change)
settings["enabled"] = True  # AddItemEvent ('enabled',) True

The wrappers can share existing mutable storage. Mutating that storage directly bypasses the hook; make changes through the hooked container to receive events. Hooks are optional, and nested wrappers retain the root and path for supported nested container types.

Status

Requires Python 3.12 or newer. This repository is an early implementation of the container and mixin design; the API and separation of responsibilities may evolve.