From 0c4de62bba2d2421eb9e3a3ca6a0887206e202d5 Mon Sep 17 00:00:00 2001 From: Thomas <34217413+thommann@users.noreply.github.com> Date: Fri, 4 Jul 2025 11:56:29 +0200 Subject: [PATCH] fix(jambo): skip Annotated wrapping for trivial anyOf field constraints (#3) --- jambo/parser/anyof_type_parser.py | 28 +++++++++++++++++++++++++- tests/parser/test_anyof_type_parser.py | 14 ++++--------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/jambo/parser/anyof_type_parser.py b/jambo/parser/anyof_type_parser.py index 55ff3ec..8f43975 100644 --- a/jambo/parser/anyof_type_parser.py +++ b/jambo/parser/anyof_type_parser.py @@ -34,8 +34,34 @@ class AnyOfTypeParser(GenericTypeParser): # By defining the type as Union of Annotated type we can use the Field validator # to enforce the constraints of each union type when needed. # We use Annotated to attach the Field validators to the type. + # Only wrap in Annotated[T, Field(**v)] if there are meaningful field constraints + # Don't wrap for simple cases where v only contains {'default': None} field_types = [ - Annotated[t, Field(**v)] if v is not None else t for t, v in sub_types + Annotated[t, Field(**v)] if self._has_meaningful_constraints(v) else t + for t, v in sub_types ] return Union[(*field_types,)], mapped_properties + + @staticmethod + def _has_meaningful_constraints(field_props): + """ + Check if field properties contain meaningful constraints that require Field wrapping. + + Returns False if: + - field_props is None or empty + - field_props only contains {'default': None} + + Returns True if: + - field_props contains a non-None default value + - field_props contains other constraint properties (min_length, max_length, pattern, etc.) + """ + if not field_props: + return False + + # If only default is set and it's None, no meaningful constraints + if len(field_props) == 1 and field_props.get('default') is None: + return False + + # If there are multiple properties or non-None default, that's meaningful + return True \ No newline at end of file diff --git a/tests/parser/test_anyof_type_parser.py b/tests/parser/test_anyof_type_parser.py index 32c2f45..de5cb9b 100644 --- a/tests/parser/test_anyof_type_parser.py +++ b/tests/parser/test_anyof_type_parser.py @@ -46,11 +46,8 @@ class TestAnyOfTypeParser(TestCase): type_1, type_2 = get_args(type_parsing) - self.assertEqual(get_origin(type_1), Annotated) - self.assertIn(str, get_args(type_1)) - - self.assertEqual(get_origin(type_2), Annotated) - self.assertIn(int, get_args(type_2)) + self.assertEqual(type_1, str) + self.assertEqual(type_2, int) def test_any_of_string_or_int_with_default(self): """ @@ -74,11 +71,8 @@ class TestAnyOfTypeParser(TestCase): type_1, type_2 = get_args(type_parsing) - self.assertEqual(get_origin(type_1), Annotated) - self.assertIn(str, get_args(type_1)) - - self.assertEqual(get_origin(type_2), Annotated) - self.assertIn(int, get_args(type_2)) + self.assertEqual(type_1, str) + self.assertEqual(type_2, int) self.assertEqual(type_validator["default"], 42)