saves
Save data in and out of the emulator's save directories.
Save data in and out of the emulator's save directories.
Activate restores a zip archive into the emulator's save directories; exit zips every save file modified since launch.
attributelog= logging.getLogger(__name__)attributeSAVE_FILE_MAX_BYTES= int(os.environ.get('SAVE_FILE_MAX_BYTES', str(256 * 1024 * 1024)))Env-tunable guard against runaway dumps, from SAVE_FILE_MAX_BYTES (default 256 MiB).
func_iter_save_files(root, subtrees) -> list[Path]List every regular file under the allowed subtrees.
Sorted so identical content zips to identical bytes. Dot-prefixed components are staging or tmp entries and never ship, and symlinks are skipped.
paramrootPathThe emulator's save data root.
paramsubtreestuple[str, ...]Subdirectory names under root that hold save data.
Returns
listThe files found, in sorted order.
func_read_file_stable(p, retries=4, settle=0.5) -> Optional[tuple[bytes, float]]Read p only when size and mtime match before and after the read.
This is what keeps a file the emulator is mid-writing from ever being shipped torn.
parampPathThe file to read.
paramretriesint= 4How many reads to attempt before giving up.
paramsettlefloat= 0.5Seconds to wait between attempts.
Returns
typing.OptionalThe file contents and its mtime, or None when the file could not be
funcbuild_save_archive(root, subtrees, baseline) -> dict[str, Any]Zip every save file modified since baseline (the launch timestamp).
Member paths are relative to root and mtimes are stored in UTC on both
sides, so a timezone difference between the dump and a later restore never
shifts them past the newer-file guard.
paramrootPathThe emulator's save data root.
paramsubtreestuple[str, ...]Subdirectory names under root that hold save data.
parambaselinefloatUnix timestamp; files with an mtime at or after it are included.
Returns
dictA report dict of the shape
func_under(member, subtrees) -> boolWhether an archive member path lies inside one of the given subtrees.
parammemberPurePosixPathThe member path, relative to the save data root.
paramsubtreestuple[str, ...]Subdirectory names to test against.
Returns
boolTrue when member starts with one of the subtrees followed by a slash.
funcextract_save_archive(content, root, subtrees, excluded=()) -> dict[str, Any]Restore an archive into the emulator's data dir.
excluded names subtrees the emulator owns but this session syncs some
other way. Those members are dropped rather than refused: archives taken
before that sync was turned on still carry them, and restoring one would
undo what the other route just wrote. A member under neither is still a
hard error, since that is the guard against an archive writing outside the
save area.
Existing files newer than their archive member are skipped so a restore can never roll back saves made since the archive was taken. Each file is written through a temp file and renamed into place.
paramcontentbytesThe zip archive body.
paramrootPathThe emulator's save data root.
paramsubtreestuple[str, ...]Subdirectory names under root that members may be restored into.
paramexcludedtuple[str, ...]= ()Subdirectory names whose members are counted and dropped.
Returns
dictA dict of the shape {"written", "skipped", "excluded", "failed", "error"}
funcwrite_export(zip_bytes, name) -> strPersist a dump archive under settings.EXPORT_DIR for inspection.
paramzip_bytesbytesThe archive body.
paramnamestrThe filename to write it as.
Returns
strThe path written, as a string.
funcwrite_import(zip_bytes, name) -> strPersist an archive the parent uploaded for restore under settings.IMPORT_DIR.
Written through a temp file and renamed so a half-received upload can never be handed to activate as a restore source.
paramzip_bytesbytesThe archive body.
paramnamestrThe filename to write it as.
Returns
strThe path written, as a string.