llama-stack-mirror/llama_stack/strong_typing/serialization.py
Ashwin Bharambe 314ee09ae3
chore: move all Llama Stack types from llama-models to llama-stack (#1098)
llama-models should have extremely minimal cruft. Its sole purpose
should be didactic -- show the simplest implementation of the llama
models and document the prompt formats, etc.

This PR is the complement to
https://github.com/meta-llama/llama-models/pull/279

## Test Plan

Ensure all `llama` CLI `model` sub-commands work:

```bash
llama model list
llama model download --model-id ...
llama model prompt-format -m ...
```

Ran tests:
```bash
cd tests/client-sdk
LLAMA_STACK_CONFIG=fireworks pytest -s -v inference/
LLAMA_STACK_CONFIG=fireworks pytest -s -v vector_io/
LLAMA_STACK_CONFIG=fireworks pytest -s -v agents/
```

Create a fresh venv `uv venv && source .venv/bin/activate` and run
`llama stack build --template fireworks --image-type venv` followed by
`llama stack run together --image-type venv` <-- the server runs

Also checked that the OpenAPI generator can run and there is no change
in the generated files as a result.

```bash
cd docs/openapi_generator
sh run_openapi_generator.sh
```
2025-02-14 09:10:59 -08:00

97 lines
3.5 KiB
Python

# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the terms described in the LICENSE file in
# the root directory of this source tree.
"""
Type-safe data interchange for Python data classes.
:see: https://github.com/hunyadi/strong_typing
"""
import inspect
import json
import sys
from types import ModuleType
from typing import Any, Optional, TextIO, TypeVar
from .core import JsonType
from .deserializer import create_deserializer
from .inspection import TypeLike
from .serializer import create_serializer
T = TypeVar("T")
def object_to_json(obj: Any) -> JsonType:
"""
Converts a Python object to a representation that can be exported to JSON.
* Fundamental types (e.g. numeric types) are written as is.
* Date and time types are serialized in the ISO 8601 format with time zone.
* A byte array is written as a string with Base64 encoding.
* UUIDs are written as a UUID string.
* Enumerations are written as their value.
* Containers (e.g. `list`, `dict`, `set`, `tuple`) are exported recursively.
* Objects with properties (including data class types) are converted to a dictionaries of key-value pairs.
"""
typ: type = type(obj)
generator = create_serializer(typ)
return generator.generate(obj)
def json_to_object(typ: TypeLike, data: JsonType, *, context: Optional[ModuleType] = None) -> object:
"""
Creates an object from a representation that has been de-serialized from JSON.
When de-serializing a JSON object into a Python object, the following transformations are applied:
* Fundamental types are parsed as `bool`, `int`, `float` or `str`.
* Date and time types are parsed from the ISO 8601 format with time zone into the corresponding Python type
`datetime`, `date` or `time`
* A byte array is read from a string with Base64 encoding into a `bytes` instance.
* UUIDs are extracted from a UUID string into a `uuid.UUID` instance.
* Enumerations are instantiated with a lookup on enumeration value.
* Containers (e.g. `list`, `dict`, `set`, `tuple`) are parsed recursively.
* Complex objects with properties (including data class types) are populated from dictionaries of key-value pairs
using reflection (enumerating type annotations).
:raises TypeError: A de-serializing engine cannot be constructed for the input type.
:raises JsonKeyError: Deserialization for a class or union type has failed because a matching member was not found.
:raises JsonTypeError: Deserialization for data has failed due to a type mismatch.
"""
# use caller context for evaluating types if no context is supplied
if context is None:
this_frame = inspect.currentframe()
if this_frame is not None:
caller_frame = this_frame.f_back
del this_frame
if caller_frame is not None:
try:
context = sys.modules[caller_frame.f_globals["__name__"]]
finally:
del caller_frame
parser = create_deserializer(typ, context)
return parser.parse(data)
def json_dump_string(json_object: JsonType) -> str:
"Dump an object as a JSON string with a compact representation."
return json.dumps(json_object, ensure_ascii=False, check_circular=False, separators=(",", ":"))
def json_dump(json_object: JsonType, file: TextIO) -> None:
json.dump(
json_object,
file,
ensure_ascii=False,
check_circular=False,
separators=(",", ":"),
)
file.write("\n")