python-hexagonal 0.1.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.
Files changed (53) hide show
  1. hexagonal/__init__.py +2 -0
  2. hexagonal/adapters/drivens/buses/base/__init__.py +15 -0
  3. hexagonal/adapters/drivens/buses/base/command_bus.py +69 -0
  4. hexagonal/adapters/drivens/buses/base/event_bus.py +160 -0
  5. hexagonal/adapters/drivens/buses/base/infrastructure.py +38 -0
  6. hexagonal/adapters/drivens/buses/base/message_bus.py +73 -0
  7. hexagonal/adapters/drivens/buses/base/query.py +82 -0
  8. hexagonal/adapters/drivens/buses/base/utils.py +1 -0
  9. hexagonal/adapters/drivens/buses/inmemory/__init__.py +12 -0
  10. hexagonal/adapters/drivens/buses/inmemory/command_bus.py +70 -0
  11. hexagonal/adapters/drivens/buses/inmemory/event_bus.py +69 -0
  12. hexagonal/adapters/drivens/buses/inmemory/infra.py +49 -0
  13. hexagonal/adapters/drivens/mappers.py +127 -0
  14. hexagonal/adapters/drivens/repository/base/__init__.py +13 -0
  15. hexagonal/adapters/drivens/repository/base/repository.py +85 -0
  16. hexagonal/adapters/drivens/repository/base/unit_of_work.py +75 -0
  17. hexagonal/adapters/drivens/repository/sqlite/__init__.py +18 -0
  18. hexagonal/adapters/drivens/repository/sqlite/datastore.py +197 -0
  19. hexagonal/adapters/drivens/repository/sqlite/env_vars.py +2 -0
  20. hexagonal/adapters/drivens/repository/sqlite/infrastructure.py +20 -0
  21. hexagonal/adapters/drivens/repository/sqlite/outbox.py +405 -0
  22. hexagonal/adapters/drivens/repository/sqlite/repository.py +286 -0
  23. hexagonal/adapters/drivens/repository/sqlite/unit_of_work.py +25 -0
  24. hexagonal/adapters/drivers/__init__.py +5 -0
  25. hexagonal/adapters/drivers/app.py +38 -0
  26. hexagonal/application/__init__.py +29 -0
  27. hexagonal/application/api.py +61 -0
  28. hexagonal/application/app.py +76 -0
  29. hexagonal/application/bus_app.py +70 -0
  30. hexagonal/application/handlers.py +107 -0
  31. hexagonal/application/infrastructure.py +64 -0
  32. hexagonal/application/query.py +71 -0
  33. hexagonal/domain/__init__.py +77 -0
  34. hexagonal/domain/aggregate.py +159 -0
  35. hexagonal/domain/base.py +169 -0
  36. hexagonal/domain/exceptions.py +38 -0
  37. hexagonal/entrypoints/__init__.py +4 -0
  38. hexagonal/entrypoints/app.py +53 -0
  39. hexagonal/entrypoints/base.py +105 -0
  40. hexagonal/entrypoints/bus.py +68 -0
  41. hexagonal/entrypoints/sqlite.py +49 -0
  42. hexagonal/ports/__init__.py +0 -0
  43. hexagonal/ports/drivens/__init__.py +43 -0
  44. hexagonal/ports/drivens/application.py +35 -0
  45. hexagonal/ports/drivens/buses.py +148 -0
  46. hexagonal/ports/drivens/infrastructure.py +19 -0
  47. hexagonal/ports/drivens/repository.py +152 -0
  48. hexagonal/ports/drivers/__init__.py +3 -0
  49. hexagonal/ports/drivers/app.py +58 -0
  50. hexagonal/py.typed +0 -0
  51. python_hexagonal-0.1.0.dist-info/METADATA +15 -0
  52. python_hexagonal-0.1.0.dist-info/RECORD +53 -0
  53. python_hexagonal-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,35 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Generic, Iterable
3
+
4
+ from hexagonal.domain import (
5
+ CloudMessage,
6
+ QueryResults,
7
+ TEvento,
8
+ TMessagePayloadType,
9
+ TQuery,
10
+ TView,
11
+ )
12
+
13
+ from .repository import ISearchRepository, TManager
14
+
15
+
16
+ class IUseCase(ABC):
17
+ @abstractmethod
18
+ def execute(self) -> Iterable[TEvento]: ...
19
+
20
+
21
+ class IMessageHandler(ABC, Generic[TMessagePayloadType]):
22
+ @abstractmethod
23
+ def handle_message(self, message: CloudMessage[TMessagePayloadType]) -> None: ...
24
+
25
+ @abstractmethod
26
+ def get_use_case(self, message: TMessagePayloadType) -> IUseCase: ...
27
+
28
+
29
+ class IQueryHandler(ABC, Generic[TManager, TQuery, TView]):
30
+ @property
31
+ @abstractmethod
32
+ def repository(self) -> ISearchRepository[TManager, TQuery, TView]: ...
33
+
34
+ @abstractmethod
35
+ def get(self, query: TQuery) -> QueryResults[TView]: ...
@@ -0,0 +1,148 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Callable, Generic, Literal, Type, overload
3
+
4
+ from hexagonal.domain import (
5
+ CloudMessage,
6
+ Query,
7
+ QueryResult,
8
+ QueryResults,
9
+ TCommand,
10
+ TEvent,
11
+ TQuery,
12
+ TView,
13
+ )
14
+
15
+ from .application import IMessageHandler, IQueryHandler
16
+ from .infrastructure import IBaseInfrastructure
17
+ from .repository import IInboxRepository, IOutboxRepository, TManager
18
+
19
+
20
+ class IBaseMessageBus(IBaseInfrastructure, ABC, Generic[TManager]):
21
+ @property
22
+ @abstractmethod
23
+ def inbox_repository(self) -> IInboxRepository[TManager]: ...
24
+
25
+ @property
26
+ @abstractmethod
27
+ def outbox_repository(self) -> IOutboxRepository[TManager]: ...
28
+
29
+ @abstractmethod
30
+ def publish_from_outbox(self, limit: int | None = None):
31
+ """Publicar mensajes desde la outbox., hasta el límite especificado."""
32
+ ...
33
+
34
+ @abstractmethod
35
+ def consume(self, limit: int | None = None):
36
+ """Consumir mensajes desde la inbox, hasta el límite especificado."""
37
+ ...
38
+
39
+
40
+ class ICommandBus(IBaseMessageBus[TManager], ABC):
41
+ @abstractmethod
42
+ def register_handler(
43
+ self, command_type: Type[TCommand], handler: IMessageHandler[TCommand]
44
+ ) -> None:
45
+ """Registrar un manejador para un tipo de comando."""
46
+ ...
47
+
48
+ @abstractmethod
49
+ def unregister_handler(self, command_type: Type[TCommand]) -> None:
50
+ """Desregistrar el manejador para un tipo de comando."""
51
+ ...
52
+
53
+ @abstractmethod
54
+ def dispatch(
55
+ self,
56
+ command: TCommand | CloudMessage[TCommand],
57
+ *,
58
+ to_outbox: bool = False,
59
+ ) -> None:
60
+ """Despachar un comando para su procesamiento."""
61
+ ...
62
+
63
+ @abstractmethod
64
+ def process_command(self, command: CloudMessage[TCommand]) -> None:
65
+ """Procesar un comando recibido."""
66
+ ...
67
+
68
+
69
+ class IEventBus(IBaseMessageBus[TManager], ABC):
70
+ @abstractmethod
71
+ def subscribe(self, event_type: Type[TEvent], handler: IMessageHandler[TEvent]):
72
+ """Suscribir un manejador a un tipo de evento."""
73
+ ...
74
+
75
+ @abstractmethod
76
+ def unsubscribe(
77
+ self,
78
+ event_type: Type[TEvent],
79
+ *handlers: IMessageHandler[TEvent],
80
+ ): ...
81
+
82
+ @abstractmethod
83
+ def publish(self, *events: CloudMessage[TEvent]) -> None:
84
+ """Publicar un evento a todos sus suscriptores."""
85
+ ...
86
+
87
+ @abstractmethod
88
+ def process_events(self, *events: CloudMessage[TEvent]) -> None: ...
89
+
90
+ # wait for
91
+ @overload
92
+ def wait_for_publish(
93
+ self, event_type: Type[TEvent], handler: Callable[[TEvent], None]
94
+ ) -> None: ...
95
+ @overload
96
+ def wait_for_publish(
97
+ self, event_type: Type[TEvent]
98
+ ) -> Callable[[Callable[[TEvent], None]], None]: ...
99
+
100
+ @abstractmethod
101
+ def wait_for_publish(
102
+ self, event_type: Type[TEvent], handler: Callable[[TEvent], None] | None = None
103
+ ) -> Callable[[Callable[[TEvent], None]], None] | None: ...
104
+
105
+
106
+ class IQueryBus(IBaseInfrastructure, Generic[TManager]):
107
+ @abstractmethod
108
+ def register_handler(
109
+ self,
110
+ query_type: Type[TQuery],
111
+ handler: IQueryHandler[TManager, TQuery, TView],
112
+ ): ...
113
+
114
+ @abstractmethod
115
+ def unregister_handler(self, query_type: Type[Query[TView]]): ...
116
+
117
+ @overload
118
+ def get(self, query: Query[TView], *, one: Literal[True]) -> QueryResult[TView]: ...
119
+
120
+ @overload
121
+ def get(
122
+ self,
123
+ query: Query[TView],
124
+ *,
125
+ one: Literal[False] = False,
126
+ ) -> QueryResults[TView]: ...
127
+
128
+ @abstractmethod
129
+ def get(
130
+ self,
131
+ query: Query[TView],
132
+ *,
133
+ one: bool = False,
134
+ ) -> QueryResult[TView] | QueryResults[TView]: ...
135
+
136
+
137
+ class IBusInfrastructure(IBaseInfrastructure, Generic[TManager]):
138
+ @property
139
+ @abstractmethod
140
+ def command_bus(self) -> ICommandBus[TManager]: ...
141
+
142
+ @property
143
+ @abstractmethod
144
+ def event_bus(self) -> IEventBus[TManager]: ...
145
+
146
+ @property
147
+ @abstractmethod
148
+ def query_bus(self) -> IQueryBus[TManager]: ...
@@ -0,0 +1,19 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Mapping
3
+
4
+ from hexagonal.domain import InfrastructureNotInitialized
5
+
6
+
7
+ class IBaseInfrastructure(ABC):
8
+ @property
9
+ @abstractmethod
10
+ def initialized(self) -> bool: ...
11
+
12
+ @abstractmethod
13
+ def initialize(self, env: Mapping[str, str]) -> None: ...
14
+
15
+ def verify(self):
16
+ if not self.initialized:
17
+ raise InfrastructureNotInitialized(
18
+ f"{self.__class__.__name__} is not initialized"
19
+ )
@@ -0,0 +1,152 @@
1
+ from abc import ABC, abstractmethod
2
+ from contextlib import contextmanager
3
+ from typing import Any, Generic, List, Self, TypeVar
4
+ from uuid import UUID
5
+
6
+ from hexagonal.domain import (
7
+ AggregateRoot,
8
+ CloudMessage,
9
+ TIdEntity,
10
+ TQuery,
11
+ TView,
12
+ )
13
+
14
+ from .infrastructure import IBaseInfrastructure
15
+
16
+ TAggregate = TypeVar("TAggregate", bound=AggregateRoot[Any, Any])
17
+
18
+
19
+ class IConnectionManager(IBaseInfrastructure, ABC):
20
+ @contextmanager
21
+ @abstractmethod
22
+ def start_connection(self) -> Any: ...
23
+
24
+
25
+ TManager = TypeVar("TManager", bound=IConnectionManager)
26
+
27
+
28
+ class IBaseRepository(IBaseInfrastructure, Generic[TManager]):
29
+ @property
30
+ @abstractmethod
31
+ def connection_manager(self) -> TManager: ...
32
+
33
+ @abstractmethod
34
+ def attach_to_unit_of_work(self, uow: "IUnitOfWork[TManager]") -> None: ...
35
+
36
+ @abstractmethod
37
+ def detach_from_unit_of_work(self) -> None: ...
38
+
39
+
40
+ class IUnitOfWork(IBaseInfrastructure, ABC, Generic[TManager]):
41
+ @property
42
+ @abstractmethod
43
+ def connection_manager(self) -> TManager: ...
44
+
45
+ @abstractmethod
46
+ def commit(self) -> None: ...
47
+
48
+ @abstractmethod
49
+ def rollback(self) -> None: ...
50
+
51
+ @abstractmethod
52
+ def attach_repo(self, repo: IBaseRepository[TManager]) -> None: ...
53
+
54
+ @abstractmethod
55
+ def detach_repo(self, repo: IBaseRepository[TManager]) -> None: ...
56
+
57
+ def __enter__(self) -> Self:
58
+ return self
59
+
60
+ def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore
61
+ if exc_type is None:
62
+ self.commit()
63
+ else:
64
+ self.rollback()
65
+
66
+
67
+ class IAggregateRepository(
68
+ IBaseRepository[TManager],
69
+ Generic[TManager, TAggregate, TIdEntity],
70
+ ):
71
+ @abstractmethod
72
+ def save(self, aggregate: TAggregate) -> None:
73
+ """Persistir el agregado en el almacenamiento."""
74
+ ...
75
+
76
+ @abstractmethod
77
+ def get(self, id: TIdEntity) -> TAggregate:
78
+ """Recuperar el agregado por su ID."""
79
+ ...
80
+
81
+ @abstractmethod
82
+ def delete(self, id: TIdEntity) -> TAggregate:
83
+ """Eliminar el agregado por su ID."""
84
+ ...
85
+
86
+
87
+ class IOutboxRepository(IBaseRepository[TManager]):
88
+ """Puerto para manejar eventos pendientes de publicar (write-side)."""
89
+
90
+ @abstractmethod
91
+ def save(self, *message: CloudMessage[Any]) -> None:
92
+ """Guardar evento en la tabla Outbox en la misma transacción del agregado."""
93
+ ...
94
+
95
+ @abstractmethod
96
+ def fetch_pending(self, limit: int | None = None) -> list[CloudMessage[Any]]:
97
+ """Recuperar eventos no publicados aún."""
98
+ ...
99
+
100
+ @abstractmethod
101
+ def mark_as_published(self, *message_ids: UUID) -> None:
102
+ """Marcar un evento como publicado correctamente."""
103
+ ...
104
+
105
+ @abstractmethod
106
+ def mark_as_failed(self, *message_ids: UUID, error: str) -> None:
107
+ """Incrementar intentos o marcar el evento como fallido."""
108
+ ...
109
+
110
+
111
+ class IInboxRepository(IBaseRepository[TManager]):
112
+ """Puerto para procesar mensajes de entrada de forma idempotente."""
113
+
114
+ @abstractmethod
115
+ def register_message(
116
+ self,
117
+ message: CloudMessage[Any],
118
+ handler: str,
119
+ max_retries: int = 3,
120
+ ) -> bool:
121
+ """
122
+ Intenta registrar un mensaje.
123
+ Retorna False si ya existe (duplicado).
124
+ """
125
+ ...
126
+
127
+ @abstractmethod
128
+ def mark_as_processed(self, message_id: UUID, handler: str) -> None:
129
+ """Marcar el mensaje como procesado exitosamente."""
130
+ ...
131
+
132
+ @abstractmethod
133
+ def mark_as_failed(self, message_id: UUID, handler: str, error: str) -> None:
134
+ """Marcar el mensaje como fallido."""
135
+ ...
136
+
137
+
138
+ class ISearchRepository(IBaseRepository[TManager], Generic[TManager, TQuery, TView]):
139
+ @abstractmethod
140
+ def search(self, query: TQuery) -> List[TView]:
141
+ """Buscar objetos de valor según el query proporcionado."""
142
+ ...
143
+
144
+
145
+ class IPairInboxOutbox(IBaseInfrastructure, Generic[TManager]):
146
+ @property
147
+ @abstractmethod
148
+ def inbox(self) -> IInboxRepository[TManager]: ...
149
+
150
+ @property
151
+ @abstractmethod
152
+ def outbox(self) -> IOutboxRepository[TManager]: ...
@@ -0,0 +1,3 @@
1
+ from .app import IBaseApplication, IBusApp
2
+
3
+ __all__ = ["IBaseApplication", "IBusApp"]
@@ -0,0 +1,58 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Generic
3
+
4
+ from hexagonal.domain import CloudMessage, TCommand, TEvent
5
+ from hexagonal.ports.drivens import (
6
+ IBusInfrastructure,
7
+ ICommandBus,
8
+ IEventBus,
9
+ IQueryBus,
10
+ IUnitOfWork,
11
+ TManager,
12
+ )
13
+
14
+
15
+ class IBusApp(ABC, Generic[TManager]):
16
+ @property
17
+ @abstractmethod
18
+ def uow(self) -> IUnitOfWork[TManager]: ...
19
+
20
+ @abstractmethod
21
+ def bootstrap(
22
+ self,
23
+ command_bus: ICommandBus[TManager],
24
+ query_bus: IQueryBus[TManager],
25
+ event_bus: IEventBus[TManager],
26
+ ) -> None: ...
27
+
28
+
29
+ class IBaseApplication(ABC, Generic[TManager]):
30
+ @property
31
+ @abstractmethod
32
+ def bus_app(self) -> IBusApp[TManager]: ...
33
+
34
+ @property
35
+ @abstractmethod
36
+ def bus_infrastructure(self) -> IBusInfrastructure[TManager]: ...
37
+
38
+ @property
39
+ @abstractmethod
40
+ def command_bus(self) -> ICommandBus[TManager]: ...
41
+
42
+ @property
43
+ @abstractmethod
44
+ def query_bus(self) -> IQueryBus[TManager]: ...
45
+
46
+ @property
47
+ @abstractmethod
48
+ def event_bus(self) -> IEventBus[TManager]: ...
49
+
50
+ @abstractmethod
51
+ def bootstrap(self, bus_app: IBusApp[TManager]) -> None: ...
52
+
53
+ @abstractmethod
54
+ def dispatch_and_wait_events(
55
+ self,
56
+ command: CloudMessage[TCommand],
57
+ *event_types: type[TEvent],
58
+ ) -> dict[type[TEvent], TEvent | None]: ...
hexagonal/py.typed ADDED
File without changes
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.3
2
+ Name: python-hexagonal
3
+ Version: 0.1.0
4
+ Summary: Framework to build hexagonal architecture applications in Python.
5
+ Author: jose-matos-9281
6
+ Author-email: jose-matos-9281 <58991817+jose-matos-9281@users.noreply.github.com>
7
+ Requires-Dist: eventsourcing>=9.4.6
8
+ Requires-Dist: orjson>=3.11.5
9
+ Requires-Dist: pydantic>=2.12.5
10
+ Requires-Dist: uuid6>=2025.0.1
11
+ Requires-Python: >=3.12
12
+ Description-Content-Type: text/markdown
13
+
14
+ # python-hexagonal
15
+ Framework of Ports and adapters Architecture, applying concepts of DDD
@@ -0,0 +1,53 @@
1
+ hexagonal/__init__.py,sha256=4GlVYmzCh2BmPst6WpxxqraLcfXmlbyrGcNFyi28dng,62
2
+ hexagonal/adapters/drivens/buses/base/__init__.py,sha256=3RM8lIIh4425-Ixnu_v667sdM6iAwDqds3GNUAANp5M,380
3
+ hexagonal/adapters/drivens/buses/base/command_bus.py,sha256=RhUcObspthpq4NUEooFXIV0p81FS5KsnJ3G3M0MGjFw,2226
4
+ hexagonal/adapters/drivens/buses/base/event_bus.py,sha256=jIDuipRaO7MT7oE0M3e8ALSmqe-YnFAVgTqqbHwUXqg,5743
5
+ hexagonal/adapters/drivens/buses/base/infrastructure.py,sha256=4x36U57kP4yk7YKGGmkQIB10JPmTFSgnaMx5OUDmeWU,965
6
+ hexagonal/adapters/drivens/buses/base/message_bus.py,sha256=aR90tALUSqV_vVTFBG0KGRXJnbi7I4OQ-29cCkTDuUo,2591
7
+ hexagonal/adapters/drivens/buses/base/query.py,sha256=eElI9zbfdQ7iSaSrR2sykdyKW1wBoLj86ngZzGHb40w,2424
8
+ hexagonal/adapters/drivens/buses/base/utils.py,sha256=w1qdMpddZph2sl-S2ir_ym23Rkq9fC9MEBvJ9PB3QpU,48
9
+ hexagonal/adapters/drivens/buses/inmemory/__init__.py,sha256=ySzpKqMKT7zc77M7AXOlGU9y8l0ZkHQ0We4wkxjuyzM,405
10
+ hexagonal/adapters/drivens/buses/inmemory/command_bus.py,sha256=gMyk-VNSDk_gk5ihP3cUQcfNIgqmLD1Nt-yzuTB9Uy4,2271
11
+ hexagonal/adapters/drivens/buses/inmemory/event_bus.py,sha256=xe-I4nBs2BE-vLVawRW3lXhBlW54X-XUjL9kRnX-hE0,2288
12
+ hexagonal/adapters/drivens/buses/inmemory/infra.py,sha256=Gkjx8ZUlg5jWbSXgg64-Hgrtegbmi-mcoI0T9oEkq0U,1336
13
+ hexagonal/adapters/drivens/mappers.py,sha256=15n1SGJ0RCGtsxPrOyNcnD2qpA-YYFCUWeA3Y1_4ric,4810
14
+ hexagonal/adapters/drivens/repository/base/__init__.py,sha256=MZoFzptMLTIMRxjxswbj3T3vDepu4KW07fwrKRYaKDU,270
15
+ hexagonal/adapters/drivens/repository/base/repository.py,sha256=_SC_mR65CX39boAeUnDCFAaUj1duYPtsi2CrpmpSOGM,2728
16
+ hexagonal/adapters/drivens/repository/base/unit_of_work.py,sha256=xRn_kvbv_FYo6FDNvSDYYUuIFYeoUo7AMapyYBAzbjo,2496
17
+ hexagonal/adapters/drivens/repository/sqlite/__init__.py,sha256=0Uzaw2atFFfjQ1ppgtKQD39YwmiEl-O9nqUI30Bww20,598
18
+ hexagonal/adapters/drivens/repository/sqlite/datastore.py,sha256=N0r8v4slYFtIXGMBPuf1_AvqkAaayCXYQfzdDDMcrT4,7028
19
+ hexagonal/adapters/drivens/repository/sqlite/env_vars.py,sha256=EXRbG3NlTQg3rnUUszW0IDGuQLi_Grbd2uXIX3V4mJA,88
20
+ hexagonal/adapters/drivens/repository/sqlite/infrastructure.py,sha256=hQmogShv99cUF4PSgZlkn0BcCEMydWt0hxDREEfG5u8,736
21
+ hexagonal/adapters/drivens/repository/sqlite/outbox.py,sha256=FdEllWC2-tMHJ3-gboHQCH7iDYtlVWeYXN6KKUC3gJc,14125
22
+ hexagonal/adapters/drivens/repository/sqlite/repository.py,sha256=IRs9Mm_rBD-pE_D7OWlvvJgxW5WrvAHhdAz3jZgJA_k,10271
23
+ hexagonal/adapters/drivens/repository/sqlite/unit_of_work.py,sha256=2yoP7U_WTgK6mzMtaAEcoV2hmgNNgNjT3vpxzWT8c0A,907
24
+ hexagonal/adapters/drivers/__init__.py,sha256=tHcyqkut5K7LvlDT1QVJ3N7Z1UrmfqNYuKjlrxitoAc,87
25
+ hexagonal/adapters/drivers/app.py,sha256=3MuDI2cl1TauoBk4qVDAOWik4dGiekUYkHPZbCCCPeE,1124
26
+ hexagonal/application/__init__.py,sha256=IvGbZfRqI3hUA8SXn_YhSgwcyrQg9RFrgi3XtAWFV9Q,752
27
+ hexagonal/application/api.py,sha256=YQVRAENQVtMOSPZgjWPNUaEgennPtnPN3A2XjBEdbd4,2152
28
+ hexagonal/application/app.py,sha256=OBsJ5dPp9hdO-aKDKhdMI-PMP5UHTyadA0xAcYzq-EQ,2404
29
+ hexagonal/application/bus_app.py,sha256=Ubwy5HKDOi1vJWT0LsEm0y1vM53ROZLbHGEw72S7eYw,1995
30
+ hexagonal/application/handlers.py,sha256=sAirS7Fa9o5UAPamfLz0gU1ZpyEaeqCyB6qdqlweGfU,3011
31
+ hexagonal/application/infrastructure.py,sha256=KGKnVUkFCxZvlv1mySaunzFqXX9Kvh_XP-pfueU4jc8,2047
32
+ hexagonal/application/query.py,sha256=Td7BvPUl_rvAL2Rnf2HS8hjtH1EpfIU9BUSYvTKmGJw,2150
33
+ hexagonal/domain/__init__.py,sha256=iVAzcLFU1A2KAeI0o-RUtp4OJdF4y4NoTmjgdtD1Bh8,1422
34
+ hexagonal/domain/aggregate.py,sha256=byVnwM9_JuRNYp7FHLWMOqryAQn0H9OvyEEtsDZPmAw,4763
35
+ hexagonal/domain/base.py,sha256=aLwbE1aQp3Cf6NO-fihuK7gS2Z-KO5jtfE7ZKAerBbs,4495
36
+ hexagonal/domain/exceptions.py,sha256=y1fX320cNoswgJg_W1rGowHM8XY1wg5f_kkTEWVcjOk,1275
37
+ hexagonal/entrypoints/__init__.py,sha256=Kh83vld6l4GXJEUN-LHegT2eYlq2pDvGhtO8jTCFq7s,139
38
+ hexagonal/entrypoints/app.py,sha256=JBxj_IAPrNevS8HY6zhUR7hiGy1P22nSShorYwEXbJM,2013
39
+ hexagonal/entrypoints/base.py,sha256=8r_s-TeD2Awzyctvx4K3UHZU5t5A2WZKmlEi0gOrjF0,3215
40
+ hexagonal/entrypoints/bus.py,sha256=pilgSDBxwG_hL_3MaqzrHTshO_TfNkU8OHtcBmdiPYk,2044
41
+ hexagonal/entrypoints/sqlite.py,sha256=akCp1bglcQSz-Xz2c3usPebCKD05zTzRbTSF9TMaX5s,1738
42
+ hexagonal/ports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ hexagonal/ports/drivens/__init__.py,sha256=wERGIFEpeZScrw73Co36QwjK_icnuvKbZ7Bj_whQyQ0,897
44
+ hexagonal/ports/drivens/application.py,sha256=9vxvR4yhwOklrtFlUZin8nmzj2xqc1Hvg5xForPBYKw,863
45
+ hexagonal/ports/drivens/buses.py,sha256=tCEFbzA1-R8UMum2Y2hyeGd2W6jYz4bR8PJniktdZhY,4024
46
+ hexagonal/ports/drivens/infrastructure.py,sha256=pMr9oF9mUta-hY6vv2DieQpANYCrPpwgwDQB1QMaxpc,494
47
+ hexagonal/ports/drivens/repository.py,sha256=ijewN8988N0FTEoVtWforyeBc0ejLzBX6mDPQjJ_XE8,4096
48
+ hexagonal/ports/drivers/__init__.py,sha256=cADln99MHC7KxZzLNc63q_VS53VSpAynvG4NUr2zDwY,86
49
+ hexagonal/ports/drivers/app.py,sha256=QJlNYGlpNcRPWlsNVTYXIwRNi1ggRdkqvo6ElFXAsUw,1368
50
+ hexagonal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ python_hexagonal-0.1.0.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
52
+ python_hexagonal-0.1.0.dist-info/METADATA,sha256=OF15AlgCDDholY0Dkj_UqE27KQutCVm5djK-eU-HA14,525
53
+ python_hexagonal-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.18
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any