Skip to content

Commit 091b777

Browse files
authored
refactoring: ♻️ More precise exceptions
1 parent df00c62 commit 091b777

File tree

5 files changed

+87
-58
lines changed

5 files changed

+87
-58
lines changed

injection/core/module.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@
2727

2828
from injection.common.event import Event, EventChannel, EventListener
2929
from injection.common.lazy import LazyMapping
30-
from injection.exceptions import ModuleError, NoInjectable
30+
from injection.exceptions import (
31+
ModuleCircularUseError,
32+
ModuleError,
33+
ModuleNotUsedError,
34+
NoInjectable,
35+
)
3136

3237
__all__ = ("Injectable", "Module", "ModulePriorities")
3338

@@ -73,24 +78,29 @@ class ModuleEvent(Event, ABC):
7378
on_module: Module
7479

7580

76-
@dataclass(frozen=True)
81+
@dataclass(frozen=True, slots=True)
7782
class ModuleEventProxy(ModuleEvent):
7883
event: Event
7984

8085
def __str__(self) -> str:
8186
return f"`{self.on_module}` has propagated an event: {self.origin}"
8287

83-
@cached_property
84-
def origin(self) -> Event:
88+
def __iter__(self) -> Iterator[Event]:
8589
if isinstance(self.event, ModuleEventProxy):
86-
return self.event.origin
90+
yield from self.event
8791

88-
return self.event
92+
yield self.event
93+
94+
@property
95+
def origin(self) -> Event:
96+
return next(self.__iter__())
8997

9098
@property
9199
def is_circular(self) -> bool:
92-
origin = self.origin
93-
return isinstance(origin, ModuleEvent) and origin.on_module is self.on_module
100+
return any(
101+
isinstance(event, ModuleEvent) and event.on_module is self.on_module
102+
for event in self
103+
)
94104

95105
@property
96106
def previous_module(self) -> Module | None:
@@ -381,7 +391,7 @@ def on_event(self, event: Event, /):
381391
self_event = ModuleEventProxy(self, event)
382392

383393
if self_event.is_circular:
384-
raise ModuleError(
394+
raise ModuleCircularUseError(
385395
"Circular dependency between two modules: "
386396
f"`{self_event.previous_module}` and `{self}`."
387397
)
@@ -399,7 +409,7 @@ def __move_module(self, module: Module, priority: ModulePriorities):
399409
try:
400410
self.__modules.move_to_end(module, last=last)
401411
except KeyError as exc:
402-
raise ModuleError(
412+
raise ModuleNotUsedError(
403413
f"`{module}` can't be found in the modules used by `{self}`."
404414
) from exc
405415

injection/exceptions.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
__all__ = ("InjectionError", "ModuleError", "NoInjectable")
2-
3-
41
class InjectionError(Exception):
52
...
63

@@ -11,3 +8,11 @@ class NoInjectable(KeyError, InjectionError):
118

129
class ModuleError(InjectionError):
1310
...
11+
12+
13+
class ModuleCircularUseError(ModuleError):
14+
...
15+
16+
17+
class ModuleNotUsedError(KeyError, ModuleError):
18+
...

poetry.lock

Lines changed: 39 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/core/test_module.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
from contextlib import suppress
12
from typing import Any
23

34
import pytest
45

56
from injection import Module, ModulePriorities
67
from injection.core import Injectable
7-
from injection.exceptions import ModuleError
8+
from injection.exceptions import ModuleCircularUseError, ModuleError, ModuleNotUsedError
89

910

1011
class SomeClass:
@@ -86,13 +87,28 @@ def test_use_with_self_raise_module_error(self, module, event_history):
8687

8788
event_history.assert_length(0)
8889

89-
def test_use_with_circular_dependency_raise_module_error(self, module):
90+
def test_use_with_circular_dependency_raise_module_circular_use_error(self, module):
9091
second_module = Module()
9192
module.use(second_module)
9293

93-
with pytest.raises(ModuleError):
94+
with pytest.raises(ModuleCircularUseError):
9495
second_module.use(module)
9596

97+
def test_use_with_deep_circular_dependency_raise_module_circular_use_error(
98+
self,
99+
module,
100+
):
101+
second_module = Module()
102+
third_module = Module()
103+
104+
module.use(second_module)
105+
106+
with suppress(ModuleCircularUseError):
107+
second_module.use(module)
108+
109+
with pytest.raises(ModuleCircularUseError):
110+
module.use(third_module)
111+
96112
def test_use_with_module_already_in_use_raise_module_error(
97113
self,
98114
module,
@@ -178,5 +194,5 @@ def test_change_priority_with_success(self, module, event_history):
178194
def test_change_priority_with_module_not_found(self, module, event_history):
179195
second_module = Module()
180196

181-
with pytest.raises(ModuleError):
197+
with pytest.raises(ModuleNotUsedError):
182198
module.change_priority(second_module, ModulePriorities.HIGH)

tests/helpers/event_helper.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
from injection.common.event import Event, EventListener
55

6-
__all__ = ("EventHistory",)
7-
86

97
@dataclass(repr=False, eq=False, frozen=True, slots=True)
108
class EventHistory(EventListener):

0 commit comments

Comments
 (0)