python-event-sourcery 0.5.1a2__tar.gz → 0.5.1a3__tar.gz

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.
Files changed (65) hide show
  1. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/PKG-INFO +1 -1
  2. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/subscription/in_transaction.py +41 -22
  3. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/event_sourcing/aggregate.py +3 -2
  4. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/pyproject.toml +1 -1
  5. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/LICENSE +0 -0
  6. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/README.md +0 -0
  7. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/__init__.py +0 -0
  8. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/__init__.py +0 -0
  9. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/backend.py +0 -0
  10. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/event/__init__.py +0 -0
  11. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/event/dto.py +0 -0
  12. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/event/encryption.py +0 -0
  13. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/event/registry.py +0 -0
  14. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/event/serde.py +0 -0
  15. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/event_store.py +0 -0
  16. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/in_memory.py +0 -0
  17. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/outbox.py +0 -0
  18. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/stream_id.py +0 -0
  19. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/subscription/__init__.py +0 -0
  20. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/subscription/builder.py +0 -0
  21. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/subscription/interfaces.py +0 -0
  22. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/tenant_id.py +0 -0
  23. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/_event_store/versioning.py +0 -0
  24. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/backend.py +0 -0
  25. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/encryption.py +0 -0
  26. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/event.py +0 -0
  27. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/event_sourcing/__init__.py +0 -0
  28. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/event_sourcing/repository.py +0 -0
  29. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/exceptions.py +0 -0
  30. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/in_transaction.py +0 -0
  31. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/interfaces.py +0 -0
  32. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/outbox.py +0 -0
  33. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/py.typed +0 -0
  34. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/read_model/__init__.py +0 -0
  35. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/read_model/cursors_dao.py +0 -0
  36. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/read_model/projector.py +0 -0
  37. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery/subscription.py +0 -0
  38. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/__init__.py +0 -0
  39. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/dto.py +0 -0
  40. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/event_store.py +0 -0
  41. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/migrations/0001_initial.py +0 -0
  42. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/migrations/__init__.py +0 -0
  43. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/models.py +0 -0
  44. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/outbox.py +0 -0
  45. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/py.typed +0 -0
  46. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_django/subscription.py +0 -0
  47. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_kurrentdb/__init__.py +0 -0
  48. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_kurrentdb/dto.py +0 -0
  49. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_kurrentdb/event_store.py +0 -0
  50. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_kurrentdb/outbox.py +0 -0
  51. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_kurrentdb/py.typed +0 -0
  52. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_kurrentdb/stream.py +0 -0
  53. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_kurrentdb/subscription.py +0 -0
  54. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/__init__.py +0 -0
  55. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/cursors_dao.py +0 -0
  56. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/dto.py +0 -0
  57. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/event_store.py +0 -0
  58. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/guid.py +0 -0
  59. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/jsonb.py +0 -0
  60. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/models/__init__.py +0 -0
  61. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/models/base.py +0 -0
  62. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/models/default.py +0 -0
  63. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/outbox.py +0 -0
  64. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/py.typed +0 -0
  65. {python_event_sourcery-0.5.1a2 → python_event_sourcery-0.5.1a3}/event_sourcery_sqlalchemy/subscription.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: python-event-sourcery
3
- Version: 0.5.1a2
3
+ Version: 0.5.1a3
4
4
  Summary: A library for event-based systems in Python.
5
5
  License: MIT
6
6
  Author: Sebastian Buczyński
@@ -9,6 +9,7 @@ Used for in-transaction (in-process) event processing.
9
9
 
10
10
  __all__ = ["Dispatcher", "Listener", "Listeners"]
11
11
 
12
+ from collections import defaultdict
12
13
  from collections.abc import Iterator
13
14
  from itertools import chain
14
15
  from typing import Protocol
@@ -20,7 +21,7 @@ from event_sourcery._event_store.event.dto import (
20
21
  WrappedEvent,
21
22
  )
22
23
  from event_sourcery._event_store.event.serde import Serde
23
- from event_sourcery._event_store.stream_id import StreamId
24
+ from event_sourcery._event_store.stream_id import StreamCategory, StreamId
24
25
  from event_sourcery._event_store.tenant_id import TenantId
25
26
 
26
27
 
@@ -58,9 +59,13 @@ class Listeners:
58
59
  """
59
60
 
60
61
  def __init__(self) -> None:
61
- self._listeners: dict[type[Event], set[Listener]] = {}
62
+ self._to_event_types: dict[type[Event], set[Listener]] = {}
63
+ self._to_categories: dict[StreamCategory, set[Listener]] = defaultdict(set)
62
64
 
63
- def __getitem__(self, event_type: type[Event]) -> Iterator[Listener]:
65
+ def __getitem__(
66
+ self,
67
+ subscribed_to: type[Event] | StreamCategory,
68
+ ) -> Iterator[Listener]:
64
69
  """
65
70
  Returns an iterator over all listeners registered for the given event type or
66
71
  its base types.
@@ -71,27 +76,35 @@ class Listeners:
71
76
  Returns:
72
77
  Iterator[Listener]: An iterator over matching listeners.
73
78
  """
74
- return chain(
75
- *(
76
- listeners
77
- for registered_to, listeners in self._listeners.items()
78
- if issubclass(event_type, registered_to)
79
- )
80
- )
81
-
82
- def register(self, listener: Listener, to: type[Event]) -> None:
79
+ match subscribed_to:
80
+ case StreamCategory() as category:
81
+ return chain(self._to_categories[category])
82
+ case _ as event_type:
83
+ return chain(
84
+ *(
85
+ listeners
86
+ for registered_to, listeners in self._to_event_types.items()
87
+ if issubclass(event_type, registered_to)
88
+ )
89
+ )
90
+
91
+ def register(self, listener: Listener, to: type[Event] | StreamCategory) -> None:
83
92
  """
84
93
  Registers a listener for a specific event type.
85
94
 
86
95
  Args:
87
96
  listener (Listener): The listener to register.
88
- to (type[Event]): The event type to register the listener for.
97
+ to (type[Event] | StreamCategory): The event type or stream category.
89
98
  """
90
- if to not in self._listeners:
91
- self._listeners[to] = set()
92
- self._listeners[to].add(listener)
93
-
94
- def remove(self, listener: Listener, to: type[Event]) -> None:
99
+ match to:
100
+ case StreamCategory() as category:
101
+ self._to_categories[category].add(listener)
102
+ case _ as event_type:
103
+ if event_type not in self._to_event_types:
104
+ self._to_event_types[event_type] = set()
105
+ self._to_event_types[event_type].add(listener)
106
+
107
+ def remove(self, listener: Listener, to: type[Event] | StreamCategory) -> None:
95
108
  """
96
109
  Removes a listener from a specific event type.
97
110
 
@@ -99,8 +112,12 @@ class Listeners:
99
112
  listener (Listener): The listener to remove.
100
113
  to (type[Event]): The event type to remove the listener from.
101
114
  """
102
- if to in self._listeners and listener in self._listeners[to]:
103
- self._listeners[to].remove(listener)
115
+ match to:
116
+ case StreamCategory() as category:
117
+ self._to_categories[category].remove(listener)
118
+ case _:
119
+ if to in self._to_event_types and listener in self._to_event_types[to]:
120
+ self._to_event_types[to].remove(listener)
104
121
 
105
122
 
106
123
  class Dispatcher:
@@ -122,8 +139,10 @@ class Dispatcher:
122
139
  """
123
140
  for raw in raws:
124
141
  record = self._serde.deserialize_record(raw)
125
- event_type = record.wrapped_event.event.__class__
126
- for listener in self._listeners[event_type]:
142
+ event = record.wrapped_event.event.__class__
143
+ category = record.stream_id.category or ""
144
+ listeners = set(self._listeners[event]) | set(self._listeners[category])
145
+ for listener in listeners:
127
146
  listener(
128
147
  record.wrapped_event,
129
148
  record.stream_id,
@@ -2,6 +2,7 @@ from collections.abc import Iterator
2
2
  from contextlib import contextmanager
3
3
  from typing import ClassVar
4
4
 
5
+ from event_sourcery import StreamCategory
5
6
  from event_sourcery.event import Event
6
7
 
7
8
 
@@ -17,11 +18,11 @@ class Aggregate:
17
18
  for applying events in a consistent way.
18
19
 
19
20
  Attributes:
20
- category (ClassVar[str]): StreamCategory for the aggregate type (group streams).
21
+ category (ClassVar[StreamCategory]): StreamCategory for the aggregate type (group streams).
21
22
  _changes (list[Event]): List of yet not persisted events.
22
23
  """
23
24
 
24
- category: ClassVar[str]
25
+ category: ClassVar[StreamCategory]
25
26
  _changes: list[Event]
26
27
 
27
28
  @contextmanager
@@ -3,7 +3,7 @@ name = "python-event-sourcery"
3
3
  requires-python = ">=3.10"
4
4
 
5
5
  [tool.poetry]
6
- version = "0.5.1a2"
6
+ version = "0.5.1a3"
7
7
  description = "A library for event-based systems in Python."
8
8
  readme = "README.md"
9
9
  authors = [