@@ -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
|
||||
|
||||
@@ -13,6 +13,7 @@ class ConstTypeParser(GenericTypeParser):
|
||||
default_mappings = {
|
||||
"const": "default",
|
||||
"description": "description",
|
||||
"examples": "examples",
|
||||
}
|
||||
|
||||
def from_properties_impl(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user