Files
Aidem-Media-DLL-Analysis/ams/snapshot.py
Patryk Gensch 6885bbee3d Add snapshot diff engine (ams package) + tests
Standalone CLI that diffs two engine-surface snapshots across all four axes,
the foundation the FastAPI/DB layer will sit on.

- ams.snapshot : typed access to a snapshot.json
- ams.diff     : keyed set-diff per axis (added/removed/changed) + cross-owner
                 method-move detection; types keyed by (script_name,
                 via_module_iface) so the dual MULTIARRAY stays stable;
                 filter_by_owner for per-class focus
- ams.render   : human-readable report (+/-/~), owner-grouped
- ams.cli      : python -m ams OLD NEW [--owner C] [--only ...] [--json]

6 tests pass, incl. an integration test over the committed golden pair
(asserts BlooMoo adds GRBUFFER/INTERNET, MOUSE grows 104->128, Animo gains
GETFPS, Animo script fields unchanged).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 22:18:04 +02:00

59 lines
1.5 KiB
Python

"""Loading and light typed access to an engine-surface snapshot.json."""
from __future__ import annotations
import json
from dataclasses import dataclass
from typing import Any
@dataclass
class Snapshot:
"""Thin wrapper over a parsed snapshot.json. Axes are returned as plain lists of dicts so
they round-trip cleanly to JSON; the diff engine works directly on those records."""
raw: dict[str, Any]
@classmethod
def load(cls, path: str) -> "Snapshot":
with open(path, "r", encoding="utf-8") as fh:
return cls(json.load(fh))
@property
def binary(self) -> dict[str, Any]:
return self.raw.get("binary", {})
@property
def types(self) -> list[dict]:
return self.raw.get("types", [])
@property
def methods(self) -> list[dict]:
return self.raw.get("methods", [])
@property
def events(self) -> list[dict]:
return self.raw.get("events", [])
@property
def fields(self) -> list[dict]:
return self.raw.get("fields", [])
@property
def struct_layout(self) -> list[dict]:
return self.raw.get("struct_layout", [])
@property
def method_inheritance(self) -> list[dict]:
return self.raw.get("method_inheritance", [])
@property
def field_inheritance(self) -> list[dict]:
return self.raw.get("field_inheritance", [])
@property
def label(self) -> str:
b = self.binary
return "{0} [{1}/{2}]".format(
b.get("name", "?"), b.get("engine", "?"), b.get("compiler", "?"))