exonware-xwnode 0.0.1.12__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 (132) hide show
  1. exonware/__init__.py +14 -0
  2. exonware/xwnode/__init__.py +127 -0
  3. exonware/xwnode/base.py +676 -0
  4. exonware/xwnode/config.py +178 -0
  5. exonware/xwnode/contracts.py +730 -0
  6. exonware/xwnode/errors.py +503 -0
  7. exonware/xwnode/facade.py +460 -0
  8. exonware/xwnode/strategies/__init__.py +158 -0
  9. exonware/xwnode/strategies/advisor.py +463 -0
  10. exonware/xwnode/strategies/edges/__init__.py +32 -0
  11. exonware/xwnode/strategies/edges/adj_list.py +227 -0
  12. exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
  13. exonware/xwnode/strategies/edges/base.py +169 -0
  14. exonware/xwnode/strategies/flyweight.py +328 -0
  15. exonware/xwnode/strategies/impls/__init__.py +13 -0
  16. exonware/xwnode/strategies/impls/_base_edge.py +403 -0
  17. exonware/xwnode/strategies/impls/_base_node.py +307 -0
  18. exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
  19. exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
  20. exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
  21. exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
  22. exonware/xwnode/strategies/impls/edge_coo.py +533 -0
  23. exonware/xwnode/strategies/impls/edge_csc.py +447 -0
  24. exonware/xwnode/strategies/impls/edge_csr.py +492 -0
  25. exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
  26. exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
  27. exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
  28. exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
  29. exonware/xwnode/strategies/impls/edge_octree.py +574 -0
  30. exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
  31. exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
  32. exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
  33. exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
  34. exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
  35. exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
  36. exonware/xwnode/strategies/manager.py +775 -0
  37. exonware/xwnode/strategies/metrics.py +538 -0
  38. exonware/xwnode/strategies/migration.py +432 -0
  39. exonware/xwnode/strategies/nodes/__init__.py +50 -0
  40. exonware/xwnode/strategies/nodes/_base_node.py +307 -0
  41. exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
  42. exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
  43. exonware/xwnode/strategies/nodes/array_list.py +209 -0
  44. exonware/xwnode/strategies/nodes/base.py +247 -0
  45. exonware/xwnode/strategies/nodes/deque.py +200 -0
  46. exonware/xwnode/strategies/nodes/hash_map.py +135 -0
  47. exonware/xwnode/strategies/nodes/heap.py +307 -0
  48. exonware/xwnode/strategies/nodes/linked_list.py +232 -0
  49. exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
  50. exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
  51. exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
  52. exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
  53. exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
  54. exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
  55. exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
  56. exonware/xwnode/strategies/nodes/node_btree.py +357 -0
  57. exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
  58. exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
  59. exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
  60. exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
  61. exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
  62. exonware/xwnode/strategies/nodes/node_heap.py +191 -0
  63. exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
  64. exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
  65. exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
  66. exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
  67. exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
  68. exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
  69. exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
  70. exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
  71. exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
  72. exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
  73. exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
  74. exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
  75. exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
  76. exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
  77. exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
  78. exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
  79. exonware/xwnode/strategies/nodes/node_treap.py +387 -0
  80. exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
  81. exonware/xwnode/strategies/nodes/node_trie.py +252 -0
  82. exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
  83. exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
  84. exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
  85. exonware/xwnode/strategies/nodes/queue.py +161 -0
  86. exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
  87. exonware/xwnode/strategies/nodes/stack.py +152 -0
  88. exonware/xwnode/strategies/nodes/trie.py +274 -0
  89. exonware/xwnode/strategies/nodes/union_find.py +283 -0
  90. exonware/xwnode/strategies/pattern_detector.py +603 -0
  91. exonware/xwnode/strategies/performance_monitor.py +487 -0
  92. exonware/xwnode/strategies/queries/__init__.py +24 -0
  93. exonware/xwnode/strategies/queries/base.py +236 -0
  94. exonware/xwnode/strategies/queries/cql.py +201 -0
  95. exonware/xwnode/strategies/queries/cypher.py +181 -0
  96. exonware/xwnode/strategies/queries/datalog.py +70 -0
  97. exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
  98. exonware/xwnode/strategies/queries/eql.py +70 -0
  99. exonware/xwnode/strategies/queries/flux.py +70 -0
  100. exonware/xwnode/strategies/queries/gql.py +70 -0
  101. exonware/xwnode/strategies/queries/graphql.py +240 -0
  102. exonware/xwnode/strategies/queries/gremlin.py +181 -0
  103. exonware/xwnode/strategies/queries/hiveql.py +214 -0
  104. exonware/xwnode/strategies/queries/hql.py +70 -0
  105. exonware/xwnode/strategies/queries/jmespath.py +219 -0
  106. exonware/xwnode/strategies/queries/jq.py +66 -0
  107. exonware/xwnode/strategies/queries/json_query.py +66 -0
  108. exonware/xwnode/strategies/queries/jsoniq.py +248 -0
  109. exonware/xwnode/strategies/queries/kql.py +70 -0
  110. exonware/xwnode/strategies/queries/linq.py +238 -0
  111. exonware/xwnode/strategies/queries/logql.py +70 -0
  112. exonware/xwnode/strategies/queries/mql.py +68 -0
  113. exonware/xwnode/strategies/queries/n1ql.py +210 -0
  114. exonware/xwnode/strategies/queries/partiql.py +70 -0
  115. exonware/xwnode/strategies/queries/pig.py +215 -0
  116. exonware/xwnode/strategies/queries/promql.py +70 -0
  117. exonware/xwnode/strategies/queries/sparql.py +220 -0
  118. exonware/xwnode/strategies/queries/sql.py +275 -0
  119. exonware/xwnode/strategies/queries/xml_query.py +66 -0
  120. exonware/xwnode/strategies/queries/xpath.py +223 -0
  121. exonware/xwnode/strategies/queries/xquery.py +258 -0
  122. exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
  123. exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
  124. exonware/xwnode/strategies/registry.py +604 -0
  125. exonware/xwnode/strategies/simple.py +273 -0
  126. exonware/xwnode/strategies/utils.py +532 -0
  127. exonware/xwnode/types.py +912 -0
  128. exonware/xwnode/version.py +78 -0
  129. exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
  130. exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
  131. exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
  132. exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,503 @@
1
+ """
2
+ #exonware/xwnode/src/exonware/xwnode/errors.py
3
+
4
+ A+ Best Practice Error Handling for xwnode Library.
5
+
6
+ This module implements zero-overhead error handling with rich context,
7
+ actionable suggestions, and performance optimization for critical paths.
8
+ """
9
+
10
+ import time
11
+ import difflib
12
+ from typing import Any, Dict, List, Optional, Union
13
+ from exonware.xwsystem import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ # ============================================================================
19
+ # A+ BASE ERROR SYSTEM
20
+ # ============================================================================
21
+
22
+ class XWNodeError(Exception):
23
+ """
24
+ Base exception with rich context and zero overhead in success path.
25
+
26
+ This error system follows modern Python best practices:
27
+ - Zero overhead when no errors occur
28
+ - Rich context only created on failure path
29
+ - Chainable methods for fluent error building
30
+ - Performance-optimized with __slots__
31
+ """
32
+
33
+ __slots__ = ('message', 'error_code', 'context', 'suggestions', 'timestamp', 'cause')
34
+
35
+ def __init__(self, message: str, *,
36
+ error_code: str = None,
37
+ context: Dict[str, Any] = None,
38
+ suggestions: List[str] = None,
39
+ cause: Exception = None):
40
+ super().__init__(message)
41
+ self.message = message
42
+ self.error_code = error_code or self.__class__.__name__
43
+ self.context = context or {}
44
+ self.suggestions = suggestions or []
45
+ self.timestamp = time.time()
46
+ self.cause = cause
47
+
48
+ def add_context(self, **kwargs) -> 'XWNodeError':
49
+ """Add context information (chainable)."""
50
+ self.context.update(kwargs)
51
+ return self
52
+
53
+ def suggest(self, suggestion: str) -> 'XWNodeError':
54
+ """Add actionable suggestion (chainable)."""
55
+ self.suggestions.append(suggestion)
56
+ return self
57
+
58
+ def __str__(self) -> str:
59
+ """Rich string representation with context and suggestions."""
60
+ result = [self.message]
61
+
62
+ if self.context:
63
+ context_str = ', '.join(f"{k}={v}" for k, v in self.context.items())
64
+ result.append(f"Context: {context_str}")
65
+
66
+ if self.suggestions:
67
+ suggestions_str = '; '.join(self.suggestions)
68
+ result.append(f"Suggestions: {suggestions_str}")
69
+
70
+ return " | ".join(result)
71
+
72
+
73
+ # ============================================================================
74
+ # PATH NAVIGATION ERRORS (Most Common)
75
+ # ============================================================================
76
+
77
+ class XWNodePathError(XWNodeError, KeyError):
78
+ """
79
+ Path navigation errors with AI-like suggestions.
80
+
81
+ This is the most common error type, so it's heavily optimized
82
+ with smart suggestion generation and fuzzy matching.
83
+ """
84
+
85
+ __slots__ = ('path', 'segment', 'reason', 'node_type', 'available_keys')
86
+
87
+ def __init__(self, path: str, segment: str = None, reason: str = "not_found",
88
+ node_type: str = None, available_keys: List[str] = None):
89
+ self.path = path
90
+ self.segment = segment or path
91
+ self.reason = reason # "not_found", "type_mismatch", "out_of_bounds"
92
+ self.node_type = node_type
93
+ self.available_keys = available_keys or []
94
+
95
+ # Generate helpful message
96
+ message = f"Path navigation failed: '{path}'"
97
+ if segment and segment != path:
98
+ message += f" at segment '{segment}'"
99
+ message += f" ({reason})"
100
+
101
+ context = {
102
+ 'path': path,
103
+ 'segment': segment,
104
+ 'reason': reason,
105
+ 'node_type': node_type
106
+ }
107
+
108
+ suggestions = self._generate_smart_suggestions()
109
+
110
+ super().__init__(message,
111
+ error_code=f"PATH_{reason.upper()}",
112
+ context=context,
113
+ suggestions=suggestions)
114
+
115
+ def _generate_smart_suggestions(self) -> List[str]:
116
+ """Generate AI-like suggestions based on error context."""
117
+ suggestions = []
118
+
119
+ if self.reason == "not_found" and self.available_keys:
120
+ # Fuzzy matching for typos (performance: only on error path)
121
+ close_matches = difflib.get_close_matches(
122
+ self.segment, self.available_keys, n=3, cutoff=0.6
123
+ )
124
+ if close_matches:
125
+ suggestions.append(f"Did you mean: {', '.join(close_matches)}?")
126
+
127
+ # Show available options (truncated for readability)
128
+ if len(self.available_keys) <= 5:
129
+ suggestions.append(f"Available: {', '.join(self.available_keys)}")
130
+ else:
131
+ preview = ', '.join(self.available_keys[:5])
132
+ suggestions.append(f"Available: {preview}... ({len(self.available_keys)} total)")
133
+
134
+ elif self.reason == "type_mismatch":
135
+ suggestions.append("Cannot access children of leaf nodes")
136
+ if self.node_type:
137
+ suggestions.append(f"Node type is '{self.node_type}' (not a container)")
138
+
139
+ elif self.reason == "out_of_bounds":
140
+ suggestions.append("Check list bounds before accessing by index")
141
+ if self.available_keys:
142
+ suggestions.append(f"Valid range: 0-{len(self.available_keys)-1}")
143
+
144
+ return suggestions
145
+
146
+
147
+ class XWNodeTypeError(XWNodeError, TypeError):
148
+ """Enhanced type errors with operation context."""
149
+
150
+ __slots__ = ('attempted_operation', 'actual_type', 'expected_types')
151
+
152
+ def __init__(self, message: str, *,
153
+ attempted_operation: str = None,
154
+ actual_type: str = None,
155
+ expected_types: List[str] = None):
156
+ self.attempted_operation = attempted_operation
157
+ self.actual_type = actual_type
158
+ self.expected_types = expected_types or []
159
+
160
+ context = {
161
+ 'operation': attempted_operation,
162
+ 'actual_type': actual_type,
163
+ 'expected_types': expected_types
164
+ }
165
+
166
+ suggestions = []
167
+ if expected_types:
168
+ suggestions.append(f"Expected types: {', '.join(expected_types)}")
169
+ if attempted_operation:
170
+ suggestions.append(f"Check node type before {attempted_operation}")
171
+
172
+ super().__init__(message,
173
+ error_code="TYPE_MISMATCH",
174
+ context=context,
175
+ suggestions=suggestions)
176
+
177
+
178
+ class XWNodeValueError(XWNodeError, ValueError):
179
+ """Enhanced value errors with validation context."""
180
+
181
+ __slots__ = ('invalid_value', 'constraints', 'validation_rules')
182
+
183
+ def __init__(self, message: str, *,
184
+ invalid_value: Any = None,
185
+ constraints: Dict[str, Any] = None,
186
+ validation_rules: List[str] = None):
187
+ self.invalid_value = invalid_value
188
+ self.constraints = constraints or {}
189
+ self.validation_rules = validation_rules or []
190
+
191
+ context = {
192
+ 'invalid_value': invalid_value,
193
+ 'constraints': constraints
194
+ }
195
+
196
+ suggestions = []
197
+ if validation_rules:
198
+ suggestions.extend(validation_rules)
199
+ if constraints:
200
+ for rule, value in constraints.items():
201
+ suggestions.append(f"Value must satisfy {rule}: {value}")
202
+
203
+ super().__init__(message,
204
+ error_code="INVALID_VALUE",
205
+ context=context,
206
+ suggestions=suggestions)
207
+
208
+
209
+ # ============================================================================
210
+ # PERFORMANCE-OPTIMIZED ERROR FACTORY
211
+ # ============================================================================
212
+
213
+ class ErrorFactory:
214
+ """
215
+ Zero-overhead error creation for critical paths.
216
+
217
+ This factory provides fast paths for common error scenarios,
218
+ avoiding expensive operations in hot code paths.
219
+ """
220
+
221
+ @staticmethod
222
+ def path_not_found(path: str, segment: str = None, available_keys: List[str] = None) -> XWNodePathError:
223
+ """Fast path for common 'not found' errors."""
224
+ return XWNodePathError(path, segment, "not_found", available_keys=available_keys)
225
+
226
+ @staticmethod
227
+ def type_mismatch(path: str, segment: str, node_type: str) -> XWNodePathError:
228
+ """Fast path for type mismatch errors."""
229
+ return XWNodePathError(path, segment, "type_mismatch", node_type=node_type)
230
+
231
+ @staticmethod
232
+ def index_out_of_bounds(path: str, index: int, length: int) -> XWNodePathError:
233
+ """Fast path for index errors."""
234
+ return XWNodePathError(path, str(index), "out_of_bounds").add_context(
235
+ index=index, length=length
236
+ ).suggest(f"Valid range: 0-{length-1}")
237
+
238
+ @staticmethod
239
+ def operation_not_supported(operation: str, node_type: str, supported_ops: List[str] = None) -> XWNodeTypeError:
240
+ """Fast path for unsupported operation errors."""
241
+ message = f"Operation '{operation}' not supported on {node_type}"
242
+ error = XWNodeTypeError(
243
+ message,
244
+ attempted_operation=operation,
245
+ actual_type=node_type
246
+ )
247
+ if supported_ops:
248
+ error.suggest(f"Supported operations: {', '.join(supported_ops)}")
249
+ return error
250
+
251
+ @staticmethod
252
+ def invalid_preset(preset_name: str, available_presets: List[str]) -> XWNodeValueError:
253
+ """Fast path for invalid preset errors."""
254
+ close_matches = difflib.get_close_matches(preset_name, available_presets, n=3, cutoff=0.6)
255
+ error = XWNodeValueError(
256
+ f"Unknown preset '{preset_name}'",
257
+ invalid_value=preset_name,
258
+ constraints={'available_presets': available_presets}
259
+ )
260
+ if close_matches:
261
+ error.suggest(f"Did you mean: {', '.join(close_matches)}?")
262
+ error.suggest(f"Available presets: {', '.join(available_presets)}")
263
+ return error
264
+
265
+
266
+ # ============================================================================
267
+ # STRATEGY SYSTEM ERRORS (A+ Enhanced)
268
+ # ============================================================================
269
+
270
+ class XWNodeStrategyError(XWNodeError):
271
+ """Base exception for strategy-related errors."""
272
+ pass
273
+
274
+
275
+ class XWNodeUnsupportedCapabilityError(XWNodeStrategyError):
276
+ """Raised when a strategy doesn't support a requested capability."""
277
+
278
+ __slots__ = ('capability', 'strategy', 'available_capabilities')
279
+
280
+ def __init__(self, capability: str, strategy: str, available_capabilities: List[str] = None):
281
+ self.capability = capability
282
+ self.strategy = strategy
283
+ self.available_capabilities = available_capabilities or []
284
+
285
+ message = f"Strategy '{strategy}' does not support capability '{capability}'"
286
+
287
+ context = {
288
+ 'capability': capability,
289
+ 'strategy': strategy,
290
+ 'available_capabilities': available_capabilities
291
+ }
292
+
293
+ suggestions = []
294
+ if available_capabilities:
295
+ suggestions.append(f"Available capabilities: {', '.join(available_capabilities)}")
296
+
297
+ # Suggest alternative strategies
298
+ if capability == 'graph_operations':
299
+ suggestions.append("Use preset='SOCIAL_GRAPH' or 'TREE_GRAPH_MIX' for graph features")
300
+ elif capability == 'spatial_operations':
301
+ suggestions.append("Use preset='SPATIAL_MAP' for spatial features")
302
+
303
+ super().__init__(message,
304
+ error_code="UNSUPPORTED_CAPABILITY",
305
+ context=context,
306
+ suggestions=suggestions)
307
+
308
+
309
+ class XWNodePresetError(XWNodeStrategyError):
310
+ """Raised when preset operations fail."""
311
+
312
+ __slots__ = ('preset_name', 'operation', 'reason')
313
+
314
+ def __init__(self, preset_name: str, operation: str, reason: str = None):
315
+ self.preset_name = preset_name
316
+ self.operation = operation
317
+ self.reason = reason
318
+
319
+ message = f"Preset '{preset_name}' {operation} failed"
320
+ if reason:
321
+ message += f": {reason}"
322
+
323
+ context = {
324
+ 'preset_name': preset_name,
325
+ 'operation': operation,
326
+ 'reason': reason
327
+ }
328
+
329
+ # Import here to avoid circular imports
330
+ try:
331
+ from .types import list_presets
332
+ available = list_presets()
333
+ suggestions = [f"Available presets: {', '.join(available)}"]
334
+ except ImportError:
335
+ suggestions = ["Check preset name spelling"]
336
+
337
+ super().__init__(message,
338
+ error_code="PRESET_ERROR",
339
+ context=context,
340
+ suggestions=suggestions)
341
+
342
+
343
+ # ============================================================================
344
+ # SECURITY ERRORS (A+ Enhanced)
345
+ # ============================================================================
346
+
347
+ class XWNodeSecurityError(XWNodeError):
348
+ """Base exception for security-related errors."""
349
+ pass
350
+
351
+
352
+ class XWNodeLimitError(XWNodeSecurityError):
353
+ """Raised when resource limits are exceeded."""
354
+
355
+ __slots__ = ('resource', 'limit', 'actual_value')
356
+
357
+ def __init__(self, resource: str, limit: Union[int, str], actual_value: Union[int, str] = None):
358
+ self.resource = resource
359
+ self.limit = limit
360
+ self.actual_value = actual_value
361
+
362
+ message = f"Resource limit exceeded for {resource}: limit={limit}"
363
+ if actual_value is not None:
364
+ message += f", actual={actual_value}"
365
+
366
+ context = {
367
+ 'resource': resource,
368
+ 'limit': limit,
369
+ 'actual_value': actual_value
370
+ }
371
+
372
+ suggestions = [
373
+ f"Increase {resource} limit in configuration",
374
+ "Consider using a more efficient strategy",
375
+ "Break operation into smaller chunks"
376
+ ]
377
+
378
+ super().__init__(message,
379
+ error_code="RESOURCE_LIMIT",
380
+ context=context,
381
+ suggestions=suggestions)
382
+
383
+
384
+ class XWNodePathSecurityError(XWNodeSecurityError):
385
+ """Raised for path-related security violations."""
386
+
387
+ __slots__ = ('path', 'violation_type', 'security_policy')
388
+
389
+ def __init__(self, path: str, violation_type: str, security_policy: str = None):
390
+ self.path = path
391
+ self.violation_type = violation_type
392
+ self.security_policy = security_policy
393
+
394
+ message = f"Path security violation: {violation_type} in '{path}'"
395
+ if security_policy:
396
+ message += f" (policy: {security_policy})"
397
+
398
+ context = {
399
+ 'path': path,
400
+ 'violation_type': violation_type,
401
+ 'security_policy': security_policy
402
+ }
403
+
404
+ suggestions = [
405
+ "Check path for invalid characters or patterns",
406
+ "Use only trusted data sources",
407
+ "Sanitize user input before path operations"
408
+ ]
409
+
410
+ super().__init__(message,
411
+ error_code="PATH_SECURITY",
412
+ context=context,
413
+ suggestions=suggestions)
414
+
415
+
416
+ # ============================================================================
417
+ # PERFORMANCE OPTIMIZATION HELPERS
418
+ # ============================================================================
419
+
420
+ def safe_path_access(get_child_func, path: str, segment: str, node=None):
421
+ """
422
+ Optimized wrapper for path access with minimal error overhead.
423
+
424
+ This function encapsulates the zero-overhead error handling pattern:
425
+ - Fast path when operation succeeds
426
+ - Rich error context only on failure
427
+ """
428
+ try:
429
+ # Fast path - no error overhead when successful
430
+ return get_child_func(segment)
431
+ except KeyError:
432
+ # Only create rich error on failure path
433
+ available = []
434
+ if node and hasattr(node, 'keys'):
435
+ available = list(node.keys())
436
+ raise ErrorFactory.path_not_found(path, segment, available)
437
+ except IndexError:
438
+ # Index out of bounds
439
+ length = len(node) if node and hasattr(node, '__len__') else 0
440
+ try:
441
+ index = int(segment)
442
+ raise ErrorFactory.index_out_of_bounds(path, index, length)
443
+ except ValueError:
444
+ # Non-numeric index on list
445
+ raise ErrorFactory.type_mismatch(path, segment, "list")
446
+ except TypeError:
447
+ # Type mismatch - trying to access child of leaf
448
+ node_type = type(node).__name__ if node else "unknown"
449
+ raise ErrorFactory.type_mismatch(path, segment, node_type)
450
+
451
+
452
+ # ============================================================================
453
+ # LEGACY COMPATIBILITY (Backwards compatibility)
454
+ # ============================================================================
455
+
456
+ # Keep old error names for backwards compatibility
457
+ XWNodeValidationError = XWNodeValueError
458
+ XWNodeSerializationError = XWNodeError
459
+ XWNodePerformanceError = XWNodeError
460
+ XWNodeConfigurationError = XWNodeError
461
+
462
+ # Strategy errors (maintained for compatibility)
463
+ XWNodeIllegalMigrationError = XWNodeStrategyError
464
+ XWNodeStrategyNotFoundError = XWNodeStrategyError
465
+ XWNodeStrategyInitializationError = XWNodeStrategyError
466
+ XWNodeConcurrencyError = XWNodeStrategyError
467
+
468
+
469
+ # ============================================================================
470
+ # EXPORTS
471
+ # ============================================================================
472
+
473
+ __all__ = [
474
+ # Core error system
475
+ 'XWNodeError',
476
+ 'XWNodePathError',
477
+ 'XWNodeTypeError',
478
+ 'XWNodeValueError',
479
+
480
+ # Security errors
481
+ 'XWNodeSecurityError',
482
+ 'XWNodeLimitError',
483
+ 'XWNodePathSecurityError',
484
+
485
+ # Strategy errors
486
+ 'XWNodeStrategyError',
487
+ 'XWNodeUnsupportedCapabilityError',
488
+ 'XWNodePresetError',
489
+
490
+ # Performance helpers
491
+ 'ErrorFactory',
492
+ 'safe_path_access',
493
+
494
+ # Legacy compatibility
495
+ 'XWNodeValidationError',
496
+ 'XWNodeSerializationError',
497
+ 'XWNodePerformanceError',
498
+ 'XWNodeConfigurationError',
499
+ 'XWNodeIllegalMigrationError',
500
+ 'XWNodeStrategyNotFoundError',
501
+ 'XWNodeStrategyInitializationError',
502
+ 'XWNodeConcurrencyError'
503
+ ]