Separates PR for Better Testing and Readability
This commit is contained in:
@@ -124,26 +124,3 @@ class GenericTypeParser(ABC, Generic[T]):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _has_meaningful_constraints(field_props):
|
||||
"""
|
||||
Check if field properties contain meaningful constraints that require Field wrapping.
|
||||
|
||||
Returns False if:
|
||||
- field_props is None or empty
|
||||
- field_props only contains {'default': None}
|
||||
|
||||
Returns True if:
|
||||
- field_props contains a non-None default value
|
||||
- field_props contains other constraint properties (min_length, max_length, pattern, etc.)
|
||||
"""
|
||||
if not field_props:
|
||||
return False
|
||||
|
||||
# If only default is set and it's None, no meaningful constraints
|
||||
if field_props == {"default": None}:
|
||||
return False
|
||||
|
||||
# If there are multiple properties or non-None default, that's meaningful
|
||||
return True
|
||||
|
||||
@@ -3,7 +3,7 @@ from jambo.types.json_schema_type import JSONSchemaNativeTypes
|
||||
from jambo.types.type_parser_options import TypeParserOptions
|
||||
|
||||
from pydantic import AfterValidator
|
||||
from typing_extensions import Annotated, Any, Literal, Unpack
|
||||
from typing_extensions import Annotated, Any, Unpack
|
||||
|
||||
|
||||
class ConstTypeParser(GenericTypeParser):
|
||||
@@ -33,19 +33,11 @@ class ConstTypeParser(GenericTypeParser):
|
||||
return const_type, parsed_properties
|
||||
|
||||
def _build_const_type(self, const_value):
|
||||
# Try to use Literal for hashable types (required for discriminated unions)
|
||||
# Fall back to validator approach for non-hashable types
|
||||
try:
|
||||
# Test if the value is hashable (can be used in Literal)
|
||||
hash(const_value)
|
||||
return Literal[const_value]
|
||||
except TypeError:
|
||||
# Non-hashable type (like list, dict), use validator approach
|
||||
def _validate_const_value(value: Any) -> Any:
|
||||
if value != const_value:
|
||||
raise ValueError(
|
||||
f"Value must be equal to the constant value: {const_value}"
|
||||
)
|
||||
return value
|
||||
def _validate_const_value(value: Any) -> Any:
|
||||
if value != const_value:
|
||||
raise ValueError(
|
||||
f"Value must be equal to the constant value: {const_value}"
|
||||
)
|
||||
return value
|
||||
|
||||
return Annotated[type(const_value), AfterValidator(_validate_const_value)]
|
||||
return Annotated[type(const_value), AfterValidator(_validate_const_value)]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from jambo.parser._type_parser import GenericTypeParser
|
||||
from jambo.types.type_parser_options import TypeParserOptions
|
||||
|
||||
from pydantic import Field, BeforeValidator, TypeAdapter, ValidationError
|
||||
from typing_extensions import Annotated, Union, Unpack, Any
|
||||
from pydantic import BeforeValidator, Field, TypeAdapter, ValidationError
|
||||
from typing_extensions import Annotated, Any, Union, Unpack
|
||||
|
||||
|
||||
class OneOfTypeParser(GenericTypeParser):
|
||||
@@ -11,7 +11,7 @@ class OneOfTypeParser(GenericTypeParser):
|
||||
json_schema_type = "oneOf"
|
||||
|
||||
def from_properties_impl(
|
||||
self, name, properties, **kwargs: Unpack[TypeParserOptions]
|
||||
self, name, properties, **kwargs: Unpack[TypeParserOptions]
|
||||
):
|
||||
if "oneOf" not in properties:
|
||||
raise ValueError(f"Invalid JSON Schema: {properties}")
|
||||
@@ -42,7 +42,9 @@ class OneOfTypeParser(GenericTypeParser):
|
||||
if discriminator and isinstance(discriminator, dict):
|
||||
property_name = discriminator.get("propertyName")
|
||||
if property_name:
|
||||
validated_type = Annotated[union_type, Field(discriminator=property_name)]
|
||||
validated_type = Annotated[
|
||||
union_type, Field(discriminator=property_name)
|
||||
]
|
||||
return validated_type, mapped_properties
|
||||
|
||||
def validate_one_of(value: Any) -> Any:
|
||||
@@ -59,11 +61,34 @@ class OneOfTypeParser(GenericTypeParser):
|
||||
continue
|
||||
|
||||
if matched_count == 0:
|
||||
raise ValueError(f"Value does not match any of the oneOf schemas")
|
||||
raise ValueError("Value does not match any of the oneOf schemas")
|
||||
elif matched_count > 1:
|
||||
raise ValueError(f"Value matches multiple oneOf schemas, exactly one expected")
|
||||
raise ValueError(
|
||||
"Value matches multiple oneOf schemas, exactly one expected"
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
validated_type = Annotated[union_type, BeforeValidator(validate_one_of)]
|
||||
return validated_type, mapped_properties
|
||||
|
||||
@staticmethod
|
||||
def _has_meaningful_constraints(field_props):
|
||||
"""
|
||||
Check if field properties contain meaningful constraints that require Field wrapping.
|
||||
Returns False if:
|
||||
- field_props is None or empty
|
||||
- field_props only contains {'default': None}
|
||||
Returns True if:
|
||||
- field_props contains a non-None default value
|
||||
- field_props contains other constraint properties (min_length, max_length, pattern, etc.)
|
||||
"""
|
||||
if not field_props:
|
||||
return False
|
||||
|
||||
# If only default is set and it's None, no meaningful constraints
|
||||
if field_props == {"default": None}:
|
||||
return False
|
||||
|
||||
# If there are multiple properties or non-None default, that's meaningful
|
||||
return True
|
||||
|
||||
@@ -16,6 +16,7 @@ class StringTypeParser(GenericTypeParser):
|
||||
"maxLength": "max_length",
|
||||
"minLength": "min_length",
|
||||
"pattern": "pattern",
|
||||
"format": "format",
|
||||
}
|
||||
|
||||
format_type_mapping = {
|
||||
@@ -37,9 +38,7 @@ class StringTypeParser(GenericTypeParser):
|
||||
def from_properties_impl(
|
||||
self, name, properties, **kwargs: Unpack[TypeParserOptions]
|
||||
):
|
||||
mapped_properties = self.mappings_properties_builder(
|
||||
properties, **kwargs
|
||||
)
|
||||
mapped_properties = self.mappings_properties_builder(properties, **kwargs)
|
||||
|
||||
format_type = properties.get("format")
|
||||
if not format_type:
|
||||
@@ -52,8 +51,4 @@ class StringTypeParser(GenericTypeParser):
|
||||
if format_type in self.format_pattern_mapping:
|
||||
mapped_properties["pattern"] = self.format_pattern_mapping[format_type]
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user