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

Correctly set required and nullable json schema values #43

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions pydantic_partial/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
if PYDANTIC_V1: # pragma: no cover
from pydantic.fields import ModelField # type: ignore

NULLABLE_KWARGS = {"nullable": True}
NULLABLE_KWARGS = {"nullable": True, "required": False}

class PydanticCompat: # type: ignore
model_class: type[pydantic.BaseModel]
Expand Down Expand Up @@ -46,7 +46,7 @@ def copy_model_field_info(self, model_field: ModelField, **kwargs: Any) -> Field
return copy_field_info(model_field.field_info, **kwargs)

elif PYDANTIC_V2: # pragma: no cover
NULLABLE_KWARGS = {"json_schema_extra": {"nullable": True}}
NULLABLE_KWARGS = {"json_schema_extra": {"nullable": True, "required": False}}

class PydanticCompat: # type: ignore
model_class: type[pydantic.BaseModel]
Expand All @@ -65,7 +65,11 @@ def get_model_field_info_annotation(self, field_info: FieldInfo) -> Optional[typ
return field_info.annotation

def is_model_field_info_required(self, field_info: FieldInfo) -> bool:
return field_info.is_required() # type: ignore
json_required = (
field_info.json_schema_extra is not None
and field_info.json_schema_extra.get("required", False)
)
return field_info.is_required() or json_required # type: ignore

def copy_model_field_info(self, field_info: FieldInfo, **kwargs: Any) -> FieldInfo:
return copy_field_info(field_info, **kwargs)
2 changes: 1 addition & 1 deletion pydantic_partial/partial.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def _partial_annotation_arg(field_name_: str, field_annotation: type) -> type:
field_info,
default=None, # Set default to None
default_factory=None, # Remove default_factory if set
**NULLABLE_KWARGS, # For API usage: set field as nullable
**NULLABLE_KWARGS, # For API usage: set field as nullable and not required
),
)
elif recursive or sub_fields_requested:
Expand Down
13 changes: 12 additions & 1 deletion tests/test_partial_without_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ def _field_is_required(model: Union[type[pydantic.BaseModel], pydantic.BaseModel
elif PYDANTIC_V2:
def _field_is_required(model: Union[type[pydantic.BaseModel], pydantic.BaseModel], field_name: str) -> bool:
"""Check if a field is required on a pydantic V2 model."""
return model.model_fields[field_name].is_required()
json_required = (
model.model_fields[field_name].json_schema_extra is not None
and model.model_fields[field_name].json_schema_extra.get("required", False)
)
return model.model_fields[field_name].is_required() or json_required
else:
raise DeprecationWarning("Pydantic has to be in version 1 or 2.")

Expand All @@ -21,6 +25,7 @@ class Something(pydantic.BaseModel):
name: str
age: int
already_optional: None = None
already_required: int = pydantic.Field(default=1, json_schema_extra={"required": True})


class SomethingWithMixin(PartialModelMixin, pydantic.BaseModel):
Expand Down Expand Up @@ -61,3 +66,9 @@ def test_partial_model_will_be_the_same_on_mixin():
SomethingWithMixinPartial2 = SomethingWithMixin.model_as_partial()

assert SomethingWithMixinPartial1 is SomethingWithMixinPartial2

def test_partial_model_will_override_json_required():
SomethingPartial = create_partial_model(Something)
assert _field_is_required(SomethingPartial, "already_required") is False
SomethingPartial.model_json_schema()["properties"]["already_required"]["nullable"] is True
SomethingPartial.model_json_schema()["properties"]["already_required"]["required"] is False