Bug: Support custom types providers for which there already exists a registered base factory
Description
It seems like defining a type in get_provider_map(cls) wouldn't work if that type is already handled by an existing base_factory (such as dataclass, Pydantic model, etc).
It's possible this is intended, as the Handling Custom Types docs only specifies a plain-old Python class CustomSecret.
Please see the MCVE below for what my desired behavior would be. Is this currently possible? I've tried playing around with __base_factory_overrides__ but didn't have any luck.
URL to code causing the issue
No response
MCVE
from pydantic import BaseModel, ConfigDict
from polyfactory.factories.pydantic_factory import ModelFactory
class CustomSecretPydantic(BaseModel):
value: str
class CustomSecretPlain:
def __init__(self, value: str) -> None:
self.value = value
def __repr__(self) -> str:
return self.value
def __str__(self) -> str:
return self.value
class MyModel(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
id: int
secret: CustomSecretPydantic
class MyFactory(ModelFactory[MyModel]):
@classmethod
def get_provider_map(cls) -> dict[type, Any]:
providers_map = super().get_provider_map()
return {
**providers_map,
CustomSecretPydantic: lambda: CustomSecretPydantic.model_validate({"value": "asdf"}),
CustomSecretPlain: lambda: CustomSecretPlain(value="asdf"),
}
if __name__ == "__main__":
print(MyFactory.build())
Steps to reproduce
1. Run code
2. Observe that "asdf" is NOT generated
I'd expect that it would be.
Screenshots
"In the format of: "
Logs
No response
Release Version
2.17.0
Platform
- [ ] Linux
- [X] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)
Hi @mjmaurer ,
Looks like this currently isn't possible but PRs welcome to fix.
Couple of potential workarounds
- Set this at the field level.
- Create a separate factory that targets this model only and register as default type, e.g. something like
class CustomSecretPydantic(ModelFactory[CustomSecretPydantic]):
__set_as_default_factory_for_type__ = True
@classmethod
def process_kwargs(cls, **kwargs: Any) -> dict[str, Any]:
return {"value": "asdf"}
Thanks, the latter option worked perfectly!