Skip to content

Commit 26393ff

Browse files
authored
feat: ✨ Skip injectable
1 parent 0053bdc commit 26393ff

4 files changed

Lines changed: 123 additions & 91 deletions

File tree

injection/_core/module.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
ModuleLockError,
7474
ModuleNotUsedError,
7575
NoInjectable,
76+
SkipInjectable,
7677
)
7778

7879
"""
@@ -620,7 +621,7 @@ async def aget_instance[T](
620621
async def aget_instance(self, cls, default=None): # type: ignore[no-untyped-def]
621622
try:
622623
return await self.afind_instance(cls)
623-
except KeyError:
624+
except (KeyError, SkipInjectable):
624625
return default
625626

626627
@overload
@@ -640,7 +641,7 @@ def get_instance[T](
640641
def get_instance(self, cls, default=None): # type: ignore[no-untyped-def]
641642
try:
642643
return self.find_instance(cls)
643-
except KeyError:
644+
except (KeyError, SkipInjectable):
644645
return default
645646

646647
@overload
@@ -866,29 +867,28 @@ class Dependencies:
866867
lazy_mapping: Lazy[Mapping[str, Injectable[Any]]]
867868

868869
def __iter__(self) -> Iterator[tuple[str, Any]]:
869-
for name, injectable in self.mapping.items():
870-
instance = injectable.get_instance()
871-
yield name, instance
870+
for name, injectable in self.items():
871+
with suppress(SkipInjectable):
872+
yield name, injectable.get_instance()
872873

873874
async def __aiter__(self) -> AsyncIterator[tuple[str, Any]]:
874-
for name, injectable in self.mapping.items():
875-
instance = await injectable.aget_instance()
876-
yield name, instance
875+
for name, injectable in self.items():
876+
with suppress(SkipInjectable):
877+
yield name, await injectable.aget_instance()
877878

878879
@property
879880
def are_resolved(self) -> bool:
880881
return self.lazy_mapping.is_set
881882

882-
@property
883-
def mapping(self) -> Mapping[str, Injectable[Any]]:
884-
return ~self.lazy_mapping
885-
886883
async def aget_arguments(self) -> dict[str, Any]:
887884
return {key: value async for key, value in self}
888885

889886
def get_arguments(self) -> dict[str, Any]:
890887
return dict(self)
891888

889+
def items(self) -> Iterator[tuple[str, Injectable[Any]]]:
890+
return iter((~self.lazy_mapping).items())
891+
892892
@classmethod
893893
def from_iterable(cls, iterable: Iterable[tuple[str, Injectable[Any]]]) -> Self:
894894
lazy_mapping = Lazy(lambda: dict(iterable))

injection/exceptions.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"ScopeAlreadyDefinedError",
1111
"ScopeError",
1212
"ScopeUndefinedError",
13+
"SkipInjectable",
1314
)
1415

1516

@@ -30,6 +31,9 @@ def cls(self) -> type[T]:
3031
return self.__class
3132

3233

34+
class SkipInjectable(InjectionError): ...
35+
36+
3337
class ModuleError(InjectionError): ...
3438

3539

@@ -42,7 +46,7 @@ class ModuleNotUsedError(KeyError, ModuleError): ...
4246
class ScopeError(InjectionError): ...
4347

4448

45-
class ScopeUndefinedError(LookupError, ScopeError): ...
49+
class ScopeUndefinedError(LookupError, SkipInjectable, ScopeError): ...
4650

4751

4852
class ScopeAlreadyDefinedError(ScopeError): ...

tests/test_scoped.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections.abc import AsyncIterator, Iterator
2+
from dataclasses import dataclass
23

34
import pytest
45

@@ -173,3 +174,30 @@ async def some_injectable_recipe() -> AsyncIterator[SomeInjectable]:
173174
instance_2 = await afind_instance(SomeInjectable)
174175

175176
assert instance_1 is instance_2
177+
178+
async def test_scoped_with_scope_not_defined(self):
179+
@scoped("test")
180+
class A: ...
181+
182+
@injectable
183+
@dataclass
184+
class B:
185+
a: A | None = None
186+
187+
# sync
188+
b = find_instance(B)
189+
assert b.a is None
190+
191+
with define_scope("test"):
192+
b = find_instance(B)
193+
194+
assert isinstance(b.a, A)
195+
196+
# async
197+
b = await afind_instance(B)
198+
assert b.a is None
199+
200+
async with adefine_scope("test"):
201+
b = await afind_instance(B)
202+
203+
assert isinstance(b.a, A)

0 commit comments

Comments
 (0)