@@ -897,13 +897,15 @@ def _create_synthetic_enum_obj(
897897 final_enum = [* enum_values , None ] if nullable else enum_values
898898 final_varnames = varnames if len (varnames ) == len (enum_values ) else []
899899
900+ # Only include default if original has one; otherwise don't set it at all
901+ # to avoid incorrectly marking the synthetic object as having a default
900902 return self .SCHEMA_OBJECT_TYPE (
901903 type = enum_type ,
902904 enum = final_enum ,
903905 title = original .title ,
904906 description = original .description ,
905907 x_enum_varnames = final_varnames ,
906- default = original .default if original .has_default else None ,
908+ ** ({ " default" : original .default } if original .has_default else {}) ,
907909 )
908910
909911 def is_constraints_field (self , obj : JsonSchemaObject ) -> bool :
@@ -3051,7 +3053,7 @@ def parse_list_item(
30513053 for index , item in enumerate (target_items )
30523054 ]
30533055
3054- def parse_array_fields ( # noqa: PLR0912
3056+ def parse_array_fields ( # noqa: PLR0912, PLR0915
30553057 self ,
30563058 name : str ,
30573059 obj : JsonSchemaObject ,
@@ -3066,12 +3068,19 @@ def parse_array_fields( # noqa: PLR0912
30663068 required : bool = False
30673069 nullable : Optional [bool ] = None # noqa: UP045
30683070 else :
3069- required = not ( obj .has_default and self . apply_default_values_for_required_fields )
3071+ required = not obj .has_default
30703072 if self .strict_nullable :
30713073 nullable = obj .nullable if obj .has_default or required else True
30723074 else :
30733075 required = not obj .nullable and required
3074- nullable = None
3076+ # Set nullable=False when has_default and schema doesn't explicitly allow null
3077+ # This prevents fall_back_to_nullable from adding | None
3078+ if obj .nullable :
3079+ nullable = True
3080+ elif obj .has_default :
3081+ nullable = False
3082+ else :
3083+ nullable = None
30753084 is_tuple = False
30763085 suppress_item_constraints = False
30773086 if isinstance (obj .items , JsonSchemaObject ):
@@ -3256,10 +3265,35 @@ def parse_root_type( # noqa: PLR0912, PLR0914, PLR0915
32563265 data_type = self .data_type_manager .get_data_type (
32573266 Types .any ,
32583267 )
3259- required = self ._should_field_be_required (
3260- has_default = obj .has_default ,
3261- is_nullable = bool (obj .nullable ),
3262- )
3268+ # For RootModels (not TypeAlias):
3269+ # - required=False when nullable or has_default (preserves = None for nullable types)
3270+ # - nullable=False when has_default and not explicitly nullable (prevents fall_back_to_nullable)
3271+ # For TypeAlias (IS_ALIAS=True):
3272+ # - Defaults are meaningless for type aliases, so don't process has_default
3273+ is_type_alias = getattr (self .data_model_root_type , "IS_ALIAS" , False )
3274+ if self .force_optional_for_required_fields :
3275+ required = False
3276+ nullable = None # Will be handled by fall_back_to_nullable
3277+ # Force optional makes all fields optional, so use None as default
3278+ has_default_override = True
3279+ default_value = obj .default if obj .has_default else None
3280+ elif obj .nullable :
3281+ required = False
3282+ nullable = True
3283+ # Nullable fields should have None as default when no explicit default is set
3284+ has_default_override = True
3285+ default_value = obj .default if obj .has_default else None
3286+ elif obj .has_default and not is_type_alias :
3287+ required = False
3288+ # Set nullable=False to prevent fall_back_to_nullable from adding | None
3289+ nullable = False
3290+ has_default_override = True
3291+ default_value = obj .default
3292+ else :
3293+ required = True
3294+ nullable = None
3295+ has_default_override = obj .has_default
3296+ default_value = obj .default if obj .has_default else UNDEFINED
32633297 name = self ._apply_title_as_name (name , obj )
32643298 if not reference :
32653299 reference = self .model_resolver .add (path , name , loaded = True , class_name = True )
@@ -3273,20 +3307,18 @@ def parse_root_type( # noqa: PLR0912, PLR0914, PLR0915
32733307 fields = [
32743308 self .data_model_field_type (
32753309 data_type = data_type ,
3276- default = obj . default ,
3310+ default = default_value ,
32773311 required = required ,
32783312 constraints = constraints ,
3279- nullable = obj .nullable
3280- if self .strict_nullable and obj .nullable is not None
3281- else (False if self .strict_nullable and obj .has_default else None ),
3313+ nullable = nullable ,
32823314 strip_default_none = self .strip_default_none ,
32833315 extras = self .get_field_extras (obj ),
32843316 use_annotated = self .use_annotated ,
32853317 use_field_description = self .use_field_description ,
32863318 use_field_description_example = self .use_field_description_example ,
32873319 use_inline_field_description = self .use_inline_field_description ,
32883320 original_name = None ,
3289- has_default = obj . has_default ,
3321+ has_default = has_default_override ,
32903322 )
32913323 ],
32923324 custom_base_class = self ._resolve_base_class (name , obj .custom_base_path ),
@@ -3295,7 +3327,7 @@ def parse_root_type( # noqa: PLR0912, PLR0914, PLR0915
32953327 path = self .current_source_path ,
32963328 nullable = obj .type_has_null ,
32973329 treat_dot_as_module = self .treat_dot_as_module ,
3298- default = obj . default if obj . has_default else UNDEFINED ,
3330+ default = default_value if has_default_override else UNDEFINED ,
32993331 )
33003332 self .results .append (data_model_root_type )
33013333 return self .data_type (reference = reference )
0 commit comments