Skip to content

Commit

Permalink
Merge pull request #47 from team23/sivachandran-sp/override-partial-c…
Browse files Browse the repository at this point in the history
…lass-name

Allow partial class name can be overridden by @sivachandran
  • Loading branch information
ddanier authored Feb 12, 2025
2 parents 1eb1855 + 4d0ad4d commit 32a4215
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 5 deletions.
12 changes: 9 additions & 3 deletions pydantic_partial/partial.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def create_partial_model(
base_cls: type[SelfT],
*fields: str,
recursive: bool = False,
partial_cls_name: Optional[str] = None,
) -> type[SelfT]:
# Convert one type to being partial - if possible
def _partial_annotation_arg(field_name_: str, field_annotation: type) -> type:
Expand Down Expand Up @@ -128,9 +129,12 @@ def _partial_annotation_arg(field_name_: str, field_annotation: type) -> type:
if not optional_fields:
return base_cls

if partial_cls_name is None:
partial_cls_name = f"{base_cls.__name__}Partial"

# Generate new subclass model with those optional fields
return pydantic.create_model(
f"{base_cls.__name__}Partial",
partial_cls_name,
__base__=base_cls,
**optional_fields,
)
Expand All @@ -147,21 +151,23 @@ def model_as_partial(
cls: type[ModelSelfT],
*fields: str,
recursive: bool = False,
partial_cls_name: Optional[str] = None,
) -> type[ModelSelfT]:
return cast(
type[ModelSelfT],
create_partial_model(cls, *fields, recursive=recursive),
create_partial_model(cls, *fields, recursive=recursive, partial_cls_name=partial_cls_name),
)

@classmethod
def as_partial(
cls: type[ModelSelfT],
*fields: str,
recursive: bool = False,
partial_cls_name: Optional[str] = None,
) -> type[ModelSelfT]:
warnings.warn(
"as_partial(...) is deprecated, use model_as_partial(...) instead",
DeprecationWarning,
stacklevel=2,
)
return cls.model_as_partial(*fields, recursive=recursive)
return cls.model_as_partial(*fields, recursive=recursive, partial_cls_name=partial_cls_name)
9 changes: 9 additions & 0 deletions tests/test_partial.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,12 @@ def test_no_change_to_optional_fields():
def test_as_partial_works_as_expected():
with pytest.warns(DeprecationWarning):
assert Something.model_as_partial() is Something.as_partial()


def test_partial_class_name_can_be_overridden():
SomethingPartial = Something.model_as_partial("name")
assert SomethingPartial.__name__ == "SomethingPartial"

partial_cls_name = "SomethingWithOptionalName"
SomethingWithOptionalName = Something.model_as_partial("name", partial_cls_name=partial_cls_name)
assert SomethingWithOptionalName.__name__ == partial_cls_name
13 changes: 11 additions & 2 deletions tests/test_partial_without_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,18 @@ def test_partial_model_will_only_be_cached_with_same_params():


def test_partial_model_will_be_the_same_on_mixin():
# Note: When we do not pass recursive=False the functools.lru_cache will
# Note: When we do not pass recursive=False and partial_cls_name=None the functools.lru_cache will
# actually create a separate model class, as the parameters differ.
SomethingWithMixinPartial1 = create_partial_model(SomethingWithMixin, recursive=False)
SomethingWithMixinPartial1 = create_partial_model(SomethingWithMixin, recursive=False, partial_cls_name=None)
SomethingWithMixinPartial2 = SomethingWithMixin.model_as_partial()

assert SomethingWithMixinPartial1 is SomethingWithMixinPartial2


def test_partial_class_name_can_be_overridden():
SomethingPartial = create_partial_model(Something, "name")
assert SomethingPartial.__name__ == "SomethingPartial"

partial_cls_name = "SomethingWithOptionalName"
SomethingWithOptionalName = create_partial_model(Something, "name", partial_cls_name=partial_cls_name)
assert SomethingWithOptionalName.__name__ == partial_cls_name

0 comments on commit 32a4215

Please sign in to comment.