-
-
Notifications
You must be signed in to change notification settings - Fork 485
Open
Labels
Bug 🐛This is something that is not working as expectedThis is something that is not working as expected
Description
Description
The Provide class cannot properly detect when a callable instance's __call__ method is a generator function. This breaks the dependency injection with cleanup pattern when using stateful callable instances.
Reproduction
from typing import Generator, Any
from uuid import UUID, uuid4
from litestar.di import Provide
class SessionSchedulerFactory:
"""A callable factory that maintains state across calls."""
def __init__(self):
self._sessions: dict[UUID, object] = {}
def __call__(self) -> Generator[object, Any, None]:
"""Generator method that should be detected by Provide."""
try:
yield uuid4()
finally:
pass
def session_scheduler_factory() -> Generator[object, Any, None]:
try:
yield uuid4()
finally:
pass
# Function works correctly
Provide(session_scheduler_factory, sync_to_thread=False).has_sync_generator_dependency # True
# Callable instance fails to be detected
Provide(SessionSchedulerFactory(), sync_to_thread=False).has_sync_generator_dependency # FalseNote: This example is simplified for reproducibility. The real use case involves maintaining a cache of sessions across multiple dependency injections, which requires instance state.
Root Cause
In Provide.__init__, isclass(instance) returns False for callable instances, so the code checks isgeneratorfunction(instance) instead of isgeneratorfunction(instance.__call__):
is_class_dependency = isclass(dependency)
self.has_sync_generator_dependency = isgeneratorfunction(
dependency if not is_class_dependency else dependency.__call__
)Proposed Fix
Check callable instances the same way as classes:
is_class_dependency = isclass(dependency)
is_callable_instance = not is_class_dependency and hasattr(dependency, '__call__')
check_target = dependency.__call__ if (is_class_dependency or is_callable_instance) else dependency
self.has_sync_generator_dependency = isgeneratorfunction(check_target)
self.has_async_generator_dependency = isasyncgenfunction(check_target)Litestar Version
litestar==2.18.0
Metadata
Metadata
Assignees
Labels
Bug 🐛This is something that is not working as expectedThis is something that is not working as expected