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
12 changes: 4 additions & 8 deletions injection/common/lazy.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from functools import partial
from types import new_class
from types import MappingProxyType, new_class
from typing import Any, Callable, Generic, Iterator, Mapping, TypeVar

from frozendict import frozendict

__all__ = ("Lazy", "LazyMapping")

_sentinel = new_class("sentinel")()
Expand All @@ -22,7 +19,7 @@ def __init__(self, factory: Callable[[], T]):

def __setattr__(self, name: str, value: Any):
if self.is_set:
raise TypeError(f"`{repr(self)}` is frozen.")
raise TypeError(f"`{self}` is frozen.")

return super().__setattr__(name, value)

Expand All @@ -47,11 +44,10 @@ def is_set(self) -> bool:
class LazyMapping(Mapping[K, V]):
__slots__ = ("__lazy",)

__lazy: Lazy[frozendict[K, V]]
__lazy: Lazy[MappingProxyType[K, V]]

def __init__(self, iterator: Iterator[tuple[K, V]]):
factory = partial(frozendict, iterator)
self.__lazy = Lazy(factory)
self.__lazy = Lazy(lambda: MappingProxyType(dict(iterator)))

def __getitem__(self, key: K) -> V:
return self.__lazy.value[key]
Expand Down
45 changes: 23 additions & 22 deletions injection/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,29 +84,37 @@ class ModuleEventProxy(ModuleEvent):
def __str__(self) -> str:
return f"`{self.on_module}` has propagated an event: {self.origin}"

def __iter__(self) -> Iterator[Event]:
@property
def history(self) -> Iterator[Event]:
if isinstance(self.event, ModuleEventProxy):
yield from self.event
yield from self.event.history

yield self.event

@property
def origin(self) -> Event:
return next(iter(self))
return next(self.history)

@property
def is_circular(self) -> bool:
return any(
isinstance(event, ModuleEvent) and event.on_module is self.on_module
for event in self
)
def check_recursion(self):
last_module = None
found = False

@property
def previous_module(self) -> Module | None:
if isinstance(self.event, ModuleEvent):
return self.event.on_module
for event in self.history:
if not isinstance(event, ModuleEvent):
continue

return None
last_module = event.on_module

if found is False:
found = last_module is self.on_module

if found:
raise ModuleCircularUseError(
"Circular dependency between two modules: "
f"`{self.on_module}` and `{last_module}`."
)

return self


@dataclass(frozen=True, slots=True)
Expand Down Expand Up @@ -390,14 +398,7 @@ def remove_listener(self, listener: EventListener):
return self

def on_event(self, event: Event, /):
self_event = ModuleEventProxy(self, event)

if self_event.is_circular:
raise ModuleCircularUseError(
"Circular dependency between two modules: "
f"`{self_event.previous_module}` and `{self}`."
)

self_event = ModuleEventProxy(self, event).check_recursion()
self.notify(self_event)

def notify(self, event: Event):
Expand Down
58 changes: 6 additions & 52 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ repository = "https://github.com/simplysquare/python-injection"

[tool.poetry.dependencies]
python = ">=3.10, <4"
frozendict = "*"

[tool.poetry.group.dev.dependencies]
black = "*"
Expand Down