Type ↔ JSON, the type-first way, and structural equality.
A type is the source of truth: schema asks the type to describe itself,
and from_schema rebuilds a type from that description — resolving scalars
through the registry, or producing an opaque scalar for a name this process
does not implement, so an unknown extension still round-trips.
Two types are structurally equal when their wire forms are equal. That is the
only equality the storage check needs: a value may be stored at a position iff
their structures match, which is what stops an Image from landing in a
Thumbnail slot while letting ImageSequence and Array[Image] (equal
structure, different names) interchange.
from_schema(obj)
Rebuild a type from its wire form.
Composites recurse; a scalar resolves to its registered type, or to an
opaque scalar carrying the document's kind/extensions when this
process does not implement the name.
Source code in capturegraph-lib/capturegraph/types/schema/serialize.py
| def from_schema(obj: dict[str, Any]) -> type[CGType]:
"""Rebuild a type from its wire form.
Composites recurse; a scalar resolves to its registered type, or to an
opaque scalar carrying the document's ``kind``/``extensions`` when this
process does not implement the name.
"""
type_name = obj.get("type")
if not isinstance(type_name, str) or not type_name:
raise ValueError(f"Type JSON needs a non-empty 'type' string: {obj!r}")
match type_name:
case "array":
return Array[from_schema(obj["element"])]
case "struct":
fields = {n: from_schema(f) for n, f in obj["fields"].items()}
return type("Struct", (Struct,), {"__annotations__": fields})
case "map":
return Map[from_schema(obj["key"]), from_schema(obj["element"])]
case "path":
target = obj.get("target")
return Path[from_schema(target)] if target is not None else Path
case "void":
return Void
case _:
known = scalar_for(type_name)
if known is not None:
return known
kind = obj.get("kind")
if kind not in ("json", "binary", None):
raise ValueError(f"Scalar {type_name!r} has unknown kind {kind!r}")
extensions = tuple(obj.get("extensions", ()))
if kind == "json" and not extensions:
extensions = ("json",)
return opaque_scalar(type_name, kind, extensions)
|
schema(cgtype)
The wire form (schema) of a type.
Source code in capturegraph-lib/capturegraph/types/schema/serialize.py
| def schema(cgtype: type[CGType]) -> dict[str, Any]:
"""The wire form (schema) of a type."""
return cgtype.schema()
|
structural_eq(a, b)
Whether two types describe the same on-disk structure.
Source code in capturegraph-lib/capturegraph/types/schema/serialize.py
| def structural_eq(a: type[CGType], b: type[CGType]) -> bool:
"""Whether two types describe the same on-disk structure."""
return schema(a) == schema(b)
|