Skip to content

Commit 63f1064

Browse files
authored
refactor: Improve code readability
1 parent 132e5ef commit 63f1064

File tree

11 files changed

+162
-201
lines changed

11 files changed

+162
-201
lines changed

injection/__init__.pyi

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,8 @@ class Module:
145145
extensively.
146146
"""
147147

148-
name: str
148+
name: str | None
149149

150-
def __init__(self, name: str = ...) -> None: ...
151150
def __contains__(self, cls: _InputType[Any], /) -> bool: ...
152151
@property
153152
def is_locked(self) -> bool: ...

injection/_core/common/asynchronous.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,3 @@ async def acall(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
6464

6565
def call(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
6666
return self.callable(*args, **kwargs)
67-
68-
69-
@runtime_checkable
70-
class HiddenCaller[**P, T](Protocol):
71-
__slots__ = ()
72-
73-
@property
74-
@abstractmethod
75-
def __injection_hidden_caller__(self) -> Caller[P, T]:
76-
raise NotImplementedError
77-
78-
@abstractmethod
79-
def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
80-
raise NotImplementedError

injection/_core/common/key.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

injection/_core/common/type.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,19 @@ def get_yield_hints[T](
5151
return ()
5252

5353

54-
def iter_return_types(*args: TypeInfo[Any]) -> Iterator[InputType[Any]]:
54+
def iter_flat_types(*args: Any) -> Iterator[Any]:
5555
for arg in args:
5656
if isinstance(arg, Collection) and not isclass(arg):
57-
inner_args = arg
58-
59-
elif isfunction(arg) and (return_type := get_return_hint(arg)):
60-
inner_args = (return_type,)
57+
yield from iter_flat_types(*arg)
6158

6259
else:
63-
yield arg # type: ignore[misc]
64-
continue
60+
yield arg
61+
6562

66-
yield from iter_return_types(*inner_args)
63+
def iter_return_types(*args: Any) -> Iterator[Any]:
64+
for arg in args:
65+
if isfunction(arg) and (return_type := get_return_hint(arg)):
66+
yield from iter_return_types(return_type)
67+
68+
else:
69+
yield arg

injection/_core/locator.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@
1717
)
1818
from weakref import WeakKeyDictionary
1919

20-
from injection._core.common.asynchronous import (
21-
AsyncCaller,
22-
Caller,
23-
HiddenCaller,
24-
SyncCaller,
25-
)
20+
from injection._core.common.asynchronous import AsyncCaller, Caller, SyncCaller
2621
from injection._core.common.event import Event, EventChannel, EventListener
2722
from injection._core.common.type import InputType
2823
from injection._core.injectables import Injectable
@@ -285,8 +280,8 @@ def _extract_caller[**P, T](
285280
if iscoroutinefunction(function):
286281
return AsyncCaller(function)
287282

288-
elif isinstance(function, HiddenCaller):
289-
return function.__injection_hidden_caller__
283+
elif metadata := getattr(function, "__injection_metadata__", None):
284+
return metadata
290285

291286
return SyncCaller(function) # type: ignore[arg-type]
292287

injection/_core/module.py

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

3-
import itertools
4-
from abc import ABC
3+
from abc import ABC, abstractmethod
54
from collections import OrderedDict, deque
65
from collections.abc import (
76
AsyncGenerator,
@@ -45,20 +44,16 @@
4544

4645
from type_analyzer import MatchingTypesConfig, iter_matching_types, matching_types
4746

48-
from injection._core.common.asynchronous import (
49-
Caller,
50-
HiddenCaller,
51-
SimpleAwaitable,
52-
)
47+
from injection._core.common.asynchronous import Caller, SimpleAwaitable
5348
from injection._core.common.event import Event, EventChannel, EventListener
5449
from injection._core.common.invertible import Invertible, SimpleInvertible
55-
from injection._core.common.key import new_short_key
5650
from injection._core.common.lazy import Lazy
5751
from injection._core.common.threading import get_lock
5852
from injection._core.common.type import (
5953
InputType,
6054
TypeInfo,
6155
get_yield_hints,
56+
iter_flat_types,
6257
iter_return_types,
6358
)
6459
from injection._core.injectables import (
@@ -94,10 +89,6 @@
9489
SkipInjectable,
9590
)
9691

97-
"""
98-
Events
99-
"""
100-
10192

10293
@dataclass(frozen=True, slots=True)
10394
class ModuleEvent(Event, ABC):
@@ -154,11 +145,6 @@ def __str__(self) -> str:
154145
)
155146

156147

157-
"""
158-
Module
159-
"""
160-
161-
162148
class Priority(StrEnum):
163149
LOW = "low"
164150
HIGH = "high"
@@ -187,7 +173,7 @@ class _ScopedContext[**P, T]:
187173

188174
@dataclass(eq=False, frozen=True, slots=True)
189175
class Module(EventListener, InjectionProvider): # type: ignore[misc]
190-
name: str = field(default_factory=lambda: f"anonymous@{new_short_key()}")
176+
name: str | None = field(default=None)
191177
__channel: EventChannel = field(
192178
default_factory=EventChannel,
193179
init=False,
@@ -730,9 +716,10 @@ def default(cls) -> Module:
730716
def __build_key_types(input_cls: Any) -> frozenset[Any]:
731717
config = MatchingTypesConfig(ignore_none=True)
732718
return frozenset(
733-
itertools.chain.from_iterable(
734-
iter_matching_types(cls, config) for cls in iter_return_types(input_cls)
735-
)
719+
matching_type
720+
for cls in iter_flat_types(input_cls)
721+
for return_type in iter_return_types(cls)
722+
for matching_type in iter_matching_types(return_type, config)
736723
)
737724

738725
@staticmethod
@@ -748,11 +735,6 @@ def mod(name: str | None = None, /) -> Module:
748735
return Module.from_name(name)
749736

750737

751-
"""
752-
InjectedFunction
753-
"""
754-
755-
756738
@dataclass(repr=False, frozen=True, slots=True)
757739
class Dependencies:
758740
lazy_mapping: Lazy[Mapping[str, Injectable[Any]]]
@@ -786,8 +768,7 @@ def items(self, exclude: Container[str]) -> Iterator[tuple[str, Injectable[Any]]
786768

787769
@classmethod
788770
def from_iterable(cls, iterable: Iterable[tuple[str, Injectable[Any]]]) -> Self:
789-
lazy_mapping = Lazy(lambda: dict(iterable))
790-
return cls(lazy_mapping)
771+
return cls(Lazy(lambda: dict(iterable)))
791772

792773
@classmethod
793774
def empty(cls) -> Self:
@@ -970,7 +951,7 @@ def __run_tasks(self) -> None:
970951
task()
971952

972953

973-
class InjectedFunction[**P, T](HiddenCaller[P, T], ABC):
954+
class InjectedFunction[**P, T](ABC):
974955
__slots__ = ("__dict__", "__injection_metadata__")
975956

976957
__injection_metadata__: InjectMetadata[P, T]
@@ -985,10 +966,6 @@ def __repr__(self) -> str: # pragma: no cover
985966
def __str__(self) -> str: # pragma: no cover
986967
return str(self.__injection_metadata__.wrapped)
987968

988-
@property
989-
def __injection_hidden_caller__(self) -> Caller[P, T]:
990-
return self.__injection_metadata__
991-
992969
def __get__(
993970
self,
994971
instance: object | None = None,
@@ -1002,6 +979,10 @@ def __get__(
1002979
def __set_name__(self, owner: type, name: str) -> None:
1003980
self.__injection_metadata__.set_owner(owner)
1004981

982+
@abstractmethod
983+
def __call__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
984+
raise NotImplementedError
985+
1005986

1006987
class AsyncInjectedFunction[**P, T](InjectedFunction[P, Awaitable[T]]):
1007988
__slots__ = ()

injection/_core/scope.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from contextvars import ContextVar
99
from dataclasses import dataclass, field
1010
from enum import StrEnum
11+
from functools import partial
1112
from types import EllipsisType, TracebackType
1213
from typing import (
1314
TYPE_CHECKING,
@@ -23,7 +24,6 @@
2324
runtime_checkable,
2425
)
2526

26-
from injection._core.common.key import new_short_key
2727
from injection._core.common.threading import get_lock
2828
from injection._core.slots import SlotKey
2929
from injection.exceptions import (
@@ -69,7 +69,7 @@ class _ContextualScopeResolver(ScopeResolver):
6969
# Shouldn't be instantiated outside `__scope_resolvers`.
7070

7171
__context_var: ContextVar[Scope] = field(
72-
default_factory=lambda: ContextVar(f"scope@{new_short_key()}"),
72+
default_factory=partial(ContextVar, "__injection_scope__"),
7373
init=False,
7474
)
7575
__references: set[Scope] = field(
@@ -163,7 +163,7 @@ def get_scope[T](name: str, default: T | EllipsisType = ...) -> Scope | T:
163163
if resolver and (scope := resolver.get_scope()):
164164
return scope
165165

166-
if default is Ellipsis:
166+
if default is ...:
167167
raise ScopeUndefinedError(
168168
f"Scope `{name}` isn't defined in the current context."
169169
)
@@ -194,7 +194,7 @@ def _bind_scope(
194194
lock = get_lock(threadsafe)
195195

196196
with lock:
197-
if get_scope(name, default=None):
197+
if get_scope(name, None):
198198
raise ScopeAlreadyDefinedError(
199199
f"Scope `{name}` is already defined in the current context."
200200
)

injection/loaders.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,7 @@ def __is_empty(self) -> bool:
150150
return not self.module_subsets
151151

152152
def required_module_names(self, name: str | None = None, /) -> frozenset[str]:
153-
names = {self.module.name}
154-
155-
if name is not None:
156-
names.add(name)
157-
153+
names = {n for n in (self.module.name, name) if n is not None}
158154
subsets = (self.__walk_subsets_for(name) for name in names)
159155
return frozenset(itertools.chain.from_iterable(subsets))
160156

@@ -175,24 +171,30 @@ def _unload(self, name: str, /) -> None:
175171
self.module.unlock().stop_using(mod(name))
176172

177173
def __init_subsets_for(self, module: Module) -> Module:
178-
if not self.__is_empty and not self.__is_initialized(module):
174+
module_name = module.name
175+
176+
if (
177+
not self.__is_empty
178+
and module_name is not None
179+
and not self.__is_initialized(module_name)
180+
):
179181
target_modules = tuple(
180182
self.__init_subsets_for(mod(name))
181-
for name in self.module_subsets.get(module.name, ())
183+
for name in self.module_subsets.get(module_name, ())
182184
)
183185
module.init_modules(*target_modules)
184-
self.__mark_initialized(module)
186+
self.__mark_initialized(module_name)
185187

186188
return module
187189

188190
def __is_default_module(self, module_name: str) -> bool:
189191
return module_name == self.module.name
190192

191-
def __is_initialized(self, module: Module) -> bool:
192-
return module.name in self.__initialized_modules
193+
def __is_initialized(self, module_name: str) -> bool:
194+
return module_name in self.__initialized_modules
193195

194-
def __mark_initialized(self, module: Module) -> None:
195-
self.__initialized_modules.add(module.name)
196+
def __mark_initialized(self, module_name: str) -> None:
197+
self.__initialized_modules.add(module_name)
196198

197199
def __walk_subsets_for(self, module_name: str) -> Iterator[str]:
198200
yield module_name

tests/test_injectable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ class B:
240240

241241
@injectable
242242
async def a_factory(_b: B) -> A:
243-
return A()
243+
return A() # pragma: no cover
244244

245245
with pytest.raises(RecursionError):
246246
await aget_instance(A)

tests/test_singleton.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class B:
194194

195195
@singleton
196196
async def a_factory(_b: B) -> A:
197-
return A()
197+
return A() # pragma: no cover
198198

199199
with pytest.raises(RecursionError):
200200
await aget_instance(A)

0 commit comments

Comments
 (0)