diff --git a/pydantic_partial/partial.py b/pydantic_partial/partial.py index b62fbcf..e446f37 100644 --- a/pydantic_partial/partial.py +++ b/pydantic_partial/partial.py @@ -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: @@ -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, ) @@ -147,10 +151,11 @@ 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 @@ -158,10 +163,11 @@ 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) diff --git a/tests/test_partial.py b/tests/test_partial.py index 74fa1b3..6664dba 100644 --- a/tests/test_partial.py +++ b/tests/test_partial.py @@ -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 diff --git a/tests/test_partial_without_mixin.py b/tests/test_partial_without_mixin.py index 783b84a..cfdedc7 100644 --- a/tests/test_partial_without_mixin.py +++ b/tests/test_partial_without_mixin.py @@ -61,3 +61,12 @@ def test_partial_model_will_be_the_same_on_mixin(): 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