gale.save.manager module

SaveManager: a general-purpose save-game system. It only ever moves whatever JSON-serializable dict a game gives it in and out of named “slots” on disk – what that dict contains (a player’s position, an inventory, a whole world) is entirely up to the game, so the same class works for any of them.

Everything a specific game is likely to need to customize is a constructor parameter, each with a sensible default resolved from gale.conf.settings: where saves live (save_dir), what a save file is named (file_extension), the wire format (serializer/deserializer, following the same pluggable-function pattern gale.net.Server/Client already use), and a schema version + migrations for evolving what a save contains across releases without breaking old saves.

Author: Alejandro Mujica (aledrums@gmail.com)

exception gale.save.manager.SaveError[source]

Bases: Exception

Raised for anything that keeps a save from being read back: a missing slot, a corrupted file, or a stored version newer than the manager’s own, or one with no registered migration path up to it.

class gale.save.manager.SaveMetadata(slot, version, created_at, updated_at, extra=<factory>)[source]

Bases: object

What a save-select screen needs to know about a slot without loading (and migrating) its full data.

Parameters:
  • slot (str) – The slot’s name.

  • version (int) – The schema version the save is stored at, before migration.

  • created_at (float) – time.time() when the slot was first saved.

  • updated_at (float) – time.time() of the most recent save to this slot.

  • extra (Dict[str, Any]) – Whatever game-specific metadata was passed to save() (e.g. a chapter name, play time, a thumbnail path) – SaveManager never looks inside this, it’s purely for the game’s own use.

slot: str
version: int
created_at: float
updated_at: float
extra: Dict[str, Any]
class gale.save.manager.SaveManager(save_dir=None, version=None, file_extension=None, serializer=<function json_serialize>, deserializer=<function json_deserialize>, migrations=None)[source]

Bases: object

Usage example:

manager = SaveManager() manager.save(“slot1”, {“level”: 3, “hp”: 80}, play_time=120.5) data = manager.load(“slot1”) # {“level”: 3, “hp”: 80}

for save in manager.list_saves():

print(save.slot, save.extra.get(“play_time”))

Parameters:
  • save_dir (str | Path | None)

  • version (int | None)

  • file_extension (str | None)

  • serializer (Callable[[Dict[str, Any]], bytes])

  • deserializer (Callable[[bytes], Dict[str, Any]])

  • migrations (Dict[int, Callable[[Dict[str, Any]], Dict[str, Any]]])

migrations: Dict[int, Callable[[Dict[str, Any]], Dict[str, Any]]]
exists(slot)[source]
Parameters:

slot (str) – The slot’s name.

Returns:

Whether a save exists in slot.

Return type:

bool

save(slot, data, **metadata)[source]

Writes data to slot, tagged with the manager’s current version and any metadata. Written atomically (via a temporary file renamed into place) so a crash mid-write can never leave a corrupted save behind.

Parameters:
  • slot (str) – The slot’s name.

  • data (Dict[str, Any]) – A JSON-serializable dict with whatever the game wants to persist.

  • metadata (Any) – Arbitrary game-specific extras (play time, a thumbnail path, a chapter name, …), later available through list_saves()/read_metadata() without loading data.

Return type:

None

load(slot)[source]
Parameters:

slot (str) – The slot’s name.

Returns:

The slot’s data dict, migrated up to the manager’s current version if it was stored at an older one.

Raises:

SaveError – If the slot doesn’t exist, is corrupted, is stored at a version newer than the manager’s own, or is missing a migration needed to reach it.

Return type:

Dict[str, Any]

read_metadata(slot)[source]
Parameters:

slot (str) – The slot’s name.

Returns:

The slot’s SaveMetadata, without loading (or migrating) its data.

Raises:

SaveError – If the slot doesn’t exist or is corrupted.

Return type:

SaveMetadata

list_saves()[source]
Returns:

Every existing slot’s SaveMetadata, most recently updated first. A slot that fails to read (corrupted) is skipped rather than raising.

Return type:

List[SaveMetadata]

delete(slot)[source]
Parameters:

slot (str) – The slot’s name. Deleting a slot that doesn’t exist is a no-op.

Return type:

None