python-neva 3.3.0__py3-none-any.whl → 3.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -175,6 +175,10 @@ class ServiceProvider(abc.ABC):
175
175
  _ = self.provider.decorate(source, provides=interface, scope=scope, when=when)
176
176
  return self
177
177
 
178
+ def from_context(self, interface: type, scope: Scope | None = None) -> None:
179
+ """Declares an interface as provided by the current context."""
180
+ _ = self.provider.from_context(provides=interface, scope=scope)
181
+
178
182
  @abc.abstractmethod
179
183
  def register(self) -> Result[Self, str]:
180
184
  """Register services into the application container.
@@ -1,7 +1,20 @@
1
- from neva.events.contracts.dispatcher import EventDispatcher
1
+ from neva.events.contracts.dispatcher import (
2
+ AsyncBeforeDispatchHook,
3
+ BeforeDispatchHook,
4
+ EventDispatcher,
5
+ SyncBeforeDispatchHook,
6
+ )
2
7
  from neva.events.contracts.event import Event
3
8
  from neva.events.contracts.handler import EventHandler
4
9
  from neva.events.contracts.listener import EventListener
5
10
 
6
11
 
7
- __all__ = ["Event", "EventDispatcher", "EventHandler", "EventListener"]
12
+ __all__ = [
13
+ "AsyncBeforeDispatchHook",
14
+ "BeforeDispatchHook",
15
+ "Event",
16
+ "EventDispatcher",
17
+ "EventHandler",
18
+ "EventListener",
19
+ "SyncBeforeDispatchHook",
20
+ ]
@@ -1,10 +1,29 @@
1
- from typing import Protocol
1
+ from typing import Protocol, runtime_checkable
2
2
 
3
3
  from neva.events.contracts.event import Event
4
4
  from neva.events.contracts.listener import EventListener
5
5
  from neva.support import Result
6
6
 
7
7
 
8
+ @runtime_checkable
9
+ class AsyncBeforeDispatchHook(Protocol):
10
+ """Asynchronous hook to be called before listeners are invoked."""
11
+
12
+ async def __call__(self, context: Event) -> None:
13
+ """Execute the hook."""
14
+
15
+
16
+ @runtime_checkable
17
+ class SyncBeforeDispatchHook(Protocol):
18
+ """Synchronous hook to be called before listeners are invoked."""
19
+
20
+ def __call__(self, context: Event) -> None:
21
+ """Execute the hook."""
22
+
23
+
24
+ BeforeDispatchHook = AsyncBeforeDispatchHook | SyncBeforeDispatchHook
25
+
26
+
8
27
  class EventDispatcher(Protocol):
9
28
  """Event dispatcher protocol."""
10
29
 
@@ -15,6 +34,10 @@ class EventDispatcher(Protocol):
15
34
  """Dispatch an event to all registered listeners."""
16
35
  ...
17
36
 
37
+ async def before_dispatch(self, hook: BeforeDispatchHook) -> None:
38
+ """Register a hook to be called before listeners are invoked."""
39
+ ...
40
+
18
41
  def listen[T: Event](
19
42
  self,
20
43
  event_cls: type[T],
neva/events/dispatcher.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Base implementation of the event dispatcher."""
2
2
 
3
- from typing import Callable, Protocol, override, runtime_checkable
3
+ from typing import override
4
4
 
5
5
  from neva.arch.application import Application
6
6
  from neva.database.manager import DatabaseManager
@@ -10,19 +10,6 @@ from neva.events.event_registry import EventRegistry
10
10
  from neva.support import Err, Nothing, Result, Some
11
11
 
12
12
 
13
- @runtime_checkable
14
- class AsyncBeforeDispatchHook(Protocol):
15
- async def __call__(self, context: contracts.Event) -> None: ...
16
-
17
-
18
- @runtime_checkable
19
- class SyncBeforeDispatchHook(Protocol):
20
- def __call__(self, context: contracts.Event) -> None: ...
21
-
22
-
23
- BeforeDispatchHook = AsyncBeforeDispatchHook | SyncBeforeDispatchHook
24
-
25
-
26
13
  class EventDispatcher(contracts.EventDispatcher):
27
14
  """Event dispatcher implementation."""
28
15
 
@@ -35,7 +22,7 @@ class EventDispatcher(contracts.EventDispatcher):
35
22
  self._registry: EventRegistry = registry
36
23
  self._app: Application = app
37
24
  self._db: DatabaseManager = db
38
- self._before_dispatch_hooks: list[BeforeDispatchHook] = []
25
+ self._before_dispatch_hooks: list[contracts.BeforeDispatchHook] = []
39
26
 
40
27
  async def _apply_before_dispatch(self, event: contracts.Event) -> None:
41
28
  """Extension hook called before listeners are invoked.
@@ -49,12 +36,13 @@ class EventDispatcher(contracts.EventDispatcher):
49
36
  """
50
37
  for hook in self._before_dispatch_hooks:
51
38
  match hook:
52
- case AsyncBeforeDispatchHook():
39
+ case contracts.AsyncBeforeDispatchHook():
53
40
  await hook(event)
54
- case SyncBeforeDispatchHook():
41
+ case contracts.SyncBeforeDispatchHook():
55
42
  hook(event)
56
43
 
57
- async def before_dispatch(self, hook: BeforeDispatchHook) -> None:
44
+ @override
45
+ async def before_dispatch(self, hook: contracts.BeforeDispatchHook) -> None:
58
46
  """Register a hook to be called before listeners are invoked."""
59
47
  self._before_dispatch_hooks.append(hook)
60
48
 
@@ -2,9 +2,8 @@
2
2
 
3
3
  from typing import override
4
4
 
5
- from neva import events
6
5
  from neva.arch import Facade
7
- from neva.events import EventListener
6
+ from neva.events import contracts
8
7
  from neva.support import Result
9
8
 
10
9
  class Event(Facade):
@@ -14,10 +13,10 @@ class Event(Facade):
14
13
  @override
15
14
  def get_facade_accessor(cls) -> type: ...
16
15
  @classmethod
17
- async def dispatch(cls, event: events.Event) -> list[Result[None, str]]: ...
16
+ async def dispatch(cls, event: contracts.Event) -> list[Result[None, str]]: ...
18
17
  @classmethod
19
- def listen[T: events.Event](
18
+ def listen[T: contracts.Event](
20
19
  cls,
21
20
  event_cls: type[T],
22
- listener_cls: type[EventListener[T]],
21
+ listener_cls: type[contracts.EventListener[T]],
23
22
  ) -> None: ...
neva/testing/fakes.py CHANGED
@@ -1,19 +1,20 @@
1
1
  """Testing fakes for Neva facades."""
2
2
 
3
3
  from collections.abc import Callable
4
- from typing import Any
4
+ from typing import override
5
5
 
6
- from neva.events.event import Event as BaseEvent
6
+ from neva.events import contracts
7
7
  from neva.support import Result
8
8
 
9
9
 
10
- class EventFake:
10
+ class EventFake(contracts.EventDispatcher):
11
11
  """Recording fake for the Event facade. No listeners are dispatched."""
12
12
 
13
13
  def __init__(self) -> None:
14
- self._dispatched: list[BaseEvent[Any]] = []
14
+ self._dispatched: list[contracts.Event] = []
15
15
 
16
- async def dispatch(self, event: BaseEvent[Any]) -> list[Result[None, str]]:
16
+ @override
17
+ async def dispatch(self, event: contracts.Event) -> list[Result[None, str]]:
17
18
  """Record the event without invoking any listeners.
18
19
 
19
20
  Returns:
@@ -22,10 +23,17 @@ class EventFake:
22
23
  self._dispatched.append(event)
23
24
  return []
24
25
 
25
- def listen[T: BaseEvent[Any]](self, event_cls: type[T], listener_cls: type) -> None:
26
+ @override
27
+ def listen[T: contracts.Event](
28
+ self, event_cls: type[T], listener_cls: type[contracts.EventListener[T]]
29
+ ) -> None:
26
30
  """No-op."""
27
31
 
28
- def dispatched[E: BaseEvent[Any]](self, event_cls: type[E]) -> list[E]:
32
+ @override
33
+ async def before_dispatch(self, hook: contracts.BeforeDispatchHook) -> None:
34
+ """Register a hook to be called before listeners are invoked."""
35
+
36
+ def dispatched[E: contracts.Event](self, event_cls: type[E]) -> list[E]:
29
37
  """Return all recorded events of the given type.
30
38
 
31
39
  Returns:
@@ -33,7 +41,7 @@ class EventFake:
33
41
  """
34
42
  return [e for e in self._dispatched if isinstance(e, event_cls)]
35
43
 
36
- def assert_dispatched[E: BaseEvent[Any]](
44
+ def assert_dispatched[E: contracts.Event](
37
45
  self,
38
46
  event_cls: type[E],
39
47
  *,
@@ -61,7 +69,7 @@ class EventFake:
61
69
  if match is not None and not any(match(e) for e in matching):
62
70
  raise AssertionError(f"No {event_cls.__name__} matched the predicate")
63
71
 
64
- def assert_not_dispatched[E: BaseEvent[Any]](self, event_cls: type[E]) -> None:
72
+ def assert_not_dispatched[E: contracts.Event](self, event_cls: type[E]) -> None:
65
73
  """Assert that no event of the given type was dispatched.
66
74
 
67
75
  Args:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-neva
3
- Version: 3.3.0
3
+ Version: 3.4.0
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: aiosqlite>=0.20.0
@@ -5,7 +5,7 @@ neva/arch/facade.py,sha256=1kYVhyYto8zSyOZV6sAYJ3xWzQDJRzoVV-e_EarTp0Q,7927
5
5
  neva/arch/markers.py,sha256=STdhmW88qV8uogIa9kSD9gs-uMRaglZI8HOw3PrhX1Q,103
6
6
  neva/arch/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  neva/arch/scopes.py,sha256=Gu0kJk39Yv8LCCzxjdu0lIE0FXtnsG36LGKDuNin2CE,87
8
- neva/arch/service_provider.py,sha256=zEFwix2cL6l1Frv9w1OMtnL_zjkl_BVpGBhRaNK6bb0,5636
8
+ neva/arch/service_provider.py,sha256=SqL3uQGBh7aDIc_Lcp8Ijr3fdOtB8wbsmMnjU4GuUy4,5862
9
9
  neva/arch/integrations/__init__.py,sha256=cXuqC4JfZdGYLlh6POgYUVXUT2NQ84276eC-RYTyFxk,75
10
10
  neva/arch/integrations/faststream.py,sha256=AOwfpfdL3O5HLAx80SwUGQb_hKEeAkFOUyIXtjODaHM,1696
11
11
  neva/config/__init__.py,sha256=Ygfnh-MRRKYDdf54_LeMSHwmck5VpNHTdnnMtGEFLtU,121
@@ -21,15 +21,15 @@ neva/database/provider.py,sha256=l2be4Ri53RtQq1-qzohy3cqzJQpTaNzqXGVhXPKUCXc,167
21
21
  neva/database/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  neva/database/transaction.py,sha256=_0Dsao_vhCJT5YRUmrHOLb0uxvfdE-5k3n0yMPLC1o8,5167
23
23
  neva/events/__init__.py,sha256=Gpi5q-pNlIi-q23U2ZOsNf8Y9rB6AQtsBbbBFU0tkFc,776
24
- neva/events/dispatcher.py,sha256=fFhF39sba1VOiwLa2eHzib5qWk4n_SOoWiYkmZL044o,4686
24
+ neva/events/dispatcher.py,sha256=5M8s3aVzx9lIViGkigtu1kq6gFbam4OKDajuWNGuqA0,4376
25
25
  neva/events/event.py,sha256=q-KyyxNkU3AN2YSaujuNPIoXQMXhGOwClTap5y8fU5I,282
26
26
  neva/events/event_registry.py,sha256=IZnpR3oLyvt5K2pn9KMCBw5W4JP7Ok_zMKI2SgQoXVM,1945
27
27
  neva/events/listener.py,sha256=2d5RHVKO0pU-eL_evLReTG0DIoX9tZyOcn8PWLeECZo,1435
28
28
  neva/events/policy.py,sha256=I67ziob0IEVeXdkilNPpj2f48gEz2EZneR1Fz8Nlt2U,154
29
29
  neva/events/provider.py,sha256=cVxADLv7VXCK6gTMJsDNRzspMOH2lrIkvMRhqVh2cK4,954
30
30
  neva/events/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- neva/events/contracts/__init__.py,sha256=6-xRFR_5t6PbU-owl0WtM8mmdvmNvuHPUyL1sbFfqU8,293
32
- neva/events/contracts/dispatcher.py,sha256=jJ4qLM_5-bXcBPH_txnbwHXAs6GFB080MiDkEViatTk,594
31
+ neva/events/contracts/__init__.py,sha256=t1VafYtzOZIF78V8X3K_Fg79Hw4FjSqasjLs0EQVIFA,489
32
+ neva/events/contracts/dispatcher.py,sha256=pzCv_ZLS5ju2IKVMxL5f-fFipEqQZc6zPiIVtJhKJHc,1274
33
33
  neva/events/contracts/event.py,sha256=kUUECex_AlmaPJ-fXRg32eMkiqNS75CHldOr7bbpFqo,89
34
34
  neva/events/contracts/handler.py,sha256=SwLuuRtXhCzGkcBBLdH3MjUAkjEr0_rhqgE6dkWVJxI,327
35
35
  neva/events/contracts/listener.py,sha256=0xwPrjprkMzXu9vY1Z-EjSLFdvOUpomiE65hH16nfxA,465
@@ -81,16 +81,16 @@ neva/support/facade/crypt.pyi,sha256=_MV_qXDATaCs1pZTOw_-qPx_jjH_nG4-tUBOMX4nZIE
81
81
  neva/support/facade/db.py,sha256=mXMzuCKf390ICCBgzaub1ZoMqUBgOQByQYMEM3YnN_0,324
82
82
  neva/support/facade/db.pyi,sha256=UQFMgBuw0BGquMnuUNULC8Pdo7lDCVTCNkDaUmIZJhw,1911
83
83
  neva/support/facade/event.py,sha256=sRU-fxaRT59Fe-u2WTS5L9ncGkGLBndKa9gKbqwAq3M,1232
84
- neva/support/facade/event.pyi,sha256=wI1NlIg8p6j9jispsA6pI-kvNp81nwUM3ZP8O0zFaHk,558
84
+ neva/support/facade/event.pyi,sha256=AL_v8fxkvtd9KwbiWbVuUAcdZz0yzLn8xZROFa6lXLE,546
85
85
  neva/support/facade/hash.py,sha256=tGhsvfGovt-mcRXSjDKf4jt1n7ib0eDPXFvRUfVxLUc,292
86
86
  neva/support/facade/hash.pyi,sha256=jTs3E5ZF5cp76jrgH70DEog8gzfYIcIV2PrO9xskHyI,1656
87
87
  neva/support/facade/log.py,sha256=_uLoHB9tkpHkiqEJXazbaqfiKUOtv3NS71ZCZAprzOI,347
88
88
  neva/support/facade/log.pyi,sha256=Xi7gIzw9qRqmD4D3PcW06_HUtgLWEOdsHqs1B0jh1-k,1647
89
89
  neva/testing/__init__.py,sha256=vt5zxG1N84vn_YwP44jhYPWYnyb02-cha3m-1l-qoEw,207
90
- neva/testing/fakes.py,sha256=5HuuwMeAKhFSZfn9T8raQIjdgHkjFeZsFXDud0T4v7Q,2674
90
+ neva/testing/fakes.py,sha256=w2dnFaO6x14l0_si7iBNELMCxaFi8VsVOSQ6PmTlclE,2936
91
91
  neva/testing/fixtures.py,sha256=oiPa5ntUkW-SbySDvwEHXtti8NqSwI-R0CT1_ezTx_Y,1445
92
92
  neva/testing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
93
93
  neva/testing/test_case.py,sha256=zJBZJeKI-sv-EOaXNuSJ0V2Zp_6hdk64W4dOh0eP8RI,3290
94
- python_neva-3.3.0.dist-info/METADATA,sha256=7J-vn_EdbJAX-DgR0zsWf8NWVIq2BPd5Fp5YYiZcbic,846
95
- python_neva-3.3.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
96
- python_neva-3.3.0.dist-info/RECORD,,
94
+ python_neva-3.4.0.dist-info/METADATA,sha256=rW3P72J2ukVUItHYsF1EDWCu4SJzGqv--6PjnYDnO5o,846
95
+ python_neva-3.4.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
96
+ python_neva-3.4.0.dist-info/RECORD,,