feature: stabilized the new instance method and adds docs #64

Merged
HideyoshiNakazone merged 2 commits from feature/alters-library-api into main 2025-11-26 03:05:15 +00:00
4 changed files with 364 additions and 56 deletions

View File

@@ -0,0 +1,233 @@
===============
Reference Cache
===============
The reference cache is named after the mechanism used to implement
the `$ref` keyword in the JSON Schema specification.
Internally, the cache is used by both :py:meth:`SchemaConverter.build_with_cache <jambo.SchemaConverter.build_with_cache>`
and :py:meth:`SchemaConverter.build <jambo.SchemaConverter.build>`.
However, only :py:meth:`SchemaConverter.build_with_cache <jambo.SchemaConverter.build_with_cache>` exposes the cache through a supported API;
:py:meth:`SchemaConverter.build <jambo.SchemaConverter.build>` uses the cache internally and does not provide access to it.
-----------------------------------------
Configuring and Using the Reference Cache
-----------------------------------------
The reference cache can be used in three ways:
* Without a persistent reference cache (no sharing between calls).
* Passing an explicit ``ref_cache`` dictionary to a call.
* Using the converter instance's default cache (the instance-level cache).
Usage Without Reference Cache
=============================
When you run the library without a persistent reference cache, the generated
types are not stored for reuse. Each call to a build method creates fresh
Pydantic model classes (they will have different Python object identities).
Because nothing is cached, you cannot look up generated subtypes later.
This is the default behaviour of :py:meth:`SchemaConverter.build <jambo.SchemaConverter.build>`.
You can achieve the same behaviour with :py:meth:`SchemaConverter.build_with_cache <jambo.SchemaConverter.build_with_cache>` by
passing ``without_cache=True``.
Usage: Manually Passing a Reference Cache
=========================================
You can create and pass your own mutable mapping (typically a plain dict)
as the reference cache. This gives you full control over sharing and
lifetime of cached types. When two converters share the same dict, types
created by one converter will be reused by the other.
.. code-block:: python
from jambo import SchemaConverter
# a shared cache you control
shared_cache = {}
converter1 = SchemaConverter(shared_cache)
converter2 = SchemaConverter(shared_cache)
model1 = converter1.build_with_cache(schema)
model2 = converter2.build_with_cache(schema)
# Because both converters use the same cache object, the built models are the same object
assert model1 is model2
If you prefer a per-call cache (leaving the converter's instance cache unchanged), pass the ``ref_cache`` parameter to
:py:meth:`SchemaConverter.build_with_cache <jambo.SchemaConverter.build_with_cache>`:
.. code-block:: python
# pass an explicit, private cache for this call only
model_a = converter1.build_with_cache(schema, ref_cache={})
model_b = converter1.build_with_cache(schema, ref_cache={})
# because each call received a fresh dict, the resulting model classes are distinct
assert model_a is not model_b
Usage: Using the Instance Default (Instance-level) Cache
=======================================================
By default, a :class:`SchemaConverter` instance creates and keeps an internal
reference cache (a plain dict). Reusing the same converter instance across
multiple calls will reuse that cache and therefore reuse previously generated
model classes.
.. code-block:: python
converter = SchemaConverter() # has its own internal cache
model1 = converter.build_with_cache(schema)
model2 = converter.build_with_cache(schema)
# model1 and model2 are the same object because the instance cache persisted
assert model1 is model2
If you want to temporarily avoid using the instance cache for a single call,
use ``without_cache=True``. That causes :py:meth:`SchemaConverter.build_with_cache <jambo.SchemaConverter.build_with_cache>` to
use a fresh, empty cache for the duration of that call only:
.. code-block:: python
model1 = converter.build_with_cache(schema, without_cache=True)
model2 = converter.build_with_cache(schema, without_cache=True)
# each call used a fresh cache, so the models are distinct
assert model1 is not model2
Inspecting and Managing the Cache
=================================
The converter provides a small, explicit API to inspect and manage the
instance cache.
Retrieving cached types
-----------------------
:py:meth:`SchemaConverter.get_cached_ref <jambo.SchemaConverter.get_cached_ref>`(name) — returns a cached model class or ``None``.
Retrieving the root type of the schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When retrieving the root type of a schema, pass the schema's ``title`` property as the name.
.. code-block:: python
from jambo import SchemaConverter
converter = SchemaConverter()
schema = {
"title": "person",
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
},
}
person_model = converter.build_with_cache(schema)
cached_person_model = converter.get_cached_ref("person")
Retrieving a subtype
~~~~~~~~~~~~~~~~~~~~
When retrieving a subtype, pass a path string (for example, ``parent_name.field_name``) as the name.
.. code-block:: python
from jambo import SchemaConverter
converter = SchemaConverter()
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"],
},
}
}
person_model = converter.build_with_cache(schema)
cached_address_model = converter.get_cached_ref("person.address")
Retrieving a type from ``$defs``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When retrieving a type defined in ``$defs``, access it directly by its name.
.. code-block:: python
from jambo import SchemaConverter
converter = SchemaConverter()
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 = converter.build_with_cache(schema)
cached_address_model = converter.get_cached_ref("address")
Clearing the cache
------------------
:py:meth:`SchemaConverter.clear_ref_cache <jambo.SchemaConverter.clear_ref_cache>`() — removes all entries from the instance cache.
Notes and Behavioural Differences
================================
* :py:meth:`SchemaConverter.build <jambo.SchemaConverter.build>` does not expose or persist an instance cache. If you call it without
providing a ``ref_cache`` it will create and use a temporary cache for that
call only; nothing from that call will be available later via
:py:meth:`SchemaConverter.get_cached_ref <jambo.SchemaConverter.get_cached_ref>`.
* :py:meth:`SchemaConverter.build_with_cache <jambo.SchemaConverter.build_with_cache>` is the supported entry point when you want
cache control: it uses the instance cache by default, accepts an explicit
``ref_cache`` dict for per-call control, or uses ``without_cache=True`` to
run with an ephemeral cache.
References in the Test Suite
============================
These behaviours are exercised in the project's tests; see :mod:`tests.test_schema_converter`
for examples and additional usage notes.

View File

@@ -1,9 +1,15 @@
===================
Using Jambo Using Jambo
=================== ===================
Jambo is designed to be easy to use, it doesn't require any complex setup or configuration. Jambo is designed to be easy to use. It doesn't require complex setup or configuration when not needed, while providing more powerful instance methods when you do need control.
Below a example of how to use Jambo to convert a JSON Schema into a Pydantic model.
Below is an example of how to use Jambo to convert a JSON Schema into a Pydantic model.
-------------------------
Static Method (no config)
-------------------------
.. code-block:: python .. code-block:: python
@@ -15,8 +21,16 @@ Below a example of how to use Jambo to convert a JSON Schema into a Pydantic mod
"properties": { "properties": {
"name": {"type": "string"}, "name": {"type": "string"},
"age": {"type": "integer"}, "age": {"type": "integer"},
"address": {
"type": "object",
"properties": {
"street": {"type": "string"},
"city": {"type": "string"},
},
"required": ["street", "city"],
},
}, },
"required": ["name"], "required": ["name", "address"],
} }
Person = SchemaConverter.build(schema) Person = SchemaConverter.build(schema)
@@ -26,16 +40,76 @@ Below a example of how to use Jambo to convert a JSON Schema into a Pydantic mod
# Output: Person(name='Alice', age=30) # Output: Person(name='Alice', age=30)
The :py:meth:`SchemaConverter.build <jambo.SchemaConverter.build>` static method takes a JSON Schema dictionary and returns a Pydantic model class. You can then instantiate this class with the required fields, and it will automatically validate the data according to the schema. The :py:meth:`SchemaConverter.build <jambo.SchemaConverter.build>` static method takes a JSON Schema dictionary and returns a Pydantic model class.
If passed a description inside the schema it will also add it to the Pydantic model using the `description` field. This is useful for AI Frameworks as: LangChain, CrewAI and others, as they use this description for passing context to LLMs. Note: the static ``build`` method was the original public API of this library and is kept for backwards compatibility. It creates and returns a model class for the provided schema but does not expose or persist an instance cache.
For more complex schemas and types see our documentation on --------------------------------
Instance Method (with ref cache)
--------------------------------
.. code-block:: python
from jambo import SchemaConverter
converter = SchemaConverter()
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", "address"],
}
# The instance API (build_with_cache) populates the converter's instance-level reference cache
Person = converter.build_with_cache(schema)
obj = Person(name="Alice", age=30)
print(obj)
# Output: Person(name='Alice', age=30)
# When using the converter's built-in instance cache (no ref_cache passed to the call),
# all object types parsed during the build are stored and can be retrieved via get_cached_ref.
cached_person_model = converter.get_cached_ref("Person")
assert Person is cached_person_model # the cached class is the same object that was built
# A nested/subobject type can also be retrieved from the instance cache
cached_address_model = converter.get_cached_ref("Person.address")
The :py:meth:`SchemaConverter.build_with_cache <jambo.SchemaConverter.build_with_cache>` instance method was added after the
initial static API to make it easier to access and reuse subtypes defined in a schema.
Unlike the original static :py:meth:`SchemaConverter.build <jambo.SchemaConverter.build>`,
the instance method persists and exposes the reference cache and provides helpers such as
:py:meth:`SchemaConverter.get_cached_ref <jambo.SchemaConverter.get_cached_ref>` and
:py:meth:`SchemaConverter.clear_ref_cache <jambo.SchemaConverter.clear_ref_cache>`.
For details and examples about the reference cache and the different cache modes (instance cache, per-call cache, ephemeral cache), see:
.. toctree::
usage.ref_cache
Type System
-----------
For a full explanation of the supported schemas and types see our documentation on types:
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:caption: Contents:
usage.string usage.string
usage.numeric usage.numeric

View File

@@ -22,7 +22,7 @@ class SchemaConverter:
ref_cache = dict() ref_cache = dict()
self._ref_cache = ref_cache self._ref_cache = ref_cache
def build_with_instance( def build_with_cache(
self, self,
schema: JSONSchema, schema: JSONSchema,
ref_cache: Optional[RefCacheDict] = None, ref_cache: Optional[RefCacheDict] = None,
@@ -55,6 +55,7 @@ class SchemaConverter:
) -> type[BaseModel]: ) -> type[BaseModel]:
""" """
Converts a JSON Schema to a Pydantic model. Converts a JSON Schema to a Pydantic model.
This method doesn't use a reference cache if none is provided.
:param schema: The JSON Schema to convert. :param schema: The JSON Schema to convert.
:param ref_cache: An optional reference cache to use during conversion, if provided `with_clean_cache` will be ignored. :param ref_cache: An optional reference cache to use during conversion, if provided `with_clean_cache` will be ignored.
:return: The generated Pydantic model. :return: The generated Pydantic model.

View File

@@ -33,7 +33,7 @@ class TestSchemaConverter(TestCase):
} }
with self.assertRaises(InvalidSchemaException): with self.assertRaises(InvalidSchemaException):
self.converter.build_with_instance(schema) self.converter.build_with_cache(schema)
def test_invalid_schema_type(self): def test_invalid_schema_type(self):
schema = { schema = {
@@ -47,7 +47,7 @@ class TestSchemaConverter(TestCase):
} }
with self.assertRaises(InvalidSchemaException): with self.assertRaises(InvalidSchemaException):
self.converter.build_with_instance(schema) self.converter.build_with_cache(schema)
def test_build_expects_title(self): def test_build_expects_title(self):
schema = { schema = {
@@ -60,7 +60,7 @@ class TestSchemaConverter(TestCase):
} }
with self.assertRaises(InvalidSchemaException): with self.assertRaises(InvalidSchemaException):
self.converter.build_with_instance(schema) self.converter.build_with_cache(schema)
def test_build_expects_object(self): def test_build_expects_object(self):
schema = { schema = {
@@ -70,7 +70,7 @@ class TestSchemaConverter(TestCase):
} }
with self.assertRaises(UnsupportedSchemaException): with self.assertRaises(UnsupportedSchemaException):
self.converter.build_with_instance(schema) self.converter.build_with_cache(schema)
def test_is_invalid_field(self): def test_is_invalid_field(self):
schema = { schema = {
@@ -86,7 +86,7 @@ class TestSchemaConverter(TestCase):
} }
with self.assertRaises(InvalidSchemaException) as context: with self.assertRaises(InvalidSchemaException) as context:
self.converter.build_with_instance(schema) self.converter.build_with_cache(schema)
self.assertTrue("Unknown type" in str(context.exception)) self.assertTrue("Unknown type" in str(context.exception))
def test_jsonschema_to_pydantic(self): def test_jsonschema_to_pydantic(self):
@@ -101,7 +101,7 @@ class TestSchemaConverter(TestCase):
"required": ["name"], "required": ["name"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertTrue(is_pydantic_model(model)) self.assertTrue(is_pydantic_model(model))
@@ -122,7 +122,7 @@ class TestSchemaConverter(TestCase):
"required": ["name"], "required": ["name"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual(model(name="John", age=30).name, "John") self.assertEqual(model(name="John", age=30).name, "John")
@@ -153,7 +153,7 @@ class TestSchemaConverter(TestCase):
"required": ["age"], "required": ["age"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual(model(age=30).age, 30) self.assertEqual(model(age=30).age, 30)
@@ -178,7 +178,7 @@ class TestSchemaConverter(TestCase):
"required": ["age"], "required": ["age"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual(model(age=30).age, 30.0) self.assertEqual(model(age=30).age, 30.0)
@@ -199,7 +199,7 @@ class TestSchemaConverter(TestCase):
"required": ["is_active"], "required": ["is_active"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual(model(is_active=True).is_active, True) self.assertEqual(model(is_active=True).is_active, True)
@@ -222,7 +222,7 @@ class TestSchemaConverter(TestCase):
"required": ["friends"], "required": ["friends"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual( self.assertEqual(
model(friends=["John", "Jane", "John"]).friends, {"John", "Jane"} model(friends=["John", "Jane", "John"]).friends, {"John", "Jane"}
@@ -235,7 +235,7 @@ class TestSchemaConverter(TestCase):
model(friends=["John", "Jane", "Invalid"]) model(friends=["John", "Jane", "Invalid"])
def test_validation_list_with_missing_items(self): def test_validation_list_with_missing_items(self):
model = self.converter.build_with_instance( model = self.converter.build_with_cache(
{ {
"title": "Person", "title": "Person",
"description": "A person", "description": "A person",
@@ -273,7 +273,7 @@ class TestSchemaConverter(TestCase):
"required": ["address"], "required": ["address"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
obj = model(address={"street": "123 Main St", "city": "Springfield"}) obj = model(address={"street": "123 Main St", "city": "Springfield"})
@@ -297,7 +297,7 @@ class TestSchemaConverter(TestCase):
"required": ["name"], "required": ["name"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
obj = model(name="John") obj = model(name="John")
@@ -320,7 +320,7 @@ class TestSchemaConverter(TestCase):
} }
with self.assertRaises(InvalidSchemaException): with self.assertRaises(InvalidSchemaException):
self.converter.build_with_instance(schema_max_length) self.converter.build_with_cache(schema_max_length)
def test_default_for_list(self): def test_default_for_list(self):
schema_list = { schema_list = {
@@ -337,7 +337,7 @@ class TestSchemaConverter(TestCase):
"required": ["friends"], "required": ["friends"],
} }
model_list = self.converter.build_with_instance(schema_list) model_list = self.converter.build_with_cache(schema_list)
self.assertEqual(model_list().friends, ["John", "Jane"]) self.assertEqual(model_list().friends, ["John", "Jane"])
@@ -358,7 +358,7 @@ class TestSchemaConverter(TestCase):
"required": ["friends"], "required": ["friends"],
} }
model_set = self.converter.build_with_instance(schema_set) model_set = self.converter.build_with_cache(schema_set)
self.assertEqual(model_set().friends, {"John", "Jane"}) self.assertEqual(model_set().friends, {"John", "Jane"})
@@ -380,7 +380,7 @@ class TestSchemaConverter(TestCase):
"required": ["address"], "required": ["address"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
obj = model(address={"street": "123 Main St", "city": "Springfield"}) obj = model(address={"street": "123 Main St", "city": "Springfield"})
@@ -404,7 +404,7 @@ class TestSchemaConverter(TestCase):
}, },
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model( obj = Model(
name="J", name="J",
@@ -433,7 +433,7 @@ class TestSchemaConverter(TestCase):
}, },
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model(id=1) obj = Model(id=1)
self.assertEqual(obj.id, 1) self.assertEqual(obj.id, 1)
@@ -457,7 +457,7 @@ class TestSchemaConverter(TestCase):
"properties": {"email": {"type": "string", "format": "email"}}, "properties": {"email": {"type": "string", "format": "email"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual(model(email="test@example.com").email, "test@example.com") self.assertEqual(model(email="test@example.com").email, "test@example.com")
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
@@ -470,7 +470,7 @@ class TestSchemaConverter(TestCase):
"properties": {"website": {"type": "string", "format": "uri"}}, "properties": {"website": {"type": "string", "format": "uri"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual( self.assertEqual(
model(website="https://example.com").website, AnyUrl("https://example.com") model(website="https://example.com").website, AnyUrl("https://example.com")
) )
@@ -485,7 +485,7 @@ class TestSchemaConverter(TestCase):
"properties": {"ip": {"type": "string", "format": "ipv4"}}, "properties": {"ip": {"type": "string", "format": "ipv4"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual(model(ip="192.168.1.1").ip, IPv4Address("192.168.1.1")) self.assertEqual(model(ip="192.168.1.1").ip, IPv4Address("192.168.1.1"))
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
@@ -498,7 +498,7 @@ class TestSchemaConverter(TestCase):
"properties": {"ip": {"type": "string", "format": "ipv6"}}, "properties": {"ip": {"type": "string", "format": "ipv6"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual( self.assertEqual(
model(ip="2001:0db8:85a3:0000:0000:8a2e:0370:7334").ip, model(ip="2001:0db8:85a3:0000:0000:8a2e:0370:7334").ip,
IPv6Address("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), IPv6Address("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
@@ -514,7 +514,7 @@ class TestSchemaConverter(TestCase):
"properties": {"id": {"type": "string", "format": "uuid"}}, "properties": {"id": {"type": "string", "format": "uuid"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual( self.assertEqual(
model(id="123e4567-e89b-12d3-a456-426614174000").id, model(id="123e4567-e89b-12d3-a456-426614174000").id,
@@ -531,7 +531,7 @@ class TestSchemaConverter(TestCase):
"properties": {"hostname": {"type": "string", "format": "hostname"}}, "properties": {"hostname": {"type": "string", "format": "hostname"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual(model(hostname="example.com").hostname, "example.com") self.assertEqual(model(hostname="example.com").hostname, "example.com")
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
@@ -544,7 +544,7 @@ class TestSchemaConverter(TestCase):
"properties": {"timestamp": {"type": "string", "format": "date-time"}}, "properties": {"timestamp": {"type": "string", "format": "date-time"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual( self.assertEqual(
model(timestamp="2024-01-01T12:00:00Z").timestamp.isoformat(), model(timestamp="2024-01-01T12:00:00Z").timestamp.isoformat(),
"2024-01-01T12:00:00+00:00", "2024-01-01T12:00:00+00:00",
@@ -560,7 +560,7 @@ class TestSchemaConverter(TestCase):
"properties": {"time": {"type": "string", "format": "time"}}, "properties": {"time": {"type": "string", "format": "time"}},
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
self.assertEqual( self.assertEqual(
model(time="20:20:39+00:00").time.isoformat(), "20:20:39+00:00" model(time="20:20:39+00:00").time.isoformat(), "20:20:39+00:00"
) )
@@ -576,7 +576,7 @@ class TestSchemaConverter(TestCase):
} }
with self.assertRaises(InvalidSchemaException): with self.assertRaises(InvalidSchemaException):
self.converter.build_with_instance(schema) self.converter.build_with_cache(schema)
def test_ref_with_root_ref(self): def test_ref_with_root_ref(self):
schema = { schema = {
@@ -592,7 +592,7 @@ class TestSchemaConverter(TestCase):
"required": ["name", "age"], "required": ["name", "age"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
obj = model( obj = model(
name="John", name="John",
@@ -627,7 +627,7 @@ class TestSchemaConverter(TestCase):
}, },
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
obj = model( obj = model(
name="John", name="John",
@@ -666,7 +666,7 @@ class TestSchemaConverter(TestCase):
}, },
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model( obj = Model(
name="John", name="John",
@@ -692,7 +692,7 @@ class TestSchemaConverter(TestCase):
"required": ["status"], "required": ["status"],
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model(status="active") obj = Model(status="active")
self.assertEqual(obj.status.value, "active") self.assertEqual(obj.status.value, "active")
@@ -711,7 +711,7 @@ class TestSchemaConverter(TestCase):
"required": ["status"], "required": ["status"],
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model() obj = Model()
self.assertEqual(obj.status.value, "active") self.assertEqual(obj.status.value, "active")
@@ -728,7 +728,7 @@ class TestSchemaConverter(TestCase):
"required": ["name"], "required": ["name"],
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model() obj = Model()
self.assertEqual(obj.name, "United States of America") self.assertEqual(obj.name, "United States of America")
@@ -751,7 +751,7 @@ class TestSchemaConverter(TestCase):
"required": ["name"], "required": ["name"],
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model() obj = Model()
self.assertEqual(obj.name, ["Brazil"]) self.assertEqual(obj.name, ["Brazil"])
@@ -771,7 +771,7 @@ class TestSchemaConverter(TestCase):
}, },
} }
Model = self.converter.build_with_instance(schema) Model = self.converter.build_with_cache(schema)
obj = Model() obj = Model()
self.assertIsNone(obj.a_thing) self.assertIsNone(obj.a_thing)
@@ -813,7 +813,7 @@ class TestSchemaConverter(TestCase):
}, },
} }
schema_type = self.converter.build_with_instance(schema) schema_type = self.converter.build_with_cache(schema)
# check for me that the types generated by the oneOf in the typing.Annotated have different names # check for me that the types generated by the oneOf in the typing.Annotated have different names
operating_system_field = schema_type.model_fields["operating_system"] operating_system_field = schema_type.model_fields["operating_system"]
@@ -827,7 +827,7 @@ class TestSchemaConverter(TestCase):
def test_object_invalid_require(self): def test_object_invalid_require(self):
# https://github.com/HideyoshiNakazone/jambo/issues/60 # https://github.com/HideyoshiNakazone/jambo/issues/60
object_ = self.converter.build_with_instance( object_ = self.converter.build_with_cache(
{ {
"$schema": "https://json-schema.org/draft/2020-12/schema", "$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "TEST", "title": "TEST",
@@ -872,10 +872,10 @@ class TestSchemaConverter(TestCase):
} }
converter1 = SchemaConverter(ref_cache) converter1 = SchemaConverter(ref_cache)
model1 = converter1.build_with_instance(schema) model1 = converter1.build_with_cache(schema)
converter2 = SchemaConverter(ref_cache) converter2 = SchemaConverter(ref_cache)
model2 = converter2.build_with_instance(schema) model2 = converter2.build_with_cache(schema)
self.assertIs(converter1._ref_cache, converter2._ref_cache) self.assertIs(converter1._ref_cache, converter2._ref_cache)
self.assertIs(model1, model2) self.assertIs(model1, model2)
@@ -894,8 +894,8 @@ class TestSchemaConverter(TestCase):
"required": ["name", "age"], "required": ["name", "age"],
} }
model1 = self.converter.build_with_instance(schema, without_cache=True) model1 = self.converter.build_with_cache(schema, without_cache=True)
model2 = self.converter.build_with_instance(schema, without_cache=True) model2 = self.converter.build_with_cache(schema, without_cache=True)
self.assertIsNot(model1, model2) self.assertIsNot(model1, model2)
@@ -913,8 +913,8 @@ class TestSchemaConverter(TestCase):
"required": ["name", "age"], "required": ["name", "age"],
} }
model1 = self.converter.build_with_instance(schema, ref_cache={}) model1 = self.converter.build_with_cache(schema, ref_cache={})
model2 = self.converter.build_with_instance(schema, ref_cache={}) model2 = self.converter.build_with_cache(schema, ref_cache={})
self.assertIsNot(model1, model2) self.assertIsNot(model1, model2)
@@ -932,7 +932,7 @@ class TestSchemaConverter(TestCase):
"required": ["name", "age"], "required": ["name", "age"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
cached_model = self.converter.get_cached_ref("Person") cached_model = self.converter.get_cached_ref("Person")
@@ -962,7 +962,7 @@ class TestSchemaConverter(TestCase):
"required": ["name", "age", "address"], "required": ["name", "age", "address"],
} }
model = self.converter.build_with_instance(schema) model = self.converter.build_with_cache(schema)
cached_model = self.converter.get_cached_ref("Person.address") cached_model = self.converter.get_cached_ref("Person.address")
@@ -990,7 +990,7 @@ class TestSchemaConverter(TestCase):
}, },
} }
person_model = self.converter.build_with_instance(schema) person_model = self.converter.build_with_cache(schema)
cached_person_model = self.converter.get_cached_ref("person") cached_person_model = self.converter.get_cached_ref("person")
self.assertIs(person_model, cached_person_model) self.assertIs(person_model, cached_person_model)