Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

model_json_schema export with Annotated types misses 'required' parameters #8793

Merged
merged 3 commits into from Feb 13, 2024

Conversation

LouisGobert
Copy link
Contributor

@LouisGobert LouisGobert commented Feb 13, 2024

Change Summary

When using an Annotation with a FieldInfo and an Ellipsis, the Ellipsis was considered as a default value. Therefore, the field was not considered mandatory.

Related issue number

fix #8780
fix #8634

Checklist

  • The pull request title is a good summary of the changes - it will be used in the changelog
  • Unit tests for the changes exist
  • Tests pass on CI
  • Documentation reflects the changes where applicable
  • My PR is ready to review, please add a comment including the phrase "please review" to assign reviewers

Selected Reviewer: @lig

Copy link

codspeed-hq bot commented Feb 13, 2024

CodSpeed Performance Report

Merging #8793 will not alter performance

Comparing LouisGobert:fix-annotation-with-field (093d05c) with main (832225b)

Summary

✅ 10 untouched benchmarks

@LouisGobert
Copy link
Contributor Author

please review

First open source contribution 🤞

@sydney-runkle sydney-runkle added the relnotes-fix Used for bugfixes. label Feb 13, 2024
Copy link
Member

@sydney-runkle sydney-runkle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great overall, just 2 quick change requests. Thanks!



def test_json_schema_annotated_with_field() -> None:
"""Check if the ellipsis in the signature is considered as a required field."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Check if the ellipsis in the signature is considered as a required field."""
"""Ensure field specified with Annotated in create_model call is still marked as required."""


Model = create_model(
'test_model',
bar=(Annotated[int, Field(description='Bar description')], ...),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you include this example as well? baz=(Annotated[int, Field(..., description="Baz description")], ...),

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe with this model:

Model = create_model(
    'test_model',
    foo=(int, ...),
    bar=(Annotated[int, Field(description="Bar description")], ...),
    baz=(Annotated[int, Field(..., description="Baz description")], ...),
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 😄

@sydney-runkle
Copy link
Member

So, with a slight modification to the logic in your PR, we can actually fix many related issues. My proposal is the following:

diff --git a/pydantic/fields.py b/pydantic/fields.py
index e369b52d..58332d79 100644
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -402,6 +402,13 @@ class FieldInfo(_repr.Representation):
             # No merging necessary, but we still need to make a copy and apply the overrides
             field_info = copy(field_infos[0])
             field_info._attributes_set.update(overrides)
+
+            default_override = overrides.pop('default', PydanticUndefined)
+            if default_override is Ellipsis:
+                default_override = PydanticUndefined
+            if field_info.default is not PydanticUndefined and default_override is not PydanticUndefined:
+                field_info.default = default_override
+
             for k, v in overrides.items():
                 setattr(field_info, k, v)
             return field_info  # type: ignore

Which fixes:

Would you be willing to add a test for the second issue as well? Thanks for your contribution!

@LouisGobert
Copy link
Contributor Author

if field_info.default is not PydanticUndefined and default_override is not PydanticUndefined:
    field_info.default = default_override

I think this was the wrong proposal because if a field is initialized with a default = PydanticUndefined, the overide won't work 😄

My modification:

if default_override is not PydanticUndefined:
    field_info.default = default_override

@sydney-runkle
Copy link
Member

Looks great, thanks for the help with the fix!

@sydney-runkle sydney-runkle merged commit 4541142 into pydantic:main Feb 13, 2024
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants