feat: better methodology for accessing cached references of: objects, subobjects and defs

This commit is contained in:
2025-11-24 20:52:02 -03:00
parent 4baaeed349
commit 682f19654d
3 changed files with 64 additions and 7 deletions

View File

@@ -31,7 +31,7 @@ class AnyOfTypeParser(GenericTypeParser):
sub_types = [ sub_types = [
GenericTypeParser.type_from_properties( GenericTypeParser.type_from_properties(
f"{name}_sub{i}", subProperty, **kwargs f"{name}.sub{i}", subProperty, **kwargs
) )
for i, subProperty in enumerate(sub_properties) for i, subProperty in enumerate(sub_properties)
] ]

View File

@@ -67,7 +67,7 @@ class ObjectTypeParser(GenericTypeParser):
return model return model
model_config = ConfigDict(validate_assignment=True) model_config = ConfigDict(validate_assignment=True)
fields = cls._parse_properties(properties, required_keys, **kwargs) fields = cls._parse_properties(name, properties, required_keys, **kwargs)
model = create_model(name, __config__=model_config, **fields) # type: ignore model = create_model(name, __config__=model_config, **fields) # type: ignore
@@ -84,6 +84,7 @@ class ObjectTypeParser(GenericTypeParser):
@classmethod @classmethod
def _parse_properties( def _parse_properties(
cls, cls,
name: str,
properties: dict[str, JSONSchema], properties: dict[str, JSONSchema],
required_keys: list[str], required_keys: list[str],
**kwargs: Unpack[TypeParserOptions], **kwargs: Unpack[TypeParserOptions],
@@ -91,15 +92,15 @@ class ObjectTypeParser(GenericTypeParser):
required_keys = required_keys or [] required_keys = required_keys or []
fields = {} fields = {}
for name, prop in properties.items(): for field_name, field_prop in properties.items():
sub_property: TypeParserOptions = kwargs.copy() sub_property: TypeParserOptions = kwargs.copy()
sub_property["required"] = name in required_keys sub_property["required"] = field_name in required_keys
parsed_type, parsed_properties = GenericTypeParser.type_from_properties( parsed_type, parsed_properties = GenericTypeParser.type_from_properties(
name, f"{name}.{field_name}",
prop, field_prop,
**sub_property, # type: ignore **sub_property, # type: ignore
) )
fields[name] = (parsed_type, Field(**parsed_properties)) fields[field_name] = (parsed_type, Field(**parsed_properties))
return fields return fields

View File

@@ -942,3 +942,59 @@ class TestSchemaConverter(TestCase):
cached_model = self.converter.get_cached_ref("NonExistentModel") cached_model = self.converter.get_cached_ref("NonExistentModel")
self.assertIsNone(cached_model) self.assertIsNone(cached_model)
def test_get_type_from_cache_nested_type(self):
schema = {
"title": "Person",
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"address": {
"type": "object",
"properties": {
"street": {"type": "string"},
"city": {"type": "string"},
},
"required": ["street", "city"],
},
},
"required": ["name", "age", "address"],
}
model = self.converter.build_with_instance(schema)
cached_model = self.converter.get_cached_ref("Person.address")
self.assertIsNotNone(cached_model)
self.assertIs(model.model_fields["address"].annotation, cached_model)
def test_get_type_from_cache_with_def(self):
schema = {
"title": "person",
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"address": {"$ref": "#/$defs/address"},
},
"$defs": {
"address": {
"type": "object",
"properties": {
"street": {"type": "string"},
"city": {"type": "string"},
},
"required": ["street", "city"],
}
},
}
person_model = self.converter.build_with_instance(schema)
cached_person_model = self.converter.get_cached_ref("person")
self.assertIs(person_model, cached_person_model)
cached_address_model = self.converter.get_cached_ref("address")
self.assertIsNotNone(cached_address_model)