61 lines
1.6 KiB
Python
61 lines
1.6 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from collections.abc import Awaitable
|
|
from typing import Any, Literal, Union
|
|
|
|
from pydantic import TypeAdapter, ValidationError
|
|
from typing_extensions import TypeVar
|
|
|
|
from .exceptions import ModelBehaviorError
|
|
from .logger import logger
|
|
from .tracing import Span, SpanError, get_current_span
|
|
|
|
T = TypeVar("T")
|
|
|
|
MaybeAwaitable = Union[Awaitable[T], T]
|
|
|
|
|
|
def transform_string_function_style(name: str) -> str:
|
|
# Replace spaces with underscores
|
|
name = name.replace(" ", "_")
|
|
|
|
# Replace non-alphanumeric characters with underscores
|
|
name = re.sub(r"[^a-zA-Z0-9]", "_", name)
|
|
|
|
return name.lower()
|
|
|
|
|
|
def validate_json(json_str: str, type_adapter: TypeAdapter[T], partial: bool) -> T:
|
|
partial_setting: bool | Literal["off", "on", "trailing-strings"] = (
|
|
"trailing-strings" if partial else False
|
|
)
|
|
try:
|
|
validated = type_adapter.validate_json(json_str, experimental_allow_partial=partial_setting)
|
|
return validated
|
|
except ValidationError as e:
|
|
attach_error_to_current_span(
|
|
SpanError(
|
|
message="Invalid JSON provided",
|
|
data={},
|
|
)
|
|
)
|
|
raise ModelBehaviorError(
|
|
f"Invalid JSON when parsing {json_str} for {type_adapter}; {e}"
|
|
) from e
|
|
|
|
|
|
def attach_error_to_span(span: Span[Any], error: SpanError) -> None:
|
|
span.set_error(error)
|
|
|
|
|
|
def attach_error_to_current_span(error: SpanError) -> None:
|
|
span = get_current_span()
|
|
if span:
|
|
attach_error_to_span(span, error)
|
|
else:
|
|
logger.warning(f"No span to add error {error} to")
|
|
|
|
|
|
async def noop_coroutine() -> None:
|
|
pass
|