omnibase_infra 0.2.3__py3-none-any.whl → 0.2.5__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.
@@ -0,0 +1,294 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 OmniNode Team
3
+ """Registry for Intent Storage Node Dependencies.
4
+
5
+ This module provides RegistryInfraIntentStorage, which registers
6
+ dependencies for the NodeIntentStorageEffect node.
7
+
8
+ Architecture:
9
+ The registry follows ONEX container-based dependency injection:
10
+ - Registers HandlerIntent with ModelONEXContainer
11
+ - Supports initialization with pre-configured HandlerGraph
12
+ - Enables runtime handler resolution via container
13
+
14
+ Registration is typically called during application bootstrap.
15
+
16
+ Related:
17
+ - NodeIntentStorageEffect: Effect node that uses these dependencies
18
+ - HandlerIntent: Intent handler for graph operations
19
+ - HandlerGraph: Underlying Memgraph graph handler
20
+ - ModelONEXContainer: ONEX dependency injection container
21
+
22
+ Testing:
23
+ This module uses module-level state (``_HANDLER_STORAGE``, ``_PROTOCOL_METADATA``)
24
+ for handler storage. Tests MUST call ``RegistryInfraIntentStorage.clear()`` in
25
+ setup and teardown fixtures to prevent test pollution between test cases.
26
+
27
+ Failure to clear state can cause:
28
+ - Tests passing in isolation but failing when run together
29
+ - Handlers from previous tests leaking into subsequent tests
30
+ - Flaky test behavior that is difficult to debug
31
+
32
+ Recommended fixture pattern:
33
+
34
+ .. code-block:: python
35
+
36
+ @pytest.fixture(autouse=True)
37
+ def clear_registry():
38
+ RegistryInfraIntentStorage.clear()
39
+ yield
40
+ RegistryInfraIntentStorage.clear()
41
+
42
+ Note:
43
+ This registry uses a module-level dict for handler storage because the
44
+ ServiceRegistry in omnibase_core v1.0 doesn't support dict-style access
45
+ or string-keyed multi-handler routing. The handlers are still validated
46
+ but stored separately.
47
+ """
48
+
49
+ from __future__ import annotations
50
+
51
+ import logging
52
+ from typing import TYPE_CHECKING, cast
53
+
54
+ logger = logging.getLogger(__name__)
55
+
56
+ if TYPE_CHECKING:
57
+ from omnibase_core.models.container.model_onex_container import ModelONEXContainer
58
+ from omnibase_infra.handlers.handler_intent import HandlerIntent
59
+
60
+ __all__ = ["RegistryInfraIntentStorage"]
61
+
62
+ # TODO(ServiceRegistry-v2): Migrate to container.service_registry once v2.0
63
+ # supports dict-style access for multi-handler routing. Current module-level
64
+ # storage is a workaround for v1.0 limitations. See docstring Note section.
65
+ #
66
+ # Module-level storage for handlers and metadata
67
+ # ServiceRegistry in v1.0 doesn't support dict-style access needed for
68
+ # handler routing
69
+ _HANDLER_STORAGE: dict[str, object] = {}
70
+ _PROTOCOL_METADATA: dict[str, dict[str, object]] = {}
71
+
72
+
73
+ class RegistryInfraIntentStorage:
74
+ """Registry for intent storage node dependencies.
75
+
76
+ Registers handler implementations with the ONEX container.
77
+ Supports the HandlerIntent which wraps HandlerGraph for Memgraph operations.
78
+
79
+ Usage:
80
+ .. code-block:: python
81
+
82
+ from omnibase_core.models.container import ModelONEXContainer
83
+ from omnibase_infra.nodes.node_intent_storage_effect.registry import (
84
+ RegistryInfraIntentStorage,
85
+ )
86
+
87
+ # Create container
88
+ container = ModelONEXContainer()
89
+
90
+ # Register dependencies
91
+ RegistryInfraIntentStorage.register(container)
92
+
93
+ # Register the handler (must have graph_handler configured)
94
+ RegistryInfraIntentStorage.register_handler(
95
+ container,
96
+ handler=intent_handler,
97
+ )
98
+
99
+ Note:
100
+ This registry does NOT instantiate handlers. Handlers must be
101
+ created externally with their specific dependencies (HandlerGraph)
102
+ and then registered via register_handler().
103
+ """
104
+
105
+ # Handler key for container registration
106
+ HANDLER_KEY = "handler_intent"
107
+
108
+ # Default handler type
109
+ DEFAULT_HANDLER_TYPE = "memgraph"
110
+
111
+ @staticmethod
112
+ def _is_registered(handler_key: str) -> bool:
113
+ """Check if a handler is already registered for the given key.
114
+
115
+ This is a private helper method used to detect re-registration
116
+ attempts, which may indicate container lifecycle issues or
117
+ missing clear() calls in tests.
118
+
119
+ Args:
120
+ handler_key: The handler key to check (e.g., "handler_intent.memgraph").
121
+
122
+ Returns:
123
+ True if a handler is already registered for this key, False otherwise.
124
+ """
125
+ return handler_key in _HANDLER_STORAGE
126
+
127
+ @staticmethod
128
+ def register(_container: ModelONEXContainer) -> None:
129
+ """Register intent storage dependencies with the container.
130
+
131
+ Registers the handler key for later handler binding. This method
132
+ sets up the infrastructure but does not bind a specific handler.
133
+
134
+ Args:
135
+ _container: ONEX dependency injection container. Currently unused
136
+ because ServiceRegistry v1.0 doesn't support dict-style access
137
+ for multi-handler routing. The parameter is retained for API
138
+ consistency with other registry methods and future migration.
139
+
140
+ Example:
141
+ >>> from omnibase_core.models.container import ModelONEXContainer
142
+ >>> container = ModelONEXContainer()
143
+ >>> RegistryInfraIntentStorage.register(container)
144
+ """
145
+ # Register handler metadata for discovery
146
+ # Actual handler binding happens via register_handler()
147
+ _PROTOCOL_METADATA[RegistryInfraIntentStorage.HANDLER_KEY] = {
148
+ "handler": "HandlerIntent",
149
+ "module": "omnibase_infra.handlers.handler_intent",
150
+ "description": "Handler for intent storage operations in Memgraph",
151
+ "capabilities": [
152
+ "intent.storage",
153
+ "intent.storage.store",
154
+ "intent.storage.query_session",
155
+ "intent.storage.query_distribution",
156
+ ],
157
+ }
158
+
159
+ @staticmethod
160
+ def register_handler(
161
+ _container: ModelONEXContainer,
162
+ handler: HandlerIntent,
163
+ ) -> None:
164
+ """Register a specific intent handler with the container.
165
+
166
+ Binds a concrete HandlerIntent implementation to the handler key.
167
+ The handler must already be initialized with a HandlerGraph.
168
+
169
+ Args:
170
+ _container: ONEX dependency injection container. Currently unused
171
+ because ServiceRegistry v1.0 doesn't support dict-style access.
172
+ The parameter is retained for API consistency.
173
+ handler: HandlerIntent instance to register (must be initialized).
174
+
175
+ Raises:
176
+ ProtocolConfigurationError: If handler does not implement the required
177
+ protocol methods (initialize, shutdown, execute).
178
+
179
+ Example:
180
+ >>> from omnibase_infra.handlers.handler_intent import HandlerIntent
181
+ >>> handler = HandlerIntent(container)
182
+ >>> await handler.initialize({"graph_handler": graph_handler})
183
+ >>> RegistryInfraIntentStorage.register_handler(container, handler)
184
+ """
185
+ from omnibase_infra.enums import EnumInfraTransportType
186
+ from omnibase_infra.errors import (
187
+ ModelInfraErrorContext,
188
+ ProtocolConfigurationError,
189
+ )
190
+
191
+ # NOTE: Protocol-based duck typing is used here per ONEX conventions.
192
+ # We verify the handler implements required methods rather than checking
193
+ # concrete class inheritance. This enables:
194
+ # 1. Fail-fast validation: Immediately reject invalid handlers
195
+ # 2. Duck typing: Any object with the required methods is accepted
196
+ # 3. Testability: Mock handlers can be injected without subclassing
197
+ required_methods = ["initialize", "shutdown", "execute"]
198
+ missing = [
199
+ m for m in required_methods if not callable(getattr(handler, m, None))
200
+ ]
201
+ if missing:
202
+ context = ModelInfraErrorContext.with_correlation(
203
+ transport_type=EnumInfraTransportType.GRAPH,
204
+ operation="register_handler",
205
+ target_name="intent_handler",
206
+ )
207
+ raise ProtocolConfigurationError(
208
+ f"Handler missing required protocol methods: {missing}. "
209
+ f"Got {type(handler).__name__}",
210
+ context=context,
211
+ )
212
+
213
+ # Store handler in module-level storage
214
+ handler_key = (
215
+ f"{RegistryInfraIntentStorage.HANDLER_KEY}."
216
+ f"{RegistryInfraIntentStorage.DEFAULT_HANDLER_TYPE}"
217
+ )
218
+
219
+ # Warn if re-registering over an existing handler
220
+ if RegistryInfraIntentStorage._is_registered(handler_key):
221
+ logger.warning(
222
+ "Re-registering handler '%s'. This may indicate container lifecycle "
223
+ "issues or missing clear() calls in tests.",
224
+ handler_key,
225
+ )
226
+
227
+ _HANDLER_STORAGE[handler_key] = handler
228
+
229
+ # Also register as default
230
+ default_key = RegistryInfraIntentStorage.HANDLER_KEY + ".default"
231
+ if RegistryInfraIntentStorage._is_registered(default_key):
232
+ logger.warning(
233
+ "Re-registering handler '%s'. This may indicate container lifecycle "
234
+ "issues or missing clear() calls in tests.",
235
+ default_key,
236
+ )
237
+ _HANDLER_STORAGE[default_key] = handler
238
+
239
+ @staticmethod
240
+ def get_handler(
241
+ _container: ModelONEXContainer,
242
+ handler_type: str | None = None,
243
+ ) -> HandlerIntent | None:
244
+ """Retrieve a registered intent handler from the container.
245
+
246
+ Args:
247
+ _container: ONEX dependency injection container. Currently unused
248
+ because ServiceRegistry v1.0 doesn't support dict-style access.
249
+ The parameter is retained for API consistency.
250
+ handler_type: Specific handler type to retrieve. If None, returns default.
251
+
252
+ Returns:
253
+ The registered HandlerIntent, or None if not found.
254
+
255
+ Example:
256
+ >>> handler = RegistryInfraIntentStorage.get_handler(container)
257
+ >>> if handler:
258
+ ... result = await handler.execute(envelope)
259
+ """
260
+ if handler_type is not None:
261
+ handler_key = f"{RegistryInfraIntentStorage.HANDLER_KEY}.{handler_type}"
262
+ else:
263
+ handler_key = RegistryInfraIntentStorage.HANDLER_KEY + ".default"
264
+
265
+ result = _HANDLER_STORAGE.get(handler_key)
266
+ return cast("HandlerIntent | None", result)
267
+
268
+ @staticmethod
269
+ def clear() -> None:
270
+ """Clear all registered handlers and protocol metadata.
271
+
272
+ Resets all module-level state to empty dicts. This method is essential
273
+ for test isolation.
274
+
275
+ Warning:
276
+ This method MUST be called in test setup and teardown to prevent
277
+ test pollution. Module-level state persists across test cases within
278
+ the same Python process. Failing to call this method can cause:
279
+
280
+ - Handlers from previous tests affecting subsequent tests
281
+ - Tests passing individually but failing when run together
282
+ - Non-deterministic test failures that are difficult to reproduce
283
+
284
+ Example:
285
+ .. code-block:: python
286
+
287
+ @pytest.fixture(autouse=True)
288
+ def clear_registry():
289
+ RegistryInfraIntentStorage.clear()
290
+ yield
291
+ RegistryInfraIntentStorage.clear()
292
+ """
293
+ _HANDLER_STORAGE.clear()
294
+ _PROTOCOL_METADATA.clear()
@@ -91,13 +91,22 @@ Security Design (Intentional Fail-Open Architecture):
91
91
  - validator_routing_coverage.py: Routing gap detection (module docstring)
92
92
  """
93
93
 
94
+ # Topic suffix validation models (OMN-1537)
95
+ from omnibase_core.models.validation import (
96
+ ModelTopicSuffixParts,
97
+ ModelTopicValidationResult,
98
+ )
94
99
  from omnibase_core.validation import (
95
100
  CircularImportValidator,
96
101
  ModelModuleImportResult,
102
+ compose_full_topic,
103
+ is_valid_topic_suffix,
104
+ parse_topic_suffix,
97
105
  validate_all,
98
106
  validate_architecture,
99
107
  validate_contracts,
100
108
  validate_patterns,
109
+ validate_topic_suffix,
101
110
  validate_union_usage,
102
111
  )
103
112
 
@@ -222,6 +231,13 @@ __all__: list[str] = [
222
231
  "NODE_ARCHETYPE_EXPECTED_CATEGORIES", # Node archetype categories
223
232
  "TOPIC_CATEGORY_PATTERNS", # Topic category patterns
224
233
  "TOPIC_SUFFIXES", # Topic suffix constants
234
+ # Topic suffix validation (OMN-1537)
235
+ "ModelTopicSuffixParts", # Topic suffix parsed parts
236
+ "ModelTopicValidationResult", # Topic validation result
237
+ "compose_full_topic", # Compose full topic from parts
238
+ "is_valid_topic_suffix", # Check if topic suffix is valid
239
+ "parse_topic_suffix", # Parse topic suffix into parts
240
+ "validate_topic_suffix", # Validate topic suffix format
225
241
  # Errors
226
242
  "ChainPropagationError", # Chain propagation error (OMN-951)
227
243
  "ExecutionShapeViolationError", # Execution shape violation
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omnibase_infra
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: ONEX Infrastructure - Service integration and database infrastructure tools
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -28,8 +28,8 @@ Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
28
28
  Requires-Dist: jsonschema (>=4.20.0,<5.0.0)
29
29
  Requires-Dist: mcp (>=1.25.0,<2.0.0)
30
30
  Requires-Dist: neo4j (>=5.15.0,<6.0.0)
31
- Requires-Dist: omnibase-core (>=0.9.4,<0.10.0)
32
- Requires-Dist: omnibase-spi (>=0.6.0,<0.7.0)
31
+ Requires-Dist: omnibase-core (>=0.9.6,<0.10.0)
32
+ Requires-Dist: omnibase-spi (>=0.6.1,<0.7.0)
33
33
  Requires-Dist: opentelemetry-api (>=1.27.0,<2.0.0)
34
34
  Requires-Dist: opentelemetry-exporter-otlp (>=1.27.0,<2.0.0)
35
35
  Requires-Dist: opentelemetry-instrumentation (>=0.48b0,<0.49)
@@ -88,7 +88,7 @@ omnibase_infra/handlers/filesystem/model_file_system_result.py,sha256=qrQyZCuxHi
88
88
  omnibase_infra/handlers/handler_consul.py,sha256=F2u4-f8eW8Nli5drg1oH6sZJkw3EfuaycnvzmEXeOQI,31409
89
89
  omnibase_infra/handlers/handler_db.py,sha256=toaT1DS-J76J47isXsRSkcB7QFD5-8SaDbOqVEIhMmQ,44871
90
90
  omnibase_infra/handlers/handler_filesystem.py,sha256=J71cMTmWpQP4Y2h2nxy4jLmDKbvg9Xwbubjb-_ZFqGo,58333
91
- omnibase_infra/handlers/handler_graph.py,sha256=12Nulsm-xIuFJZP61IilS-SuNupRFhHWWYAtLbQzwhs,44692
91
+ omnibase_infra/handlers/handler_graph.py,sha256=SuBH4XRgGUTPFD46jZDiGC5rkCfbVJy4-gpavfX5ZaU,79794
92
92
  omnibase_infra/handlers/handler_http.py,sha256=1HAl26wtTpql1GNlLw9ZwjhOm32Oif4TOguAam16y5s,37899
93
93
  omnibase_infra/handlers/handler_intent.py,sha256=aoX8Prgum2GbqI-exNA2e2kASA1b8cVpeXcR6JtuMIg,13992
94
94
  omnibase_infra/handlers/handler_manifest_persistence.contract.yaml,sha256=kkkcDL88RcmK0ZaAa4eDcSajKwwU4iia0LN7o_zqRD8,6397
@@ -390,6 +390,14 @@ omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py,sha256=cGJmDLS
390
390
  omnibase_infra/nodes/effects/protocol_postgres_adapter.py,sha256=foLR6ZRv1EqfrZVxo9DTM5uunhkdCncnAr-6gqSEw8M,3198
391
391
  omnibase_infra/nodes/effects/registry_effect.py,sha256=dSoqw_9hF7GiYQ6a9KtF7bgEXCW2FqH5b3Ud3b5CQaM,20975
392
392
  omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py,sha256=6WXK7ZcWqPdpGLVpXbFzu-uIuc6vxCAgEpWTNHOy2Is,15566
393
+ omnibase_infra/nodes/node_intent_storage_effect/__init__.py,sha256=CVxx3WtXt_BcSgEG5496N5n7ZCK8FZFmx4jt9sPwUjE,1864
394
+ omnibase_infra/nodes/node_intent_storage_effect/contract.yaml,sha256=GSECd-8WAxytIwUQQTnP7167S0bD-1roAGaI08e_K9Q,6642
395
+ omnibase_infra/nodes/node_intent_storage_effect/models/__init__.py,sha256=XZ6L3PLHjNvnxRmJnDtVVWCsmZVfKdxnrenQWdJ1_D8,778
396
+ omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_input.py,sha256=hnAb6IQJVmJYubdg_MnB2afBk9df0bLV0gv1vnSyFug,4889
397
+ omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_output.py,sha256=kRufInAdTi58pEtLM4sYWKrwvD7g-EGFKZxb6pTSRzo,4479
398
+ omnibase_infra/nodes/node_intent_storage_effect/node.py,sha256=zfThTRPijnyrGyQLaHETC_yxdwn56IwnnS1cyH6QZD0,3475
399
+ omnibase_infra/nodes/node_intent_storage_effect/registry/__init__.py,sha256=9sLDlHv4ySokV3Jhw6KTSgpWOfI3Lt1cg-jcO9-5Zjg,1443
400
+ omnibase_infra/nodes/node_intent_storage_effect/registry/registry_infra_intent_storage.py,sha256=C095vuMER24eNHPzTxFpVR9c_DxepFO0inUGfrUOvOw,11499
393
401
  omnibase_infra/nodes/node_registration_orchestrator/README.md,sha256=DgmzwS7EkNi1ein4O1fG5FzIE_85fHCuN39J3N_3Wbk,18217
394
402
  omnibase_infra/nodes/node_registration_orchestrator/__init__.py,sha256=TEmJpSvnjYR4rO0xm-V7roVSZwEQDf6X_NIryXPiHLc,4545
395
403
  omnibase_infra/nodes/node_registration_orchestrator/contract.yaml,sha256=4amAy5T7LZgLx2-hODJ0UvKJpGNLttnGuAXWgO4pycs,26212
@@ -706,7 +714,7 @@ omnibase_infra/utils/util_error_sanitization.py,sha256=FxoHw40HCu9SO83jXuGQ5L349
706
714
  omnibase_infra/utils/util_pydantic_validators.py,sha256=7i8mgUyy-ObUCw0ICVY_N_sSoxIFfDkGsk182riQUqo,16271
707
715
  omnibase_infra/utils/util_retry_optimistic.py,sha256=hSCUGNJgECaKN3PBf44r3Y7Lh0m8BQPDk0YTSJyWtOo,10967
708
716
  omnibase_infra/utils/util_semver.py,sha256=ceTeLo753aAkyyI847XlceajdMvBIn3XJq1X1Fkfz78,7661
709
- omnibase_infra/validation/__init__.py,sha256=Ws8xI8hQ-0D87gxrWRoUwYMO1jHRPJuHgK7hzit9tXs,12640
717
+ omnibase_infra/validation/__init__.py,sha256=_HyFyYgxncjbWzbKs1Fi7jADh31SAlOB5x8QqOKNbzM,13295
710
718
  omnibase_infra/validation/contracts/security.validation.yaml,sha256=NixKgUo7KliQr1yJBY65j2WaxJv_XKoUSCA6pB77DiQ,3858
711
719
  omnibase_infra/validation/enums/__init__.py,sha256=J4vRP14R2lHaixXCk1MH5Bzh3Vd0pZmySpN8PkqJc4c,278
712
720
  omnibase_infra/validation/enums/enum_contract_violation_severity.py,sha256=beR4vRNXtQ7ckOSOYZHn3NAacZBNTX1csG9_Y6SPd7M,414
@@ -731,8 +739,8 @@ omnibase_infra/validation/validator_routing_coverage.py,sha256=51vYEi5NhU6wqohk2
731
739
  omnibase_infra/validation/validator_runtime_shape.py,sha256=9Xl37_dNDinT7nr-BoJ9fG3O5cT1_j6N-C7bojwQi3g,39033
732
740
  omnibase_infra/validation/validator_security.py,sha256=Yn_kwxBtPzEj1GzrW0OafL-bR-FgoqdeFzseQqF2_B8,20622
733
741
  omnibase_infra/validation/validator_topic_category.py,sha256=1y6STpSNIJsE2AmX5f8PVzPuOfoQmedgocSbEqOdtrM,48798
734
- omnibase_infra-0.2.3.dist-info/METADATA,sha256=H7cdWfmx6qcKKqLO9H9wR73cQhNcLopSeAjpNHnqwus,7553
735
- omnibase_infra-0.2.3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
736
- omnibase_infra-0.2.3.dist-info/entry_points.txt,sha256=NlZEQIMp4I5S2f0l286hLyA48oQB92S0ISrn1rfFP30,110
737
- omnibase_infra-0.2.3.dist-info/licenses/LICENSE,sha256=CwYWppeN0neFHYdbbUdHbR4_PiyTYnmk6ufFWuVsL7I,1070
738
- omnibase_infra-0.2.3.dist-info/RECORD,,
742
+ omnibase_infra-0.2.5.dist-info/METADATA,sha256=jfps4nOkHND0EapFOjf-osUGKwledT6kvy6DSfM8R_4,7553
743
+ omnibase_infra-0.2.5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
744
+ omnibase_infra-0.2.5.dist-info/entry_points.txt,sha256=NlZEQIMp4I5S2f0l286hLyA48oQB92S0ISrn1rfFP30,110
745
+ omnibase_infra-0.2.5.dist-info/licenses/LICENSE,sha256=CwYWppeN0neFHYdbbUdHbR4_PiyTYnmk6ufFWuVsL7I,1070
746
+ omnibase_infra-0.2.5.dist-info/RECORD,,