Skip to content

Commit cad0d9b

Browse files
author
remimd
committed
on progress
1 parent c999cff commit cad0d9b

File tree

3 files changed

+42
-49
lines changed

3 files changed

+42
-49
lines changed

injection/common/lazy.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,7 @@ def __iter__(self) -> Iterator[_K]:
5656

5757
def __len__(self) -> int:
5858
return len(~self.__lazy)
59+
60+
@property
61+
def is_set(self) -> bool:
62+
return self.__lazy.is_set

injection/core/module.py

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
wraps,
2626
)
2727
from inspect import Signature, isclass
28-
from types import MappingProxyType, UnionType
28+
from types import UnionType
2929
from typing import (
3030
Any,
3131
ClassVar,
@@ -421,7 +421,7 @@ def decorator(wp):
421421
wp.__init__ = self.inject(wp.__init__, force=force)
422422
return wp
423423

424-
wrapper = Injected(wp, force=force).update(self)
424+
wrapper = InjectionFunction(wp, force=force).update(self)
425425
self.add_listener(wrapper)
426426
return wrapper
427427

@@ -540,45 +540,35 @@ def __move_module(self, module: Module, priority: ModulePriority):
540540

541541

542542
"""
543-
Injected
543+
InjectionFunction
544544
"""
545545

546546

547547
@dataclass(repr=False, frozen=True, slots=True)
548548
class Dependencies:
549-
mapping: MappingProxyType[str, Injectable]
550-
551-
__SELF_KEY: ClassVar[str] = "$self"
549+
mapping: Mapping[str, Injectable]
552550

553551
def __bool__(self) -> bool:
554552
return bool(self.mapping)
555553

556-
@property
557-
def arguments(self) -> OrderedDict[str, Any]:
558-
return OrderedDict(self.items(exclude={self.__SELF_KEY}))
559-
560-
@property
561-
def self(self) -> Any | None:
562-
return self.get(self.__SELF_KEY)
563-
564-
def items(self, /, *, exclude: Set[str] = frozenset()) -> Iterator[tuple[str, Any]]:
554+
def __iter__(self) -> Iterator[tuple[str, Any]]:
565555
for name, injectable in self.mapping.items():
566-
if name in exclude:
567-
continue
568-
569556
yield name, injectable.get_instance()
570557

571-
def get(self, key: str) -> Any | None:
572-
injectable = self.mapping.get(key)
558+
@property
559+
def are_resolved(self) -> bool:
560+
if isinstance(self.mapping, LazyMapping) and not self.mapping.is_set:
561+
return False
573562

574-
if injectable is None:
575-
return None
563+
return bool(self)
576564

577-
return injectable.get_instance()
565+
@property
566+
def arguments(self) -> OrderedDict[str, Any]:
567+
return OrderedDict(self)
578568

579569
@classmethod
580570
def from_mapping(cls, mapping: Mapping[str, Injectable]):
581-
return cls(mapping=MappingProxyType(mapping))
571+
return cls(mapping=mapping)
582572

583573
@classmethod
584574
def empty(cls):
@@ -602,8 +592,9 @@ def __resolver(
602592
)
603593

604594
if owner:
595+
name, _ = next(hints)
605596
hints = itertools.chain(
606-
((cls.__SELF_KEY, owner),),
597+
((name, owner),),
607598
hints,
608599
)
609600

@@ -621,48 +612,47 @@ class Arguments(NamedTuple):
621612
kwargs: Mapping[str, Any]
622613

623614

624-
class Injected(EventListener):
625-
__slots__ = ("__dict__", "__function", "__dependencies", "__owner")
615+
class InjectionFunction(EventListener):
616+
__slots__ = ("__dict__", "__wrapped__", "__wrapper", "__dependencies", "__owner")
626617

627618
def __init__(self, wrapped: Callable[..., Any], *, force: bool = False):
628-
update_wrapper(self, wrapped)
619+
update_wrapper(self, wrapped, updated=())
629620

630621
@wraps(wrapped)
631622
def wrapper(*args, **kwargs):
632623
args, kwargs = self.bind(args, kwargs, force)
633624
return wrapped(*args, **kwargs)
634625

635-
self.__function = wrapper
626+
self.__wrapper = wrapper
636627
self.__dependencies = Dependencies.empty()
637628
self.__owner = None
638629

639630
def __repr__(self) -> str:
640-
return repr(self.__function)
631+
return repr(self.__wrapped__)
641632

642633
def __str__(self) -> str:
643-
return str(self.__function)
634+
return str(self.__wrapped__)
644635

645636
def __call__(self, /, *args, **kwargs) -> Any:
646-
return self.__function(*args, **kwargs)
637+
return self.__wrapper(*args, **kwargs)
647638

648639
def __get__(self, instance: object | None, owner: type):
649640
if instance is None:
650-
instance = self.__dependencies.self
641+
return self
651642

652-
return self.__function.__get__(instance, owner)
643+
return self.__wrapper.__get__(instance, owner)
653644

654645
def __set_name__(self, owner: type, name: str):
655-
if self.__dependencies:
656-
raise TypeError
646+
if self.__dependencies.are_resolved:
647+
raise TypeError("TODO")
657648

658649
if self.__owner:
659-
raise TypeError
650+
raise TypeError("TODO")
660651

661-
with thread_lock:
662-
self.__owner = owner
652+
self.__owner = owner
663653

664654
@cached_property
665-
def __signature(self) -> Signature:
655+
def __signature__(self) -> Signature:
666656
return inspect.signature(self.__wrapped__, eval_str=True)
667657

668658
def bind(
@@ -674,22 +664,23 @@ def bind(
674664
if kwargs is None:
675665
kwargs = {}
676666

677-
if not (arguments := self.__dependencies.arguments):
667+
if not self.__dependencies:
678668
return Arguments(args, kwargs)
679669

680-
bound = self.__signature.bind_partial(*args, **kwargs)
670+
bound = self.__signature__.bind_partial(*args, **kwargs)
671+
dependencies = self.__dependencies.arguments
681672

682673
if force:
683-
bound.arguments |= arguments
674+
bound.arguments |= dependencies
684675
else:
685-
bound.arguments = arguments | bound.arguments
676+
bound.arguments = dependencies | bound.arguments
686677

687678
return Arguments(bound.args, bound.kwargs)
688679

689680
def update(self, module: Module):
690681
with thread_lock:
691682
self.__dependencies = Dependencies.resolve(
692-
self.__signature,
683+
self.__signature__,
693684
module,
694685
self.__owner,
695686
)

tests/test_inject.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,11 @@ def test_inject_with_self_injectable(self):
175175
class A:
176176
@inject
177177
def my_method(self, dependency: SomeInjectable):
178-
pass
178+
assert isinstance(self, A)
179+
assert isinstance(dependency, SomeInjectable)
179180

180181
with pytest.raises(TypeError):
181182
A.my_method()
182183

183184
injectable(A)
184185
assert A.my_method() is None
185-
186-
a = A.my_method.__self__
187-
assert isinstance(a, A)

0 commit comments

Comments
 (0)