feat(examples): Add examples for primitive types

Refs: #52
This commit is contained in:
JCHacking
2025-11-17 23:41:16 +01:00
parent 81c149120e
commit 43ce95cc9a
11 changed files with 223 additions and 7 deletions

View File

@@ -18,6 +18,7 @@ class GenericTypeParser(ABC, Generic[T]):
default_mappings = {
"default": "default",
"description": "description",
"examples": "examples",
}
@abstractmethod
@@ -51,6 +52,11 @@ class GenericTypeParser(ABC, Generic[T]):
"Default value is not valid", invalid_field=name
)
if not self._validate_default(parsed_type, parsed_properties):
raise InvalidSchemaException(
"Examples values are not valid", invalid_field=name
)
return parsed_type, parsed_properties
@classmethod
@@ -127,3 +133,22 @@ class GenericTypeParser(ABC, Generic[T]):
return False
return True
@staticmethod
def _validate_examples(field_type: T, field_prop: dict) -> bool:
values = field_prop.get("examples")
if values is None:
return True
if not isinstance(values, list):
return False
try:
field = Annotated[field_type, Field(**field_prop)] # type: ignore
for value in values:
TypeAdapter(field).validate_python(value)
except Exception as _:
return False
return True

View File

@@ -13,6 +13,7 @@ class ConstTypeParser(GenericTypeParser):
default_mappings = {
"const": "default",
"description": "description",
"examples": "examples",
}
def from_properties_impl(

View File

@@ -41,4 +41,9 @@ class EnumTypeParser(GenericTypeParser):
if "default" in parsed_properties and parsed_properties["default"] is not None:
parsed_properties["default"] = enum_type(parsed_properties["default"])
if "examples" in parsed_properties:
parsed_properties["examples"] = [
enum_type(example) for example in parsed_properties["examples"]
]
return enum_type, parsed_properties

View File

@@ -7,6 +7,7 @@ from typing_extensions import Unpack
from datetime import date, datetime, time, timedelta
from ipaddress import IPv4Address, IPv6Address
from typing import Any
from uuid import UUID
@@ -62,8 +63,38 @@ class StringTypeParser(GenericTypeParser):
if format_type in self.format_pattern_mapping:
mapped_properties["pattern"] = self.format_pattern_mapping[format_type]
print("A")
if "examples" in mapped_properties:
mapped_properties["examples"] = [
self.__parse_example(example, format_type, mapped_type)
for example in mapped_properties["examples"]
]
if "json_schema_extra" not in mapped_properties:
mapped_properties["json_schema_extra"] = {}
mapped_properties["json_schema_extra"]["format"] = format_type
return mapped_type, mapped_properties
def __parse_example(
self, example: Any, format_type: str, mapped_type: type[Any]
) -> Any:
"""
Parse example from JSON Schema format to python format
:param example: Example Value
:param format_type: Format Type
:param mapped_type: Type to parse
:return: Example parsed
"""
match format_type:
case "date" | "time" | "date-time":
return mapped_type.fromisoformat(example)
case "duration":
# TODO: Implement duration parser
raise NotImplementedError
case "ipv4" | "ipv6":
return mapped_type(example)
case "uuid":
return mapped_type(example)
case _:
return example