Skip to content

Commit d764c39

Browse files
authored
refactor: Internal logic about constants
1 parent 5130b19 commit d764c39

4 files changed

Lines changed: 42 additions & 56 deletions

File tree

injection/_core/common/lazy.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator
1+
from collections.abc import Callable, Iterator
22
from functools import partial
33

44
from injection._core.common.invertible import Invertible
@@ -13,15 +13,6 @@ def cache() -> Iterator[T]:
1313
return partial(next, cache())
1414

1515

16-
def alazy[T](factory: Callable[..., Awaitable[T]]) -> Callable[[], Awaitable[T]]:
17-
async def cache() -> AsyncIterator[T]:
18-
value = await factory()
19-
while True:
20-
yield value
21-
22-
return partial(_anext, cache())
23-
24-
2516
class Lazy[T](Invertible[T]):
2617
__slots__ = ("__get", "__is_set")
2718

@@ -44,7 +35,3 @@ def __invert__(self) -> T:
4435
@property
4536
def is_set(self) -> bool:
4637
return self.__is_set
47-
48-
49-
async def _anext[T](async_iterator: AsyncIterator[T]) -> T:
50-
return await anext(async_iterator)

injection/_core/injectables.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ def unlock(self) -> None:
119119
self.cache.pop(self.__key, None)
120120

121121

122+
@dataclass(repr=False, eq=False, frozen=True, slots=True)
123+
class ConstantInjectable[T](Injectable[T]):
124+
instance: T
125+
126+
async def aget_instance(self) -> T:
127+
return self.instance
128+
129+
def get_instance(self) -> T:
130+
return self.instance
131+
132+
122133
@dataclass(repr=False, eq=False, frozen=True, slots=True)
123134
class ScopedInjectable[R, T](Injectable[T], ABC):
124135
factory: Caller[..., R]

injection/_core/locator.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,32 +73,44 @@ class InjectableBroker[T](Protocol):
7373
def get(self, provider: InjectionProvider) -> Injectable[T] | None:
7474
raise NotImplementedError
7575

76+
@abstractmethod
77+
def is_locked(self, provider: InjectionProvider) -> bool:
78+
raise NotImplementedError
79+
7680
@abstractmethod
7781
def request(self, provider: InjectionProvider) -> Injectable[T]:
7882
raise NotImplementedError
7983

8084

8185
@dataclass(repr=False, eq=False, frozen=True, slots=True)
8286
class DynamicInjectableBroker[T](InjectableBroker[T]):
83-
injectable_factory: InjectableFactory[T]
87+
factory: InjectableFactory[T]
8488
recipe: Recipe[..., T]
85-
cache: WeakKeyDictionary[InjectionProvider, Injectable[T]] = field(
89+
injectables: WeakKeyDictionary[InjectionProvider, Injectable[T]] = field(
8690
default_factory=WeakKeyDictionary,
8791
init=False,
8892
)
8993

9094
def get(self, provider: InjectionProvider) -> Injectable[T] | None:
91-
return self.cache.get(provider)
95+
return self.injectables.get(provider)
96+
97+
def is_locked(self, provider: InjectionProvider) -> bool:
98+
injectable = self.get(provider)
99+
100+
if injectable is None:
101+
return False
102+
103+
return injectable.is_locked
92104

93105
def request(self, provider: InjectionProvider) -> Injectable[T]:
94106
with suppress(KeyError):
95-
return self.cache[provider]
107+
return self.injectables[provider]
96108

97109
injectable = _make_injectable(
98-
self.injectable_factory,
110+
self.factory,
99111
provider.make_injected_function(self.recipe), # type: ignore[misc]
100112
)
101-
self.cache[provider] = injectable
113+
self.injectables[provider] = injectable
102114
return injectable
103115

104116

@@ -109,16 +121,19 @@ class StaticInjectableBroker[T](InjectableBroker[T]):
109121
def get(self, provider: InjectionProvider) -> Injectable[T] | None:
110122
return self.value
111123

124+
def is_locked(self, provider: InjectionProvider) -> bool:
125+
return False
126+
112127
def request(self, provider: InjectionProvider) -> Injectable[T]:
113128
return self.value
114129

115130
@classmethod
116131
def from_factory(
117132
cls,
118-
injectable_factory: InjectableFactory[T],
133+
factory: InjectableFactory[T],
119134
recipe: Recipe[..., T],
120135
) -> Self:
121-
return cls(_make_injectable(injectable_factory, recipe))
136+
return cls(_make_injectable(factory, recipe))
122137

123138

124139
class Mode(StrEnum):
@@ -172,9 +187,7 @@ def __brokers(self) -> frozenset[InjectableBroker[Any]]:
172187
return frozenset(record.broker for record in self.__records.values())
173188

174189
def is_locked(self, provider: InjectionProvider) -> bool:
175-
return any(
176-
injectable.is_locked for injectable in self.__iter_injectables(provider)
177-
)
190+
return any(broker.is_locked(provider) for broker in self.__brokers)
178191

179192
def request[T](
180193
self,

injection/_core/module.py

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
from injection._core.common.event import Event, EventChannel, EventListener
5151
from injection._core.common.invertible import Invertible, SimpleInvertible
5252
from injection._core.common.key import new_short_key
53-
from injection._core.common.lazy import Lazy, alazy, lazy
53+
from injection._core.common.lazy import Lazy
5454
from injection._core.common.threading import get_lock
5555
from injection._core.common.type import (
5656
InputType,
@@ -61,6 +61,7 @@
6161
from injection._core.injectables import (
6262
AsyncCMScopedInjectable,
6363
CMScopedInjectable,
64+
ConstantInjectable,
6465
Injectable,
6566
ScopedInjectable,
6667
ScopedSlotInjectable,
@@ -249,6 +250,7 @@ def decorator(wp: Recipe[P, T]) -> Recipe[P, T]:
249250
return decorator(wrapped) if wrapped else decorator
250251

251252
singleton = partialmethod(injectable, cls=SingletonInjectable)
253+
constant = partialmethod(injectable, cls=SingletonInjectable, inject=False)
252254

253255
def scoped[**P, T](
254256
self,
@@ -293,34 +295,12 @@ def decorator(
293295

294296
def should_be_injectable[T](self, wrapped: type[T] | None = None, /) -> Any:
295297
def decorator(wp: type[T]) -> type[T]:
296-
injectable = ShouldBeInjectable(wp)
297-
broker = StaticInjectableBroker(injectable)
298+
broker = StaticInjectableBroker(ShouldBeInjectable(wp))
298299
self.update_from(wp, broker, Mode.FALLBACK)
299300
return wp
300301

301302
return decorator(wrapped) if wrapped else decorator
302303

303-
def constant[**P, T](
304-
self,
305-
wrapped: Recipe[P, T] | None = None,
306-
/,
307-
*,
308-
on: TypeInfo[T] = (),
309-
mode: Mode | ModeStr = Mode.get_default(),
310-
) -> Any:
311-
def decorator(wp: Recipe[P, T]) -> Recipe[P, T]:
312-
recipe: Recipe[[], T] = alazy(wp) if iscoroutinefunction(wp) else lazy(wp) # type: ignore[arg-type]
313-
self.injectable(
314-
recipe,
315-
ignore_type_hint=True,
316-
inject=False,
317-
on=(wp, on),
318-
mode=mode,
319-
)
320-
return wp
321-
322-
return decorator(wrapped) if wrapped else decorator
323-
324304
def set_constant[T](
325305
self,
326306
instance: T,
@@ -335,13 +315,8 @@ def set_constant[T](
335315
elif not on:
336316
raise ValueError("`on` must be provided when `alias` is `True`.")
337317

338-
self.injectable(
339-
lambda: instance,
340-
ignore_type_hint=True,
341-
inject=False,
342-
on=on,
343-
mode=mode,
344-
)
318+
broker = StaticInjectableBroker(ConstantInjectable(instance))
319+
self.update_from(on, broker, mode)
345320
return instance
346321

347322
def reserve_scoped_slot[T](

0 commit comments

Comments
 (0)