Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ellar/di/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ class DIImproperConfiguration(Exception):
pass


class RequestScopeContextNotFound(Exception):
pass


__all__ = [
"CallError",
"CircularDependency",
Expand All @@ -21,4 +25,5 @@ class DIImproperConfiguration(Exception):
"UnknownProvider",
"UnsatisfiedRequirement",
"DIImproperConfiguration",
"RequestScopeContextNotFound",
]
6 changes: 5 additions & 1 deletion ellar/di/scopes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
UnsatisfiedRequirement,
)

from .exceptions import RequestScopeContextNotFound
from .providers import InstanceProvider, Provider
from .types import T

Expand All @@ -34,7 +35,10 @@ def get(self, key: t.Type[T], provider: Provider[T]) -> Provider[T]:
scoped_context = self.get_context()

if scoped_context is None:
raise UnsatisfiedRequirement(None, key)
raise RequestScopeContextNotFound(
"RequestScope is not available. Trying to access RequestScope outside request",
UnsatisfiedRequirement(None, key),
)
try:
return scoped_context.context[key]
except KeyError:
Expand Down
14 changes: 13 additions & 1 deletion ellar/testing/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,19 @@ def get_test_client(
)

def get(self, interface: t.Type[T]) -> T:
return self.create_application().injector.get(interface) # type: ignore[no-any-return]
try:
return t.cast(T, self.create_application().injector.get(interface))
except Exception as ex:
# try to find module to which the interface belongs
module = self.create_application().injector.tree_manager.search_module_tree(
filter_item=lambda data: True,
find_predicate=lambda data: interface in data.exports
or interface in data.providers,
)
if module:
return t.cast(T, module.value.get(interface))

raise ex


class Test:
Expand Down
1 change: 1 addition & 0 deletions requirements-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pytest-asyncio
pytest-cov >= 2.12.0,< 6.0.0
python-multipart >= 0.0.5
python-socketio
regex==2024.11.6
ruff ==0.6.3
types-dataclasses ==0.6.6
types-orjson ==3.6.2
Expand Down
3 changes: 2 additions & 1 deletion tests/test_di/test_injector.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
request_scope,
transient_scope,
)
from ellar.di.exceptions import RequestScopeContextNotFound
from ellar.di.providers import ClassProvider, InstanceProvider
from injector import Binder, Injector, UnsatisfiedRequirement

Expand Down Expand Up @@ -119,7 +120,7 @@ async def test_request_service_context():
with pytest.raises(UnsatisfiedRequirement):
injector.get(Foo)

with pytest.raises(UnsatisfiedRequirement):
with pytest.raises(RequestScopeContextNotFound):
injector.get(Foo1)


Expand Down
6 changes: 3 additions & 3 deletions tests/test_di/test_provider_scopes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from ellar.core import HttpRequestConnectionContext
from ellar.core.execution_context import HostContextFactory
from ellar.di import EllarInjector, ProviderConfig, has_binding
from ellar.di.exceptions import DIImproperConfiguration
from ellar.di.exceptions import DIImproperConfiguration, RequestScopeContextNotFound
from ellar.di.scopes import RequestScope, SingletonScope, TransientScope
from ellar.utils.importer import get_class_import
from injector import UnsatisfiedRequirement, inject
from injector import inject

from .examples import AnyContext, Foo, IContext, TransientRequestContext

Expand Down Expand Up @@ -52,7 +52,7 @@ async def test_request_scope_instance():

# resolving RequestScope Providers outside RequestServiceProvider will behave like TransientScope

with pytest.raises(UnsatisfiedRequirement):
with pytest.raises(RequestScopeContextNotFound):
assert injector.get(IContext)

async with HttpRequestConnectionContext(
Expand Down