python-neva 3.2.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.
neva/events/__init__.py CHANGED
@@ -9,7 +9,8 @@ Three components are of particular interest:
9
9
 
10
10
  from neva.events.dispatcher import EventDispatcher
11
11
  from neva.events.event import Event
12
- from neva.events.listener import EventListener, HandlingPolicy, listener
12
+ from neva.events.listener import EventListener, listener
13
+ from neva.events.policy import HandlingPolicy
13
14
  from neva.events.provider import EventServiceProvider
14
15
 
15
16
 
@@ -0,0 +1,20 @@
1
+ from neva.events.contracts.dispatcher import (
2
+ AsyncBeforeDispatchHook,
3
+ BeforeDispatchHook,
4
+ EventDispatcher,
5
+ SyncBeforeDispatchHook,
6
+ )
7
+ from neva.events.contracts.event import Event
8
+ from neva.events.contracts.handler import EventHandler
9
+ from neva.events.contracts.listener import EventListener
10
+
11
+
12
+ __all__ = [
13
+ "AsyncBeforeDispatchHook",
14
+ "BeforeDispatchHook",
15
+ "Event",
16
+ "EventDispatcher",
17
+ "EventHandler",
18
+ "EventListener",
19
+ "SyncBeforeDispatchHook",
20
+ ]
@@ -0,0 +1,47 @@
1
+ from typing import Protocol, runtime_checkable
2
+
3
+ from neva.events.contracts.event import Event
4
+ from neva.events.contracts.listener import EventListener
5
+ from neva.support import Result
6
+
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
+
27
+ class EventDispatcher(Protocol):
28
+ """Event dispatcher protocol."""
29
+
30
+ async def dispatch(
31
+ self,
32
+ event: Event,
33
+ ) -> list[Result[None, str]]:
34
+ """Dispatch an event to all registered listeners."""
35
+ ...
36
+
37
+ async def before_dispatch(self, hook: BeforeDispatchHook) -> None:
38
+ """Register a hook to be called before listeners are invoked."""
39
+ ...
40
+
41
+ def listen[T: Event](
42
+ self,
43
+ event_cls: type[T],
44
+ listener_cls: type[EventListener[T]],
45
+ ) -> None:
46
+ """Register a listener for an event."""
47
+ ...
@@ -0,0 +1,7 @@
1
+ import pydantic
2
+
3
+
4
+ class Event(pydantic.BaseModel):
5
+ """Base Event class."""
6
+
7
+ pass
@@ -0,0 +1,14 @@
1
+ from typing import Protocol
2
+
3
+ from neva.events.contracts.event import Event
4
+ from neva.support import Result
5
+
6
+
7
+ class EventHandler[T: Event](Protocol):
8
+ """Define a valid function for event handling."""
9
+
10
+ __name__: str
11
+
12
+ async def __call__(self, event: T) -> Result[None, str]:
13
+ """Handle an event."""
14
+ ...
@@ -0,0 +1,19 @@
1
+ from typing import Protocol
2
+
3
+ from neva.events.contracts.event import Event
4
+ from neva.events.policy import HandlingPolicy
5
+ from neva.support import Result
6
+
7
+
8
+ class EventListener[T: Event](Protocol):
9
+ """Event listener protocol."""
10
+
11
+ policy: HandlingPolicy
12
+
13
+ async def handle(self, event: T) -> Result[None, str]:
14
+ """Handle an event.
15
+
16
+ Returns:
17
+ A result indicating whether the event was handled successfully.
18
+ """
19
+ ...
neva/events/dispatcher.py CHANGED
@@ -1,15 +1,16 @@
1
1
  """Base implementation of the event dispatcher."""
2
2
 
3
+ from typing import override
4
+
3
5
  from neva.arch.application import Application
4
6
  from neva.database.manager import DatabaseManager
5
7
  from neva.database.transaction import TransactionCallback
6
- from neva.events.event import Event
8
+ from neva.events import contracts
7
9
  from neva.events.event_registry import EventRegistry
8
- from neva.events.listener import EventListener
9
10
  from neva.support import Err, Nothing, Result, Some
10
11
 
11
12
 
12
- class EventDispatcher:
13
+ class EventDispatcher(contracts.EventDispatcher):
13
14
  """Event dispatcher implementation."""
14
15
 
15
16
  def __init__(
@@ -18,11 +19,12 @@ class EventDispatcher:
18
19
  db: DatabaseManager,
19
20
  registry: EventRegistry,
20
21
  ) -> None:
21
- self._registry = registry
22
- self._app = app
23
- self._db = db
22
+ self._registry: EventRegistry = registry
23
+ self._app: Application = app
24
+ self._db: DatabaseManager = db
25
+ self._before_dispatch_hooks: list[contracts.BeforeDispatchHook] = []
24
26
 
25
- async def _before_dispatch(self, event: Event) -> None:
27
+ async def _apply_before_dispatch(self, event: contracts.Event) -> None:
26
28
  """Extension hook called before listeners are invoked.
27
29
 
28
30
  Override in a subclass to add cross-cutting behaviour such as
@@ -32,8 +34,20 @@ class EventDispatcher:
32
34
  Args:
33
35
  event: The event about to be dispatched.
34
36
  """
35
-
36
- async def dispatch(self, event: Event) -> list[Result[None, str]]:
37
+ for hook in self._before_dispatch_hooks:
38
+ match hook:
39
+ case contracts.AsyncBeforeDispatchHook():
40
+ await hook(event)
41
+ case contracts.SyncBeforeDispatchHook():
42
+ hook(event)
43
+
44
+ @override
45
+ async def before_dispatch(self, hook: contracts.BeforeDispatchHook) -> None:
46
+ """Register a hook to be called before listeners are invoked."""
47
+ self._before_dispatch_hooks.append(hook)
48
+
49
+ @override
50
+ async def dispatch(self, event: contracts.Event) -> list[Result[None, str]]:
37
51
  """Dispatch an event to all registered listeners.
38
52
 
39
53
  Listeners are resolved from the DI container when available,
@@ -45,20 +59,23 @@ class EventDispatcher:
45
59
  Returns:
46
60
  A list of results, one per listener invocation.
47
61
  """
48
- await self._before_dispatch(event)
62
+ await self._apply_before_dispatch(event)
49
63
  results: list[Result[None, str]] = []
50
- listeners = self._registry.get_listeners(event)
64
+ listeners = self._registry.resolve_listeners(event)
51
65
 
52
- to_execute = listeners.immediate.copy()
66
+ immediate: list[type[contracts.EventListener[contracts.Event]]] = []
67
+ deferred: list[type[contracts.EventListener[contracts.Event]]] = []
68
+ [immediate.extend(listener.immediate.copy()) for listener in listeners]
69
+ [deferred.extend(listener.deferred.copy()) for listener in listeners]
53
70
 
54
71
  match self._db.current():
55
72
  case Some(tx):
56
- for listener_cls in listeners.deferred:
73
+ for listener_cls in deferred:
57
74
  _ = tx.on_commit(self._build_callback(event, listener_cls))
58
75
  case Nothing():
59
- to_execute += listeners.deferred
76
+ immediate.extend(deferred)
60
77
 
61
- for listener_cls in to_execute:
78
+ for listener_cls in immediate:
62
79
  listener = self._resolve_listener(listener_cls)
63
80
  try:
64
81
  results.append(await listener.handle(event))
@@ -67,17 +84,20 @@ class EventDispatcher:
67
84
 
68
85
  return results
69
86
 
70
- def listen[T: Event](
87
+ @override
88
+ def listen[T: contracts.Event](
71
89
  self,
72
- event_cls: type[T],
73
- listener_cls: type[EventListener[T]],
90
+ event_cls: type[T] | list[type[T]],
91
+ listener_cls: type[contracts.EventListener[T]],
74
92
  ) -> None:
75
93
  """Register a listener for an event."""
94
+ if not isinstance(event_cls, list):
95
+ event_cls = [event_cls]
76
96
  self._registry.register(event_cls, listener_cls)
77
97
 
78
- def _resolve_listener[T: Event](
79
- self, listener_cls: type[EventListener[T]]
80
- ) -> EventListener[T]:
98
+ def _resolve_listener[T: contracts.Event](
99
+ self, listener_cls: type[contracts.EventListener[T]]
100
+ ) -> contracts.EventListener[T]:
81
101
  """Resolve a listener from the container.
82
102
 
83
103
  Listeners are resolved from the DI container when available,
@@ -91,10 +111,10 @@ class EventDispatcher:
91
111
  return result.unwrap()
92
112
  return listener_cls()
93
113
 
94
- def _build_callback[T: Event](
114
+ def _build_callback[T: contracts.Event](
95
115
  self,
96
116
  event: T,
97
- listener_cls: type[EventListener[T]],
117
+ listener_cls: type[contracts.EventListener[T]],
98
118
  ) -> TransactionCallback:
99
119
  async def callback() -> Result[None, str]:
100
120
  listener = self._resolve_listener(listener_cls)
neva/events/event.py CHANGED
@@ -4,10 +4,11 @@ import datetime as dt
4
4
 
5
5
  import pydantic
6
6
 
7
+ from neva.events import contracts
7
8
  from neva.support import time
8
9
 
9
10
 
10
- class Event[T](pydantic.BaseModel):
11
+ class Event[T](contracts.Event):
11
12
  """Base event class."""
12
13
 
13
14
  event_id: T
@@ -1,27 +1,30 @@
1
1
  """Event/listener registry."""
2
2
 
3
- from typing import Any
3
+ import inspect
4
+ from typing import Any, TypeVar
4
5
 
5
- from neva.events.event import Event
6
- from neva.events.listener import EventListener, HandlingPolicy
6
+ from neva.events import contracts, policy
7
7
 
8
8
 
9
- class EventListenerRegistry[T: Event]:
9
+ class EventListenerRegistry[T: contracts.Event]:
10
10
  """Event listener registry for a given event."""
11
11
 
12
12
  def __init__(self) -> None:
13
- self.immediate: list[type[EventListener[T]]] = []
14
- self.deferred: list[type[EventListener[T]]] = []
13
+ self.immediate: list[type[contracts.EventListener[T]]] = []
14
+ self.deferred: list[type[contracts.EventListener[T]]] = []
15
15
 
16
- def add_listener(self, listener_cls: type[EventListener[T]]) -> None:
16
+ def add_listener(self, listener_cls: type[contracts.EventListener[T]]) -> None:
17
17
  """Add a listener to the correct category in the registry."""
18
18
  match listener_cls.policy:
19
- case HandlingPolicy.IMMEDIATE:
19
+ case policy.HandlingPolicy.IMMEDIATE:
20
20
  self.immediate.append(listener_cls)
21
- case HandlingPolicy.DEFERRED:
21
+ case policy.HandlingPolicy.DEFERRED:
22
22
  self.deferred.append(listener_cls)
23
23
 
24
24
 
25
+ T = TypeVar("T", bound=contracts.Event, covariant=True)
26
+
27
+
25
28
  class EventRegistry:
26
29
  """Event/listener registry."""
27
30
 
@@ -31,14 +34,26 @@ class EventRegistry:
31
34
  """Initialize the registry."""
32
35
  self.__listeners = {}
33
36
 
34
- def register[T: Event](
35
- self, event_cls: type[T], listener_cls: type[EventListener[T]]
37
+ def register(
38
+ self,
39
+ event_cls: list[type[T]],
40
+ listener_cls: type[contracts.EventListener[T]],
36
41
  ) -> None:
37
42
  """Register a listener for an event."""
38
- self.__listeners.setdefault(event_cls, EventListenerRegistry()).add_listener(
39
- listener_cls
40
- )
41
-
42
- def get_listeners[T: Event](self, event: T) -> EventListenerRegistry[T]:
43
+ for cls in event_cls:
44
+ self.__listeners.setdefault(cls, EventListenerRegistry()).add_listener(
45
+ listener_cls
46
+ )
47
+
48
+ def resolve_listeners(self, event: T) -> list[EventListenerRegistry[T]]:
49
+ """Return all listeners registries for an event type."""
50
+ registries = [
51
+ self.__listeners[cls]
52
+ for cls in inspect.getmro(type(event))
53
+ if cls in self.__listeners
54
+ ]
55
+ return registries
56
+
57
+ def get_listeners(self, event: T) -> EventListenerRegistry[T]:
43
58
  """Return all listeners registered for an event type."""
44
59
  return self.__listeners.get(type(event), EventListenerRegistry[T]())
neva/events/listener.py CHANGED
@@ -1,49 +1,26 @@
1
1
  """Event listener protocol."""
2
2
 
3
- import abc
4
- from enum import StrEnum
5
3
  from types import new_class
6
- from typing import Callable, Protocol
4
+ from typing import Callable, override
7
5
 
8
- from neva.events.event import Event
6
+ from neva.events import contracts
7
+ from neva.events.policy import HandlingPolicy
9
8
  from neva.support import Result
10
9
  from neva.support.strconv import snake2pascal
11
10
 
12
11
 
13
- class HandlingPolicy(StrEnum):
14
- """Event dispatch policy."""
15
-
16
- IMMEDIATE = "immediate"
17
- DEFERRED = "deferred"
18
-
19
-
20
- class EventListener[T: Event](abc.ABC):
21
- """Event listener protocol."""
12
+ class EventListener[T: contracts.Event](contracts.EventListener[T]):
13
+ """Base event listener class."""
22
14
 
23
15
  policy: HandlingPolicy = HandlingPolicy.IMMEDIATE
24
16
 
25
- @abc.abstractmethod
26
- async def handle(self, event: T) -> Result[None, str]:
27
- """Handle an event.
28
-
29
- Returns:
30
- A result indicating whether the event was handled successfully.
31
- """
32
-
33
-
34
- class EventHandler[T: Event](Protocol):
35
- """Define a valid function for event handling."""
36
-
37
- __name__: str
38
-
39
- async def __call__(self, event: T) -> Result[None, str]:
40
- """Handle an event."""
41
- ...
17
+ @override
18
+ async def handle(self, event: contracts.Event) -> Result[None, str]: ...
42
19
 
43
20
 
44
- def listener[T: Event](
21
+ def listener[T: contracts.Event](
45
22
  policy: HandlingPolicy = HandlingPolicy.IMMEDIATE,
46
- ) -> Callable[[EventHandler[T]], type[EventListener[T]]]:
23
+ ) -> Callable[[contracts.EventHandler[T]], type[EventListener[T]]]:
47
24
  """Create a listener from a function.
48
25
 
49
26
  Returns:
@@ -51,7 +28,7 @@ def listener[T: Event](
51
28
  """
52
29
 
53
30
  def decorator(
54
- func: EventHandler[T],
31
+ func: contracts.EventHandler[T],
55
32
  ) -> type[EventListener[T]]:
56
33
  async def handle(_: EventListener[T], event: T) -> Result[None, str]:
57
34
  return await func(event)
neva/events/policy.py ADDED
@@ -0,0 +1,8 @@
1
+ import enum
2
+
3
+
4
+ class HandlingPolicy(enum.StrEnum):
5
+ """Determines when a listener is invoked."""
6
+
7
+ IMMEDIATE = "immediate"
8
+ DEFERRED = "deferred"
neva/events/provider.py CHANGED
@@ -3,6 +3,8 @@
3
3
  from typing import Self, override
4
4
 
5
5
  from neva.arch.service_provider import ServiceProvider
6
+ from neva.events import contracts
7
+ from neva.events.dispatcher import EventDispatcher
6
8
  from neva.events.event_registry import EventRegistry
7
9
  from neva.support import Ok, Result
8
10
 
@@ -22,8 +24,7 @@ class EventServiceProvider(ServiceProvider):
22
24
  Returns:
23
25
  Result[Self, str]: The result of the registration.
24
26
  """
25
- from neva.events.dispatcher import EventDispatcher
26
-
27
27
  self.bind(EventRegistry)
28
28
  self.bind(EventDispatcher)
29
+ self.bind(EventDispatcher, interface=contracts.EventDispatcher)
29
30
  return Ok(self)
@@ -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.2.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
@@ -20,3 +20,8 @@ Requires-Dist: neva-fastapi>=1.0.0; extra == 'fastapi'
20
20
  Provides-Extra: testing
21
21
  Requires-Dist: pytest-asyncio>=0.25.3; extra == 'testing'
22
22
  Requires-Dist: pytest>=9.0.2; extra == 'testing'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # The Neva framework
26
+
27
+ PLACEHOLDER
@@ -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
@@ -20,13 +20,19 @@ neva/database/manager.py,sha256=VNvhVumZD2hoGKpkdXMAkT6KykE4H80WcG2DgShK5Hs,4240
20
20
  neva/database/provider.py,sha256=l2be4Ri53RtQq1-qzohy3cqzJQpTaNzqXGVhXPKUCXc,1674
21
21
  neva/database/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  neva/database/transaction.py,sha256=_0Dsao_vhCJT5YRUmrHOLb0uxvfdE-5k3n0yMPLC1o8,5167
23
- neva/events/__init__.py,sha256=xwIAXNcOASpuCY4DJpshZc1gtxQHimzwy-s7c-4QuiQ,746
24
- neva/events/dispatcher.py,sha256=mSjOvP1-new7z2QRBY3cbUzZ1Y_mlHSXMRt4NGhB8e0,3295
25
- neva/events/event.py,sha256=g3vAx-2qiR3QRM_or8G9mK5qx66A2LZiZ3n517R4lGQ,251
26
- neva/events/event_registry.py,sha256=jucYOUjCERz-ICdPiDrxYw_ySvmPJOcRzYKCgka29qY,1491
27
- neva/events/listener.py,sha256=-7RQOhVusKN8lopB3T2yfoQVlxX6GOSM5Pk1mPEMMro,1833
28
- neva/events/provider.py,sha256=HE7k915m8lQiqBC6kaGtb3ZfoxrgsuXXZmxkaaSnlmM,857
23
+ neva/events/__init__.py,sha256=Gpi5q-pNlIi-q23U2ZOsNf8Y9rB6AQtsBbbBFU0tkFc,776
24
+ neva/events/dispatcher.py,sha256=5M8s3aVzx9lIViGkigtu1kq6gFbam4OKDajuWNGuqA0,4376
25
+ neva/events/event.py,sha256=q-KyyxNkU3AN2YSaujuNPIoXQMXhGOwClTap5y8fU5I,282
26
+ neva/events/event_registry.py,sha256=IZnpR3oLyvt5K2pn9KMCBw5W4JP7Ok_zMKI2SgQoXVM,1945
27
+ neva/events/listener.py,sha256=2d5RHVKO0pU-eL_evLReTG0DIoX9tZyOcn8PWLeECZo,1435
28
+ neva/events/policy.py,sha256=I67ziob0IEVeXdkilNPpj2f48gEz2EZneR1Fz8Nlt2U,154
29
+ neva/events/provider.py,sha256=cVxADLv7VXCK6gTMJsDNRzspMOH2lrIkvMRhqVh2cK4,954
29
30
  neva/events/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ neva/events/contracts/__init__.py,sha256=t1VafYtzOZIF78V8X3K_Fg79Hw4FjSqasjLs0EQVIFA,489
32
+ neva/events/contracts/dispatcher.py,sha256=pzCv_ZLS5ju2IKVMxL5f-fFipEqQZc6zPiIVtJhKJHc,1274
33
+ neva/events/contracts/event.py,sha256=kUUECex_AlmaPJ-fXRg32eMkiqNS75CHldOr7bbpFqo,89
34
+ neva/events/contracts/handler.py,sha256=SwLuuRtXhCzGkcBBLdH3MjUAkjEr0_rhqgE6dkWVJxI,327
35
+ neva/events/contracts/listener.py,sha256=0xwPrjprkMzXu9vY1Z-EjSLFdvOUpomiE65hH16nfxA,465
30
36
  neva/obs/__init__.py,sha256=dVzgljk9Hvo44LI34RcwbDyT42_z4nSnFVmL4GLbKD0,331
31
37
  neva/obs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
38
  neva/obs/instrumentation/__init__.py,sha256=SfIAvuCs-L0kEzOxUJ4aOIkhbydCe7qBwWtGeDELVA0,36
@@ -75,16 +81,16 @@ neva/support/facade/crypt.pyi,sha256=_MV_qXDATaCs1pZTOw_-qPx_jjH_nG4-tUBOMX4nZIE
75
81
  neva/support/facade/db.py,sha256=mXMzuCKf390ICCBgzaub1ZoMqUBgOQByQYMEM3YnN_0,324
76
82
  neva/support/facade/db.pyi,sha256=UQFMgBuw0BGquMnuUNULC8Pdo7lDCVTCNkDaUmIZJhw,1911
77
83
  neva/support/facade/event.py,sha256=sRU-fxaRT59Fe-u2WTS5L9ncGkGLBndKa9gKbqwAq3M,1232
78
- neva/support/facade/event.pyi,sha256=wI1NlIg8p6j9jispsA6pI-kvNp81nwUM3ZP8O0zFaHk,558
84
+ neva/support/facade/event.pyi,sha256=AL_v8fxkvtd9KwbiWbVuUAcdZz0yzLn8xZROFa6lXLE,546
79
85
  neva/support/facade/hash.py,sha256=tGhsvfGovt-mcRXSjDKf4jt1n7ib0eDPXFvRUfVxLUc,292
80
86
  neva/support/facade/hash.pyi,sha256=jTs3E5ZF5cp76jrgH70DEog8gzfYIcIV2PrO9xskHyI,1656
81
87
  neva/support/facade/log.py,sha256=_uLoHB9tkpHkiqEJXazbaqfiKUOtv3NS71ZCZAprzOI,347
82
88
  neva/support/facade/log.pyi,sha256=Xi7gIzw9qRqmD4D3PcW06_HUtgLWEOdsHqs1B0jh1-k,1647
83
89
  neva/testing/__init__.py,sha256=vt5zxG1N84vn_YwP44jhYPWYnyb02-cha3m-1l-qoEw,207
84
- neva/testing/fakes.py,sha256=5HuuwMeAKhFSZfn9T8raQIjdgHkjFeZsFXDud0T4v7Q,2674
90
+ neva/testing/fakes.py,sha256=w2dnFaO6x14l0_si7iBNELMCxaFi8VsVOSQ6PmTlclE,2936
85
91
  neva/testing/fixtures.py,sha256=oiPa5ntUkW-SbySDvwEHXtti8NqSwI-R0CT1_ezTx_Y,1445
86
92
  neva/testing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
93
  neva/testing/test_case.py,sha256=zJBZJeKI-sv-EOaXNuSJ0V2Zp_6hdk64W4dOh0eP8RI,3290
88
- python_neva-3.2.0.dist-info/METADATA,sha256=2wZeNjt-ooHN3AIU1LE-K636R4shKM0-cIDXUGg1X2g,771
89
- python_neva-3.2.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
90
- python_neva-3.2.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,,