unrealon 1.1.6__py3-none-any.whl → 2.0.4__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 (145) hide show
  1. {unrealon-1.1.6.dist-info/licenses → unrealon-2.0.4.dist-info}/LICENSE +1 -1
  2. unrealon-2.0.4.dist-info/METADATA +491 -0
  3. unrealon-2.0.4.dist-info/RECORD +129 -0
  4. {unrealon-1.1.6.dist-info → unrealon-2.0.4.dist-info}/WHEEL +2 -1
  5. unrealon-2.0.4.dist-info/entry_points.txt +3 -0
  6. unrealon-2.0.4.dist-info/top_level.txt +3 -0
  7. unrealon_browser/__init__.py +5 -6
  8. unrealon_browser/cli/browser_cli.py +18 -9
  9. unrealon_browser/cli/interactive_mode.py +13 -4
  10. unrealon_browser/core/browser_manager.py +29 -16
  11. unrealon_browser/dto/__init__.py +21 -0
  12. unrealon_browser/dto/bot_detection.py +175 -0
  13. unrealon_browser/dto/models/config.py +9 -3
  14. unrealon_browser/managers/__init__.py +1 -1
  15. unrealon_browser/managers/logger_bridge.py +1 -4
  16. unrealon_browser/stealth/__init__.py +27 -0
  17. unrealon_browser/stealth/bypass_techniques.pyc +0 -0
  18. unrealon_browser/stealth/manager.pyc +0 -0
  19. unrealon_browser/stealth/nodriver_stealth.pyc +0 -0
  20. unrealon_browser/stealth/playwright_stealth.pyc +0 -0
  21. unrealon_browser/stealth/scanner_tester.pyc +0 -0
  22. unrealon_browser/stealth/undetected_chrome.pyc +0 -0
  23. unrealon_core/__init__.py +160 -0
  24. unrealon_core/config/__init__.py +16 -0
  25. unrealon_core/config/environment.py +98 -0
  26. unrealon_core/config/urls.py +93 -0
  27. unrealon_core/enums/__init__.py +24 -0
  28. unrealon_core/enums/status.py +216 -0
  29. unrealon_core/enums/types.py +240 -0
  30. unrealon_core/error_handling/__init__.py +45 -0
  31. unrealon_core/error_handling/circuit_breaker.py +292 -0
  32. unrealon_core/error_handling/error_context.py +324 -0
  33. unrealon_core/error_handling/recovery.py +371 -0
  34. unrealon_core/error_handling/retry.py +268 -0
  35. unrealon_core/exceptions/__init__.py +46 -0
  36. unrealon_core/exceptions/base.py +292 -0
  37. unrealon_core/exceptions/communication.py +22 -0
  38. unrealon_core/exceptions/driver.py +11 -0
  39. unrealon_core/exceptions/proxy.py +11 -0
  40. unrealon_core/exceptions/task.py +12 -0
  41. unrealon_core/exceptions/validation.py +17 -0
  42. unrealon_core/models/__init__.py +98 -0
  43. unrealon_core/models/arq_context.py +252 -0
  44. unrealon_core/models/arq_responses.py +125 -0
  45. unrealon_core/models/base.py +291 -0
  46. unrealon_core/models/bridge_stats.py +58 -0
  47. unrealon_core/models/communication.py +39 -0
  48. unrealon_core/models/config.py +47 -0
  49. unrealon_core/models/connection_stats.py +47 -0
  50. unrealon_core/models/driver.py +30 -0
  51. unrealon_core/models/driver_details.py +98 -0
  52. unrealon_core/models/logging.py +28 -0
  53. unrealon_core/models/task.py +21 -0
  54. unrealon_core/models/typed_responses.py +210 -0
  55. unrealon_core/models/websocket/__init__.py +91 -0
  56. unrealon_core/models/websocket/base.py +49 -0
  57. unrealon_core/models/websocket/config.py +200 -0
  58. unrealon_core/models/websocket/driver.py +215 -0
  59. unrealon_core/models/websocket/errors.py +138 -0
  60. unrealon_core/models/websocket/heartbeat.py +100 -0
  61. unrealon_core/models/websocket/logging.py +261 -0
  62. unrealon_core/models/websocket/proxy.py +496 -0
  63. unrealon_core/models/websocket/tasks.py +275 -0
  64. unrealon_core/models/websocket/utils.py +153 -0
  65. unrealon_core/models/websocket_session.py +144 -0
  66. unrealon_core/monitoring/__init__.py +43 -0
  67. unrealon_core/monitoring/alerts.py +398 -0
  68. unrealon_core/monitoring/dashboard.py +307 -0
  69. unrealon_core/monitoring/health_check.py +354 -0
  70. unrealon_core/monitoring/metrics.py +352 -0
  71. unrealon_core/utils/__init__.py +11 -0
  72. unrealon_core/utils/time.py +61 -0
  73. unrealon_core/version.py +219 -0
  74. unrealon_driver/__init__.py +90 -51
  75. unrealon_driver/core_module/__init__.py +34 -0
  76. unrealon_driver/core_module/base.py +184 -0
  77. unrealon_driver/core_module/config.py +30 -0
  78. unrealon_driver/core_module/event_manager.py +127 -0
  79. unrealon_driver/core_module/protocols.py +98 -0
  80. unrealon_driver/core_module/registry.py +146 -0
  81. unrealon_driver/decorators/__init__.py +15 -0
  82. unrealon_driver/decorators/retry.py +117 -0
  83. unrealon_driver/decorators/schedule.py +137 -0
  84. unrealon_driver/decorators/task.py +61 -0
  85. unrealon_driver/decorators/timing.py +132 -0
  86. unrealon_driver/driver/__init__.py +20 -0
  87. unrealon_driver/driver/communication/__init__.py +10 -0
  88. unrealon_driver/driver/communication/session.py +203 -0
  89. unrealon_driver/driver/communication/websocket_client.py +197 -0
  90. unrealon_driver/driver/core/__init__.py +10 -0
  91. unrealon_driver/driver/core/config.py +85 -0
  92. unrealon_driver/driver/core/driver.py +221 -0
  93. unrealon_driver/driver/factory/__init__.py +9 -0
  94. unrealon_driver/driver/factory/manager_factory.py +130 -0
  95. unrealon_driver/driver/lifecycle/__init__.py +11 -0
  96. unrealon_driver/driver/lifecycle/daemon.py +76 -0
  97. unrealon_driver/driver/lifecycle/initialization.py +97 -0
  98. unrealon_driver/driver/lifecycle/shutdown.py +48 -0
  99. unrealon_driver/driver/monitoring/__init__.py +9 -0
  100. unrealon_driver/driver/monitoring/health.py +63 -0
  101. unrealon_driver/driver/utilities/__init__.py +10 -0
  102. unrealon_driver/driver/utilities/logging.py +51 -0
  103. unrealon_driver/driver/utilities/serialization.py +61 -0
  104. unrealon_driver/managers/__init__.py +32 -0
  105. unrealon_driver/managers/base.py +174 -0
  106. unrealon_driver/managers/browser.py +98 -0
  107. unrealon_driver/managers/cache.py +116 -0
  108. unrealon_driver/managers/http.py +107 -0
  109. unrealon_driver/managers/logger.py +286 -0
  110. unrealon_driver/managers/proxy.py +99 -0
  111. unrealon_driver/managers/registry.py +87 -0
  112. unrealon_driver/managers/threading.py +54 -0
  113. unrealon_driver/managers/update.py +107 -0
  114. unrealon_driver/utils/__init__.py +9 -0
  115. unrealon_driver/utils/time.py +10 -0
  116. unrealon-1.1.6.dist-info/METADATA +0 -625
  117. unrealon-1.1.6.dist-info/RECORD +0 -55
  118. unrealon-1.1.6.dist-info/entry_points.txt +0 -9
  119. unrealon_browser/managers/stealth.py +0 -388
  120. unrealon_driver/README.md +0 -0
  121. unrealon_driver/exceptions.py +0 -33
  122. unrealon_driver/html_analyzer/__init__.py +0 -32
  123. unrealon_driver/html_analyzer/cleaner.py +0 -657
  124. unrealon_driver/html_analyzer/config.py +0 -64
  125. unrealon_driver/html_analyzer/manager.py +0 -247
  126. unrealon_driver/html_analyzer/models.py +0 -115
  127. unrealon_driver/html_analyzer/websocket_analyzer.py +0 -157
  128. unrealon_driver/models/__init__.py +0 -31
  129. unrealon_driver/models/websocket.py +0 -98
  130. unrealon_driver/parser/__init__.py +0 -36
  131. unrealon_driver/parser/cli_manager.py +0 -142
  132. unrealon_driver/parser/daemon_manager.py +0 -403
  133. unrealon_driver/parser/managers/__init__.py +0 -25
  134. unrealon_driver/parser/managers/config.py +0 -293
  135. unrealon_driver/parser/managers/error.py +0 -412
  136. unrealon_driver/parser/managers/result.py +0 -321
  137. unrealon_driver/parser/parser_manager.py +0 -458
  138. unrealon_driver/smart_logging/__init__.py +0 -24
  139. unrealon_driver/smart_logging/models.py +0 -44
  140. unrealon_driver/smart_logging/smart_logger.py +0 -406
  141. unrealon_driver/smart_logging/unified_logger.py +0 -525
  142. unrealon_driver/websocket/__init__.py +0 -31
  143. unrealon_driver/websocket/client.py +0 -249
  144. unrealon_driver/websocket/config.py +0 -188
  145. unrealon_driver/websocket/manager.py +0 -90
@@ -0,0 +1,268 @@
1
+ """
2
+ Retry System
3
+
4
+ Advanced retry logic with multiple backoff strategies.
5
+ Following critical requirements - max 500 lines, functions < 20 lines.
6
+
7
+ Phase 2: Core Systems - Error Handling
8
+ """
9
+
10
+ import asyncio
11
+ import logging
12
+ import random
13
+ from abc import ABC, abstractmethod
14
+ from datetime import datetime, timedelta
15
+ from typing import Any, Callable, Optional, Type, Union, List
16
+ from enum import Enum
17
+
18
+ from pydantic import BaseModel, Field, ConfigDict
19
+
20
+ from ..exceptions.base import UnrealOnError
21
+ from ..utils.time import utc_now
22
+
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class RetryStrategy(str, Enum):
28
+ """Retry strategy types."""
29
+ EXPONENTIAL = "exponential"
30
+ LINEAR = "linear"
31
+ FIXED = "fixed"
32
+
33
+
34
+ class RetryResult(BaseModel):
35
+ """Result of retry operation."""
36
+
37
+ model_config = ConfigDict(
38
+ validate_assignment=True,
39
+ extra="forbid"
40
+ )
41
+
42
+ success: bool = Field(description="Whether operation succeeded")
43
+ attempts: int = Field(description="Number of attempts made")
44
+ total_duration: float = Field(description="Total duration in seconds")
45
+ last_error: Optional[str] = Field(default=None, description="Last error message")
46
+ result: Optional[Any] = Field(default=None, description="Operation result if successful")
47
+
48
+
49
+ class RetryConfig(BaseModel):
50
+ """Configuration for retry behavior."""
51
+
52
+ model_config = ConfigDict(
53
+ validate_assignment=True,
54
+ extra="forbid"
55
+ )
56
+
57
+ max_attempts: int = Field(default=3, ge=1, le=10, description="Maximum retry attempts")
58
+ strategy: RetryStrategy = Field(default=RetryStrategy.EXPONENTIAL, description="Backoff strategy")
59
+ base_delay: float = Field(default=1.0, ge=0.1, le=60.0, description="Base delay in seconds")
60
+ max_delay: float = Field(default=60.0, ge=1.0, le=300.0, description="Maximum delay in seconds")
61
+ jitter: bool = Field(default=True, description="Add random jitter to delays")
62
+ retryable_exceptions: List[str] = Field(
63
+ default_factory=lambda: ["ConnectionError", "TimeoutError", "HTTPError"],
64
+ description="Exception types that should trigger retry"
65
+ )
66
+
67
+
68
+ class BackoffCalculator(ABC):
69
+ """Abstract base for backoff calculation strategies."""
70
+
71
+ def __init__(self, config: RetryConfig):
72
+ self.config = config
73
+
74
+ @abstractmethod
75
+ def calculate_delay(self, attempt: int) -> float:
76
+ """Calculate delay for given attempt number."""
77
+ pass
78
+
79
+ def add_jitter(self, delay: float) -> float:
80
+ """Add random jitter to delay."""
81
+ if not self.config.jitter:
82
+ return delay
83
+
84
+ # Add ±25% jitter
85
+ jitter_range = delay * 0.25
86
+ jitter = random.uniform(-jitter_range, jitter_range)
87
+ return max(0.1, delay + jitter)
88
+
89
+
90
+ class ExponentialBackoff(BackoffCalculator):
91
+ """Exponential backoff strategy."""
92
+
93
+ def calculate_delay(self, attempt: int) -> float:
94
+ """Calculate exponential backoff delay."""
95
+ delay = self.config.base_delay * (2 ** (attempt - 1))
96
+ delay = min(delay, self.config.max_delay)
97
+ return self.add_jitter(delay)
98
+
99
+
100
+ class LinearBackoff(BackoffCalculator):
101
+ """Linear backoff strategy."""
102
+
103
+ def calculate_delay(self, attempt: int) -> float:
104
+ """Calculate linear backoff delay."""
105
+ delay = self.config.base_delay * attempt
106
+ delay = min(delay, self.config.max_delay)
107
+ return self.add_jitter(delay)
108
+
109
+
110
+ class FixedBackoff(BackoffCalculator):
111
+ """Fixed delay backoff strategy."""
112
+
113
+ def calculate_delay(self, attempt: int) -> float:
114
+ """Calculate fixed backoff delay."""
115
+ return self.add_jitter(self.config.base_delay)
116
+
117
+
118
+ def create_backoff_calculator(config: RetryConfig) -> BackoffCalculator:
119
+ """Factory function to create backoff calculator."""
120
+ if config.strategy == RetryStrategy.EXPONENTIAL:
121
+ return ExponentialBackoff(config)
122
+ elif config.strategy == RetryStrategy.LINEAR:
123
+ return LinearBackoff(config)
124
+ else:
125
+ return FixedBackoff(config)
126
+
127
+
128
+ def is_retryable_exception(
129
+ exception: Exception,
130
+ retryable_types: List[str]
131
+ ) -> bool:
132
+ """Check if exception is retryable."""
133
+ exception_name = exception.__class__.__name__
134
+ return exception_name in retryable_types
135
+
136
+
137
+ async def retry_async(
138
+ func: Callable[..., Any],
139
+ config: RetryConfig,
140
+ *args,
141
+ **kwargs
142
+ ) -> RetryResult:
143
+ """
144
+ Execute async function with retry logic.
145
+
146
+ Args:
147
+ func: Async function to execute
148
+ config: Retry configuration
149
+ *args, **kwargs: Function arguments
150
+
151
+ Returns:
152
+ RetryResult with operation outcome
153
+ """
154
+ start_time = utc_now()
155
+ backoff = create_backoff_calculator(config)
156
+ last_error = None
157
+
158
+ for attempt in range(1, config.max_attempts + 1):
159
+ try:
160
+ logger.debug(f"Attempt {attempt}/{config.max_attempts} for {func.__name__}")
161
+
162
+ result = await func(*args, **kwargs)
163
+
164
+ duration = (utc_now() - start_time).total_seconds()
165
+
166
+ if attempt > 1:
167
+ logger.info(f"{func.__name__} succeeded on attempt {attempt}")
168
+
169
+ return RetryResult(
170
+ success=True,
171
+ attempts=attempt,
172
+ total_duration=duration,
173
+ result=result
174
+ )
175
+
176
+ except Exception as e:
177
+ last_error = str(e)
178
+
179
+ if not is_retryable_exception(e, config.retryable_exceptions):
180
+ logger.error(f"{func.__name__} failed with non-retryable error: {e}")
181
+ break
182
+
183
+ if attempt < config.max_attempts:
184
+ delay = backoff.calculate_delay(attempt)
185
+ logger.warning(
186
+ f"{func.__name__} attempt {attempt} failed: {e}. "
187
+ f"Retrying in {delay:.2f}s..."
188
+ )
189
+ await asyncio.sleep(delay)
190
+ else:
191
+ logger.error(f"{func.__name__} failed after {attempt} attempts: {e}")
192
+
193
+ duration = (utc_now() - start_time).total_seconds()
194
+
195
+ return RetryResult(
196
+ success=False,
197
+ attempts=config.max_attempts,
198
+ total_duration=duration,
199
+ last_error=last_error
200
+ )
201
+
202
+
203
+ def retry_sync(
204
+ func: Callable[..., Any],
205
+ config: RetryConfig,
206
+ *args,
207
+ **kwargs
208
+ ) -> RetryResult:
209
+ """
210
+ Execute sync function with retry logic.
211
+
212
+ Args:
213
+ func: Sync function to execute
214
+ config: Retry configuration
215
+ *args, **kwargs: Function arguments
216
+
217
+ Returns:
218
+ RetryResult with operation outcome
219
+ """
220
+ import time
221
+
222
+ start_time = utc_now()
223
+ backoff = create_backoff_calculator(config)
224
+ last_error = None
225
+
226
+ for attempt in range(1, config.max_attempts + 1):
227
+ try:
228
+ logger.debug(f"Attempt {attempt}/{config.max_attempts} for {func.__name__}")
229
+
230
+ result = func(*args, **kwargs)
231
+
232
+ duration = (utc_now() - start_time).total_seconds()
233
+
234
+ if attempt > 1:
235
+ logger.info(f"{func.__name__} succeeded on attempt {attempt}")
236
+
237
+ return RetryResult(
238
+ success=True,
239
+ attempts=attempt,
240
+ total_duration=duration,
241
+ result=result
242
+ )
243
+
244
+ except Exception as e:
245
+ last_error = str(e)
246
+
247
+ if not is_retryable_exception(e, config.retryable_exceptions):
248
+ logger.error(f"{func.__name__} failed with non-retryable error: {e}")
249
+ break
250
+
251
+ if attempt < config.max_attempts:
252
+ delay = backoff.calculate_delay(attempt)
253
+ logger.warning(
254
+ f"{func.__name__} attempt {attempt} failed: {e}. "
255
+ f"Retrying in {delay:.2f}s..."
256
+ )
257
+ time.sleep(delay)
258
+ else:
259
+ logger.error(f"{func.__name__} failed after {attempt} attempts: {e}")
260
+
261
+ duration = (utc_now() - start_time).total_seconds()
262
+
263
+ return RetryResult(
264
+ success=False,
265
+ attempts=config.max_attempts,
266
+ total_duration=duration,
267
+ last_error=last_error
268
+ )
@@ -0,0 +1,46 @@
1
+ """
2
+ UnrealOn Core Exceptions
3
+
4
+ Custom exception hierarchy for the UnrealOn system.
5
+ Provides specific exceptions for different error conditions
6
+ with proper error codes and context information.
7
+
8
+ Phase 1: Foundation exceptions with proper hierarchy
9
+ """
10
+
11
+ from .base import UnrealOnError, UnrealOnWarning
12
+ from .validation import ValidationError, ConfigurationError
13
+ from .communication import CommunicationError, WebSocketError, RPCError
14
+ from .driver import DriverError, DriverNotFoundError, DriverTimeoutError
15
+ from .task import TaskError, TaskTimeoutError, TaskValidationError
16
+ from .proxy import ProxyError, ProxyNotAvailableError, ProxyTimeoutError
17
+
18
+ __all__ = [
19
+ # Base exceptions
20
+ "UnrealOnError",
21
+ "UnrealOnWarning",
22
+
23
+ # Validation exceptions
24
+ "ValidationError",
25
+ "ConfigurationError",
26
+
27
+ # Communication exceptions
28
+ "CommunicationError",
29
+ "WebSocketError",
30
+ "RPCError",
31
+
32
+ # Driver exceptions
33
+ "DriverError",
34
+ "DriverNotFoundError",
35
+ "DriverTimeoutError",
36
+
37
+ # Task exceptions
38
+ "TaskError",
39
+ "TaskTimeoutError",
40
+ "TaskValidationError",
41
+
42
+ # Proxy exceptions
43
+ "ProxyError",
44
+ "ProxyNotAvailableError",
45
+ "ProxyTimeoutError",
46
+ ]
@@ -0,0 +1,292 @@
1
+ """
2
+ Base exceptions for UnrealOn system.
3
+
4
+ Provides the foundation exception classes that all other
5
+ UnrealOn exceptions inherit from. Includes error codes,
6
+ context information, and structured error handling.
7
+
8
+ Phase 1: Foundation exception hierarchy
9
+ """
10
+
11
+ from typing import Optional, Dict, Any, Union
12
+ from unrealon_core.utils.time import utc_now
13
+
14
+ class UnrealOnError(Exception):
15
+ """
16
+ Base exception for all UnrealOn errors.
17
+
18
+ Provides:
19
+ - Error codes for programmatic handling
20
+ - Context information for debugging
21
+ - Structured error data
22
+ - Timestamp tracking
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ message: str,
28
+ error_code: Optional[str] = None,
29
+ context: Optional[Dict[str, Any]] = None,
30
+ cause: Optional[Exception] = None
31
+ ):
32
+ """
33
+ Initialize UnrealOn error.
34
+
35
+ Args:
36
+ message: Human-readable error message
37
+ error_code: Machine-readable error code
38
+ context: Additional context information
39
+ cause: Original exception that caused this error
40
+ """
41
+ super().__init__(message)
42
+ self.message = message
43
+ self.error_code = error_code or self._get_default_error_code()
44
+ self.context = context or {}
45
+ self.cause = cause
46
+ self.timestamp = utc_now()
47
+
48
+ # Set the cause for proper exception chaining
49
+ if cause:
50
+ self.__cause__ = cause
51
+
52
+ def _get_default_error_code(self) -> str:
53
+ """Get default error code based on exception class name."""
54
+ class_name = self.__class__.__name__
55
+ # Convert CamelCase to UPPER_SNAKE_CASE
56
+ import re
57
+ error_code = re.sub('([a-z0-9])([A-Z])', r'\1_\2', class_name).upper()
58
+ return error_code
59
+
60
+ def to_dict(self) -> Dict[str, Any]:
61
+ """Convert exception to dictionary for serialization."""
62
+ return {
63
+ 'error_type': self.__class__.__name__,
64
+ 'error_code': self.error_code,
65
+ 'message': self.message,
66
+ 'context': self.context,
67
+ 'timestamp': self.timestamp.isoformat(),
68
+ 'cause': str(self.cause) if self.cause else None
69
+ }
70
+
71
+ def add_context(self, key: str, value: Any) -> 'UnrealOnError':
72
+ """Add context information to the error."""
73
+ self.context[key] = value
74
+ return self
75
+
76
+ def with_context(self, **context) -> 'UnrealOnError':
77
+ """Add multiple context items to the error."""
78
+ self.context.update(context)
79
+ return self
80
+
81
+ def __str__(self) -> str:
82
+ """String representation of the error."""
83
+ parts = [f"[{self.error_code}] {self.message}"]
84
+
85
+ if self.context:
86
+ context_str = ", ".join(f"{k}={v}" for k, v in self.context.items())
87
+ parts.append(f"Context: {context_str}")
88
+
89
+ if self.cause:
90
+ parts.append(f"Caused by: {self.cause}")
91
+
92
+ return " | ".join(parts)
93
+
94
+ def __repr__(self) -> str:
95
+ """Detailed representation of the error."""
96
+ return (
97
+ f"{self.__class__.__name__}("
98
+ f"message='{self.message}', "
99
+ f"error_code='{self.error_code}', "
100
+ f"context={self.context}, "
101
+ f"cause={self.cause!r})"
102
+ )
103
+
104
+
105
+ class UnrealOnWarning(UserWarning):
106
+ """
107
+ Base warning for UnrealOn system.
108
+
109
+ Used for non-fatal issues that should be logged
110
+ but don't prevent operation from continuing.
111
+ """
112
+
113
+ def __init__(
114
+ self,
115
+ message: str,
116
+ warning_code: Optional[str] = None,
117
+ context: Optional[Dict[str, Any]] = None
118
+ ):
119
+ """
120
+ Initialize UnrealOn warning.
121
+
122
+ Args:
123
+ message: Human-readable warning message
124
+ warning_code: Machine-readable warning code
125
+ context: Additional context information
126
+ """
127
+ super().__init__(message)
128
+ self.message = message
129
+ self.warning_code = warning_code or self._get_default_warning_code()
130
+ self.context = context or {}
131
+ self.timestamp = utc_now()
132
+
133
+ def _get_default_warning_code(self) -> str:
134
+ """Get default warning code based on class name."""
135
+ class_name = self.__class__.__name__
136
+ import re
137
+ warning_code = re.sub('([a-z0-9])([A-Z])', r'\1_\2', class_name).upper()
138
+ return warning_code
139
+
140
+ def to_dict(self) -> Dict[str, Any]:
141
+ """Convert warning to dictionary for serialization."""
142
+ return {
143
+ 'warning_type': self.__class__.__name__,
144
+ 'warning_code': self.warning_code,
145
+ 'message': self.message,
146
+ 'context': self.context,
147
+ 'timestamp': self.timestamp.isoformat()
148
+ }
149
+
150
+
151
+ class UnrealOnTimeoutError(UnrealOnError):
152
+ """
153
+ Base timeout error for operations that exceed time limits.
154
+
155
+ Used when operations take longer than expected or configured
156
+ timeout values are exceeded.
157
+ """
158
+
159
+ def __init__(
160
+ self,
161
+ message: str,
162
+ timeout_seconds: Optional[float] = None,
163
+ operation: Optional[str] = None,
164
+ **kwargs
165
+ ):
166
+ """
167
+ Initialize timeout error.
168
+
169
+ Args:
170
+ message: Error message
171
+ timeout_seconds: The timeout value that was exceeded
172
+ operation: Name of the operation that timed out
173
+ **kwargs: Additional arguments for base class
174
+ """
175
+ super().__init__(message, **kwargs)
176
+
177
+ if timeout_seconds is not None:
178
+ self.add_context('timeout_seconds', timeout_seconds)
179
+
180
+ if operation:
181
+ self.add_context('operation', operation)
182
+
183
+
184
+ class UnrealOnConfigurationError(UnrealOnError):
185
+ """
186
+ Configuration-related errors.
187
+
188
+ Used when there are issues with system configuration,
189
+ invalid settings, or missing required configuration.
190
+ """
191
+
192
+ def __init__(
193
+ self,
194
+ message: str,
195
+ config_key: Optional[str] = None,
196
+ config_value: Optional[Any] = None,
197
+ **kwargs
198
+ ):
199
+ """
200
+ Initialize configuration error.
201
+
202
+ Args:
203
+ message: Error message
204
+ config_key: The configuration key that caused the error
205
+ config_value: The invalid configuration value
206
+ **kwargs: Additional arguments for base class
207
+ """
208
+ super().__init__(message, **kwargs)
209
+
210
+ if config_key:
211
+ self.add_context('config_key', config_key)
212
+
213
+ if config_value is not None:
214
+ self.add_context('config_value', str(config_value))
215
+
216
+
217
+ class UnrealOnRetryableError(UnrealOnError):
218
+ """
219
+ Base class for errors that can be retried.
220
+
221
+ Used for temporary failures that might succeed
222
+ if the operation is attempted again.
223
+ """
224
+
225
+ def __init__(
226
+ self,
227
+ message: str,
228
+ retry_after: Optional[float] = None,
229
+ max_retries: Optional[int] = None,
230
+ **kwargs
231
+ ):
232
+ """
233
+ Initialize retryable error.
234
+
235
+ Args:
236
+ message: Error message
237
+ retry_after: Suggested delay before retry (seconds)
238
+ max_retries: Maximum number of retries recommended
239
+ **kwargs: Additional arguments for base class
240
+ """
241
+ super().__init__(message, **kwargs)
242
+
243
+ if retry_after is not None:
244
+ self.add_context('retry_after', retry_after)
245
+
246
+ if max_retries is not None:
247
+ self.add_context('max_retries', max_retries)
248
+
249
+ def should_retry(self, attempt_count: int) -> bool:
250
+ """
251
+ Check if the operation should be retried.
252
+
253
+ Args:
254
+ attempt_count: Number of attempts already made
255
+
256
+ Returns:
257
+ True if retry should be attempted
258
+ """
259
+ max_retries = self.context.get('max_retries')
260
+ if max_retries is None:
261
+ return True # No limit specified
262
+
263
+ return attempt_count < max_retries
264
+
265
+ def get_retry_delay(self, attempt_count: int) -> float:
266
+ """
267
+ Get suggested delay before retry.
268
+
269
+ Args:
270
+ attempt_count: Number of attempts already made
271
+
272
+ Returns:
273
+ Delay in seconds
274
+ """
275
+ base_delay = self.context.get('retry_after', 1.0)
276
+
277
+ # Exponential backoff: delay = base_delay * (2 ^ attempt_count)
278
+ return base_delay * (2 ** min(attempt_count, 6)) # Cap at 2^6 = 64x
279
+
280
+
281
+ class UnrealOnFatalError(UnrealOnError):
282
+ """
283
+ Fatal errors that should stop system operation.
284
+
285
+ Used for critical errors that indicate the system
286
+ cannot continue operating safely.
287
+ """
288
+
289
+ def __init__(self, message: str, **kwargs):
290
+ """Initialize fatal error."""
291
+ super().__init__(message, **kwargs)
292
+ self.add_context('fatal', True)
@@ -0,0 +1,22 @@
1
+ """
2
+ Communication exceptions for UnrealOn system.
3
+
4
+ Phase 1: Basic communication exceptions
5
+ """
6
+
7
+ from .base import UnrealOnError, UnrealOnTimeoutError
8
+
9
+
10
+ class CommunicationError(UnrealOnError):
11
+ """Base communication error."""
12
+ pass
13
+
14
+
15
+ class WebSocketError(CommunicationError):
16
+ """WebSocket communication error."""
17
+ pass
18
+
19
+
20
+ class RPCError(CommunicationError):
21
+ """RPC communication error."""
22
+ pass
@@ -0,0 +1,11 @@
1
+ """Driver exceptions - Phase 1 stubs."""
2
+ from .base import UnrealOnError, UnrealOnTimeoutError
3
+
4
+ class DriverError(UnrealOnError):
5
+ pass
6
+
7
+ class DriverNotFoundError(DriverError):
8
+ pass
9
+
10
+ class DriverTimeoutError(UnrealOnTimeoutError):
11
+ pass
@@ -0,0 +1,11 @@
1
+ """Proxy exceptions - Phase 1 stubs."""
2
+ from .base import UnrealOnError, UnrealOnTimeoutError
3
+
4
+ class ProxyError(UnrealOnError):
5
+ pass
6
+
7
+ class ProxyNotAvailableError(ProxyError):
8
+ pass
9
+
10
+ class ProxyTimeoutError(UnrealOnTimeoutError):
11
+ pass
@@ -0,0 +1,12 @@
1
+ """Task exceptions - Phase 1 stubs."""
2
+ from .base import UnrealOnError, UnrealOnTimeoutError
3
+ from .validation import ValidationError
4
+
5
+ class TaskError(UnrealOnError):
6
+ pass
7
+
8
+ class TaskTimeoutError(UnrealOnTimeoutError):
9
+ pass
10
+
11
+ class TaskValidationError(ValidationError):
12
+ pass
@@ -0,0 +1,17 @@
1
+ """
2
+ Validation exceptions for UnrealOn system.
3
+
4
+ Phase 1: Basic validation exceptions
5
+ """
6
+
7
+ from .base import UnrealOnError, UnrealOnConfigurationError
8
+
9
+
10
+ class ValidationError(UnrealOnError):
11
+ """Validation error for invalid data."""
12
+ pass
13
+
14
+
15
+ class ConfigurationError(UnrealOnConfigurationError):
16
+ """Configuration validation error."""
17
+ pass