**BROKEN INITIAL FOWARDREF**

This commit is contained in:
2025-06-12 02:35:09 -03:00
parent 760f30d08f
commit 188cd28586
3 changed files with 61 additions and 22 deletions

View File

@@ -4,7 +4,7 @@ from jambo.types.type_parser_options import TypeParserOptions
from typing_extensions import Any, ForwardRef, TypeVar, Union, Unpack
RefType = TypeVar("RefType", bound=Union[int, str])
RefType = TypeVar("RefType", bound=Union[type, ForwardRef])
class RefTypeParser(GenericTypeParser):
@@ -30,16 +30,13 @@ class RefTypeParser(GenericTypeParser):
"Look into $defs and # for recursive references."
)
ref_type = None
mapped_properties = {}
if properties["$ref"] == "#":
if "title" not in context:
raise ValueError(
"RefTypeParser: Missing title in properties for $ref #"
)
ref_type = ForwardRef(context["title"])
return ForwardRef(context["title"]), {}
elif properties["$ref"].startswith("#/$defs/"):
target_name = None
@@ -56,17 +53,8 @@ class RefTypeParser(GenericTypeParser):
if target_name is None or target_property is None:
raise ValueError(f"RefTypeParser: Invalid $ref {properties['$ref']}")
ref_type, mapped_properties = GenericTypeParser.type_from_properties(
return GenericTypeParser.type_from_properties(
target_name, target_property, **kwargs
)
else:
raise ValueError(
"RefTypeParser: Invalid $ref format. "
"Only local references are supported."
)
if not required:
mapped_properties["default"] = None
return ref_type, mapped_properties
raise ValueError(f"RefTypeParser: Unsupported $ref {properties['$ref']}")

View File

@@ -1,7 +1,9 @@
from typing_extensions import Any, NotRequired, TypedDict
from jambo.types.json_schema_type import JSONSchema
from typing_extensions import NotRequired, TypedDict
class TypeParserOptions(TypedDict):
required: bool
context: dict[str, Any]
context: JSONSchema
ref_cache: NotRequired[dict[str, type]]

View File

@@ -1,10 +1,12 @@
from jambo.parser import RefTypeParser
from jambo.parser import ObjectTypeParser, RefTypeParser
from typing_extensions import ForwardRef, get_type_hints
from unittest import TestCase
class TestRefTypeParser(TestCase):
def test_ref_type_parser_local_ref(self):
def test_ref_type_parser_with_def(self):
properties = {
"title": "person",
"$ref": "#/$defs/person",
@@ -20,8 +22,8 @@ class TestRefTypeParser(TestCase):
}
type_parsing, type_validator = RefTypeParser().from_properties(
properties=properties,
name="placeholder",
"person",
properties,
context=properties,
required=True,
)
@@ -32,3 +34,50 @@ class TestRefTypeParser(TestCase):
self.assertEqual(obj.name, "John")
self.assertEqual(obj.age, 30)
def test_ref_type_parser_with_forward_ref(self):
properties = {
"title": "person",
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"emergency_contact": {
"$ref": "#",
},
},
}
type_parsing, type_validator = ObjectTypeParser().from_properties(
"person",
properties,
context=properties,
required=True,
)
type_parsing.update_forward_refs(person=type_parsing)
self.assertIsInstance(type_parsing, type)
type_hints = get_type_hints(type_parsing, globals(), locals())
self.assertIsInstance(type_hints["emergency_contact"], ForwardRef)
"""
This is a example of how to resolve ForwardRef in a dynamic model:
```python
from typing import get_type_hints
# Make sure your dynamic model has a name
model = type_parsing
model.update_forward_refs(person=model) # 👈 resolve the ForwardRef("person")
# Inject into globals manually
globalns = globals().copy()
globalns['person'] = model
# Now you can get the resolved hints
type_hints = get_type_hints(model, globalns=globalns)
```
Use `TypeParserOptions.ref_cache` option to cache and resolve ForwardRefs
inside the ObjectTypeParser.to_model method.
"""