feature: add instance level ref cache #63

Merged
HideyoshiNakazone merged 12 commits from feature/add-instance-level-ref-cache into main 2025-11-25 00:07:55 +00:00
3 changed files with 64 additions and 7 deletions
Showing only changes of commit 682f19654d - Show all commits

View File

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

View File

@@ -67,7 +67,7 @@ class ObjectTypeParser(GenericTypeParser):
return model
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
@@ -84,6 +84,7 @@ class ObjectTypeParser(GenericTypeParser):
@classmethod
def _parse_properties(
cls,
name: str,
properties: dict[str, JSONSchema],
required_keys: list[str],
**kwargs: Unpack[TypeParserOptions],
@@ -91,15 +92,15 @@ class ObjectTypeParser(GenericTypeParser):
required_keys = required_keys or []
fields = {}
for name, prop in properties.items():
for field_name, field_prop in properties.items():
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(
name,
prop,
f"{name}.{field_name}",
field_prop,
**sub_property, # type: ignore
)
fields[name] = (parsed_type, Field(**parsed_properties))
fields[field_name] = (parsed_type, Field(**parsed_properties))
return fields

View File

@@ -942,3 +942,59 @@ class TestSchemaConverter(TestCase):
cached_model = self.converter.get_cached_ref("NonExistentModel")
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)