litestar-org / litestar-org/polyfactory

Enhancement: Add an optional database parameter to BaseFactory.create_{a}sync

Open
#878 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
1.5k
Forks
120
PR merge metrics
No merged PRs in 30d

Description

### Summary

Both `create_sync` and `create_async` currently accept kwargs but forward them directly to the `build` or `batch` methods.
They also both call `_get_sync_persistence` which allows to dynamically create a __{a}sync_persistence__ instance but is not receiving any parameters.

My idea is to allow for a single `database: Any | None` parameter to be passed from the `create_{a}sync` methods to `_get_async_persistence` and add an `__init__` to both `{As,S}yncPersistenceProtocol`.
We could then use it at runtime in tests to specify a particular database in which to create the object.

See the next example which might be clearer.
The database used here does not exists but looks like Mongo which is what I used in the real project.

```py
# persistence.py
@runtime_checkable
class SyncPersistenceProtocol(Protocol[T]):
database: Any | None

def __init__(self, database: Any | None = None):
self.database = database
...
```

```py
# factories.base.py
class BaseFactory(ABC, Generic[T]):
@classmethod
def _get_sync_persistence(cls, database: Any | None = None) -> SyncPersistenceProtocol[T]:
...
if cls.__sync_persistence__:
return cls.__sync_persistence__(database) if callable(cls.__sync_persistence__) else cls.__sync_persistence__
...
...
@classmethod
def create_sync(cls, database: Any | None = None, **kwargs: Any) -> T:
...
return cls._get_sync_persistence(database).save(data=cls.build(**kwargs))
```

```py
# tests.factories.py

class SyncPersistenceHandler(SyncPersistenceProtocol[Person]):
def save(self, person: Person) -> Person:
self.database.person_collection.insert_one(person.model_dump())
return person

def save_many(self, data: list[Person]) -> list[Person]:
self.database.person_collection.insert_many([person.model_dump() for person in data])
return data

class PersonFactory(ModelFactory[Person]):
__sync_persistence__ = SyncPersistenceHandler
...
```

```
# tests.test_person.py

@fixure
def database(settings):
client = Client(settings)
return client.database

def test_create(database):
person = PersonFactory.create_sync(database=database, age=42)
assert database.person_collection.exists(id=person.id)
```

### Basic Example

_No response_

### Drawbacks and Impact

_No response_

### Unresolved questions

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with persistence.py and factories.base.py, focusing on the SyncPersistenceProtocol, AsyncPersistenceProtocol, and BaseFactory create_sync/create_async paths. Review tests.test_person.py for the persistence-handler usage, then add coverage showing a supplied database reaches both sync and async persistence instances and that object creation still succeeds.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
database, testing
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.