From e9d61a126803d034a7a1117ab5fae34267a874a9 Mon Sep 17 00:00:00 2001 From: Fred Sonnenwald Date: Mon, 30 Jun 2025 12:23:47 +0100 Subject: [PATCH 1/2] Add null type parser --- jambo/parser/__init__.py | 2 ++ jambo/parser/null_type_parser.py | 25 ++++++++++++++++ tests/parser/test_null_type_parser.py | 43 +++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 jambo/parser/null_type_parser.py create mode 100644 tests/parser/test_null_type_parser.py diff --git a/jambo/parser/__init__.py b/jambo/parser/__init__.py index a953057..f3b8b25 100644 --- a/jambo/parser/__init__.py +++ b/jambo/parser/__init__.py @@ -7,6 +7,7 @@ from .const_type_parser import ConstTypeParser from .enum_type_parser import EnumTypeParser from .float_type_parser import FloatTypeParser from .int_type_parser import IntTypeParser +from .null_type_parser import NullTypeParser from .object_type_parser import ObjectTypeParser from .ref_type_parser import RefTypeParser from .string_type_parser import StringTypeParser @@ -22,6 +23,7 @@ __all__ = [ "BooleanTypeParser", "FloatTypeParser", "IntTypeParser", + "NullTypeParser", "ObjectTypeParser", "StringTypeParser", "RefTypeParser", diff --git a/jambo/parser/null_type_parser.py b/jambo/parser/null_type_parser.py new file mode 100644 index 0000000..35036ef --- /dev/null +++ b/jambo/parser/null_type_parser.py @@ -0,0 +1,25 @@ +from jambo.parser._type_parser import GenericTypeParser +from jambo.types.type_parser_options import TypeParserOptions + +from typing_extensions import Unpack + + +class NullTypeParser(GenericTypeParser): + mapped_type = None + + json_schema_type = "type:null" + + type_mappings = { + "default": "default", + } + + def from_properties_impl( + self, name, properties, **kwargs: Unpack[TypeParserOptions] + ): + mapped_properties = self.mappings_properties_builder(properties, **kwargs) + + default_value = properties.get("default") + if default_value is not None: + raise ValueError(f"Default value for {name} must be None.") + + return None, mapped_properties diff --git a/tests/parser/test_null_type_parser.py b/tests/parser/test_null_type_parser.py new file mode 100644 index 0000000..414fbae --- /dev/null +++ b/tests/parser/test_null_type_parser.py @@ -0,0 +1,43 @@ +from jambo.parser import NullTypeParser + +from unittest import TestCase + + +class TestNullTypeParser(TestCase): + def test_null_parser_no_options(self): + parser = NullTypeParser() + + properties = {"type": "null"} + + type_parsing, type_validator = parser.from_properties_impl( + "placeholder", properties + ) + + self.assertEqual(type_parsing, None) + self.assertEqual(type_validator, {"default": None}) + + def test_null_parser_with_default(self): + parser = NullTypeParser() + + properties = { + "type": "null", + "default": None, + } + + type_parsing, type_validator = parser.from_properties_impl( + "placeholder", properties + ) + + self.assertEqual(type_parsing, None) + self.assertEqual(type_validator["default"], None) + + def test_null_parser_with_invalid_default(self): + parser = NullTypeParser() + + properties = { + "type": "null", + "default": "invalid", + } + + with self.assertRaises(ValueError): + parser.from_properties_impl("placeholder", properties) -- 2.49.1 From 00d88388f84bd8372929dd3bb402019f8999b365 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Mon, 18 Aug 2025 23:33:16 -0300 Subject: [PATCH 2/2] Fixes Behavior of Pydantic None Type and Adds More Tests --- jambo/parser/null_type_parser.py | 13 +++---------- tests/parser/test_null_type_parser.py | 24 +++++------------------- tests/test_schema_converter.py | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/jambo/parser/null_type_parser.py b/jambo/parser/null_type_parser.py index 35036ef..4c384f4 100644 --- a/jambo/parser/null_type_parser.py +++ b/jambo/parser/null_type_parser.py @@ -5,21 +5,14 @@ from typing_extensions import Unpack class NullTypeParser(GenericTypeParser): - mapped_type = None + mapped_type = type(None) json_schema_type = "type:null" - type_mappings = { - "default": "default", - } - def from_properties_impl( self, name, properties, **kwargs: Unpack[TypeParserOptions] ): mapped_properties = self.mappings_properties_builder(properties, **kwargs) + mapped_properties["default"] = None - default_value = properties.get("default") - if default_value is not None: - raise ValueError(f"Default value for {name} must be None.") - - return None, mapped_properties + return self.mapped_type, mapped_properties diff --git a/tests/parser/test_null_type_parser.py b/tests/parser/test_null_type_parser.py index 414fbae..e2732c0 100644 --- a/tests/parser/test_null_type_parser.py +++ b/tests/parser/test_null_type_parser.py @@ -13,31 +13,17 @@ class TestNullTypeParser(TestCase): "placeholder", properties ) - self.assertEqual(type_parsing, None) + self.assertEqual(type_parsing, type(None)) self.assertEqual(type_validator, {"default": None}) - def test_null_parser_with_default(self): + def test_null_parser_with_invalid_default(self): parser = NullTypeParser() - properties = { - "type": "null", - "default": None, - } + properties = {"type": "null", "default": "invalid"} type_parsing, type_validator = parser.from_properties_impl( "placeholder", properties ) - self.assertEqual(type_parsing, None) - self.assertEqual(type_validator["default"], None) - - def test_null_parser_with_invalid_default(self): - parser = NullTypeParser() - - properties = { - "type": "null", - "default": "invalid", - } - - with self.assertRaises(ValueError): - parser.from_properties_impl("placeholder", properties) + self.assertEqual(type_parsing, type(None)) + self.assertEqual(type_validator, {"default": None}) diff --git a/tests/test_schema_converter.py b/tests/test_schema_converter.py index fbba3c9..6a1421d 100644 --- a/tests/test_schema_converter.py +++ b/tests/test_schema_converter.py @@ -657,3 +657,23 @@ class TestSchemaConverter(TestCase): with self.assertRaises(ValueError): Model(name="Canada") + + def test_null_type_parser(self): + schema = { + "title": "Test", + "type": "object", + "properties": { + "a_thing": {"type": "null"}, + }, + } + + Model = SchemaConverter.build(schema) + + obj = Model() + self.assertIsNone(obj.a_thing) + + obj = Model(a_thing=None) + self.assertIsNone(obj.a_thing) + + with self.assertRaises(ValueError): + Model(a_thing="not none") -- 2.49.1