pelutils.serialization package¶
JSON persistence for Pydantic models containing non-JSON values.
JSON is useful when the structure of a file should remain inspectable, but it does not represent
values such as NumPy arrays, tensors, or arbitrary Python objects. UniversalJsonModel
keeps JSON-native values in the document and stores unsupported field values as base64-encoded
pickle payloads. This preserves a readable JSON envelope without requiring callers to write
converters for every field type.
The usual interface is UniversalJsonModel.save() and
UniversalJsonModel.load(). save creates missing parent directories and writes the model to a JSON
file; load reconstructs the model from that file. Use UniversalJsonModel.to_json_dict()
and UniversalJsonModel.from_json_dict() when the serialized representation should be nested
inside another structure or handled by another storage layer.
For standalone dictionaries and lists, pretty_json converts Python objects to pretty-formatted JSON,
filling the same role as json.dumps, but often making the resulting JSON more readable.
JSONL helpers handle files containing multiple JSON records separated by newlines.
Quick start¶
import numpy as np
from pelutils.serialization import UniversalJsonModel
from pelutils.types import FloatArray
class Result(UniversalJsonModel):
accuracy: float
predictions: FloatArray # numpy arrays are handled automatically
result = Result(accuracy=0.97, predictions=np.arange(5, dtype=np.float16))
result.save("results/run-1.json")
result = Result.load("results/run-1.json")
This format is intended for trusted application data such as experiment results and cached state, not as a language-neutral interchange format. Pickle payloads are Python-specific, and loading them can execute arbitrary code. Use a format with an explicit schema and safe decoder when data comes from outside the application.
Warning
UniversalJsonModel.load and the pickle fallback execute code while loading. Never load
files from an untrusted source.
- class pelutils.serialization.UniversalJsonModel[source]¶
Bases:
BaseModelPydantic BaseModel with JSON persistence for arbitrary Python values.
Values unsupported by JSON are pickle-encoded and stored as base64 strings. Do not load data from an untrusted source. Custom
model_configvalues must retainarbitrary_types_allowed=Trueif any fields on subclasses are not JSON-serialisable by default.- classmethod from_json_dict(json_dict: dict[str, Any], **model_validate_kwargs: Any) Self[source]¶
Build a model from
to_json_dict()output. Do not load untrusted data.Keyword arguments are forwarded to
pydantic.BaseModel.model_validate().
- classmethod load(path: str | Path, *, encoding: str = 'utf-8') Self[source]¶
Load a model from
path. Do not load untrusted data.
- model_config = {'arbitrary_types_allowed': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- pelutils.serialization.jsonl_dump(objects: Iterable[Any], f: TextIO, single_block: bool = True)[source]¶
Save an iterable to a .jsonl file.
If single_block is True, objects will be joined to a single block before being written. It can be useful to set this to False if there is a large amount of lazily generated data.
- pelutils.serialization.jsonl_dumps(objects: Iterable[Any]) str[source]¶
Return the objects as a single .jsonl-formatted string, one JSON object per line.
- pelutils.serialization.jsonl_load(f: TextIO) Iterator[Any][source]¶
Return a generator of parsed lines in a .jsonl file. Empty lines are ignored.
- pelutils.serialization.jsonl_loads(string: str) Iterator[Any][source]¶
Return a generator of parsed lines. Empty lines are ignored.
- pelutils.serialization.pretty_json(obj: dict[str, Any] | list[Any], *, max_line_length: int = 140, indent: int = 2) str[source]¶
Recursively serialise dicts or lists to JSON, similar to
json.dumps, but with more readable formatting.The root container is always expanded (one element per line).
Nested containers stay on one line when they fit within max_line_length; otherwise they are expanded recursively.
Primitive-only lists are bin-packed: items fill each line up to max_line_length before wrapping to the next.
- Parameters:
obj – A dict or list (may contain arbitrary Python objects).
max_line_length – Soft limit for line width.
indent – Number of spaces per indentation level.
- Returns:
A pretty-formatted, valid JSON string.
- Return type: