@@ -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 :
@@ -3054,7 +3056,7 @@ def parse_list_item(
30543056 for index , item in enumerate (target_items )
30553057 ]
30563058
3057- def parse_array_fields ( # noqa: PLR0912
3059+ def parse_array_fields ( # noqa: PLR0912, PLR0915
30583060 self ,
30593061 name : str ,
30603062 obj : JsonSchemaObject ,
@@ -3069,12 +3071,19 @@ def parse_array_fields( # noqa: PLR0912
30693071 required : bool = False
30703072 nullable : Optional [bool ] = None # noqa: UP045
30713073 else :
3072- required = not ( obj .has_default and self . apply_default_values_for_required_fields )
3074+ required = not obj .has_default
30733075 if self .strict_nullable :
30743076 nullable = obj .nullable if obj .has_default or required else True
30753077 else :
30763078 required = not obj .nullable and required
3077- nullable = None
3079+ # Set nullable=False when has_default and schema doesn't explicitly allow null
3080+ # This prevents fall_back_to_nullable from adding | None
3081+ if obj .nullable :
3082+ nullable = True
3083+ elif obj .has_default :
3084+ nullable = False
3085+ else :
3086+ nullable = None
30783087 is_tuple = False
30793088 suppress_item_constraints = False
30803089 if isinstance (obj .items , JsonSchemaObject ):
@@ -3259,10 +3268,35 @@ def parse_root_type( # noqa: PLR0912, PLR0914, PLR0915
32593268 data_type = self .data_type_manager .get_data_type (
32603269 Types .any ,
32613270 )
3262- required = self ._should_field_be_required (
3263- has_default = obj .has_default ,
3264- is_nullable = bool (obj .nullable ),
3265- )
3271+ # For RootModels (not TypeAlias):
3272+ # - required=False when nullable or has_default (preserves = None for nullable types)
3273+ # - nullable=False when has_default and not explicitly nullable (prevents fall_back_to_nullable)
3274+ # For TypeAlias (IS_ALIAS=True):
3275+ # - Defaults are meaningless for type aliases, so don't process has_default
3276+ is_type_alias = getattr (self .data_model_root_type , "IS_ALIAS" , False )
3277+ if self .force_optional_for_required_fields :
3278+ required = False
3279+ nullable = None # Will be handled by fall_back_to_nullable
3280+ # Force optional makes all fields optional, so use None as default
3281+ has_default_override = True
3282+ default_value = obj .default if obj .has_default else None
3283+ elif obj .nullable :
3284+ required = False
3285+ nullable = True
3286+ # Nullable fields should have None as default when no explicit default is set
3287+ has_default_override = True
3288+ default_value = obj .default if obj .has_default else None
3289+ elif obj .has_default and not is_type_alias :
3290+ required = False
3291+ # Set nullable=False to prevent fall_back_to_nullable from adding | None
3292+ nullable = False
3293+ has_default_override = True
3294+ default_value = obj .default
3295+ else :
3296+ required = True
3297+ nullable = None
3298+ has_default_override = obj .has_default
3299+ default_value = obj .default if obj .has_default else UNDEFINED
32663300 name = self ._apply_title_as_name (name , obj )
32673301 if not reference :
32683302 reference = self .model_resolver .add (path , name , loaded = True , class_name = True )
@@ -3276,20 +3310,18 @@ def parse_root_type( # noqa: PLR0912, PLR0914, PLR0915
32763310 fields = [
32773311 self .data_model_field_type (
32783312 data_type = data_type ,
3279- default = obj . default ,
3313+ default = default_value ,
32803314 required = required ,
32813315 constraints = constraints ,
3282- nullable = obj .nullable
3283- if self .strict_nullable and obj .nullable is not None
3284- else (False if self .strict_nullable and obj .has_default else None ),
3316+ nullable = nullable ,
32853317 strip_default_none = self .strip_default_none ,
32863318 extras = self .get_field_extras (obj ),
32873319 use_annotated = self .use_annotated ,
32883320 use_field_description = self .use_field_description ,
32893321 use_field_description_example = self .use_field_description_example ,
32903322 use_inline_field_description = self .use_inline_field_description ,
32913323 original_name = None ,
3292- has_default = obj . has_default ,
3324+ has_default = has_default_override ,
32933325 )
32943326 ],
32953327 custom_base_class = self ._resolve_base_class (name , obj .custom_base_path ),
@@ -3298,7 +3330,7 @@ def parse_root_type( # noqa: PLR0912, PLR0914, PLR0915
32983330 path = self .current_source_path ,
32993331 nullable = obj .type_has_null ,
33003332 treat_dot_as_module = self .treat_dot_as_module ,
3301- default = obj . default if obj . has_default else UNDEFINED ,
3333+ default = default_value if has_default_override else UNDEFINED ,
33023334 )
33033335 self .results .append (data_model_root_type )
33043336 return self .data_type (reference = reference )
0 commit comments