gale.save package

gale.save: a general-purpose save-game system. SaveManager persists whatever JSON-serializable dict a game gives it into named slots on disk, so the same class works for any game; everything a specific game is likely to need to customize – where saves live, the file format, a schema version with migrations for evolving what a save contains, and arbitrary per-save metadata for a save-select screen – is a constructor parameter or a gale.conf setting.

See docs/examples/save.rst for a walkthrough.

Author: Alejandro Mujica (aledrums@gmail.com)

exception gale.save.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.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]]] | None)

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

class gale.save.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]
gale.save.json_deserialize(data)[source]
Parameters:

data (bytes) – Bytes produced by json_serialize (or a wire-compatible encoder).

Returns:

The decoded envelope dict.

Raises:

ValueError – If data is not valid JSON or does not decode to a dict.

Return type:

Dict[str, Any]

gale.save.json_serialize(envelope)[source]
Parameters:

envelope (Dict[str, Any]) – A JSON-serializable dict (SaveManager’s internal envelope: version, timestamps, metadata, and the game’s data).

Returns:

The UTF-8 encoded JSON representation of envelope.

Return type:

bytes

Submodules