simvx.core.save_manager

Pickled game-save persistence for nodes with persist=True Properties.

SaveManager walks a live scene tree, snapshots every Property flagged persist=True, and round-trips the data through pickle. Saves are atomic (write-temp + fsync + rename) and rotate two backups on each write (<slot>.sav.bak, <slot>.sav.bak2).

Per-class versioning is supported via __save_version__ (defaults to 1). When the stored version is older than the class version, apply invokes cls.__migrate_save__(values, from_v, to_v) if defined; otherwise it strict-raises. Newer-than-supported versions always strict-raise.

Example::

from simvx.core import SaveManager, Node, Property

class Player(Node):
    __save_version__ = 1
    hp = Property(100, persist=True, save_version=1)

mgr = SaveManager()              # saves under <cwd>/saves
path = mgr.save(root, "slot1")   # → <cwd>/saves/slot1.sav
data = mgr.load("slot1")
mgr.apply(root, data)

Module Contents

Classes

SaveManager

Save / load / apply persisted Property snapshots for a node tree.

Functions

pickle_atomic

Pickle obj to path atomically, rotating two backups.

Data

API

simvx.core.save_manager.log

‘getLogger(…)’

simvx.core.save_manager.SAVE_FORMAT_VERSION

1

simvx.core.save_manager.pickle_atomic(path: pathlib.Path, obj: Any) pathlib.Path[source]

Pickle obj to path atomically, rotating two backups.

Writes <path>.tmp, fsyncs, then renames into place. Before the rename lands, the previous <path> is rotated to <path>.bak and any pre-existing <path>.bak becomes <path>.bak2. At every instant either the old or the new file is fully on disk – the temp file is the only state that can be partial, and it never replaces the live file until fsync has succeeded.

Raises OSError on write failure (the temp file is best-effort cleaned).

class simvx.core.save_manager.SaveManager(save_dir: pathlib.Path | str | None = None)[source]

Save / load / apply persisted Property snapshots for a node tree.

Attributes: save_dir: Directory where <slot>.sav files live. Created on first save. Defaults to <cwd>/saves when not provided.

Initialization

__slots__

(‘save_dir’,)

save(root: simvx.core.node.Node, slot: str) pathlib.Path[source]

Snapshot the tree and write <save_dir>/<slot>.sav atomically.

Returns the final path. Raises OSError on write failure (after rotating nothing — partial state is never observable).

load(slot: str) dict[source]

Read <save_dir>/<slot>.sav and return the decoded envelope.

No fallback to .bak — backups are for manual recovery only.

apply(root: simvx.core.node.Node, data: dict) None[source]

Restore values from a loaded envelope onto a live tree.

Strict-raises if a stored node path is missing, the class fails to resolve, or per-class versions are incompatible without a migration hook.