wappa 0.1.9__py3-none-any.whl → 0.1.10__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.

Potentially problematic release.


This version of wappa might be problematic. Click here for more details.

Files changed (126) hide show
  1. wappa/__init__.py +4 -5
  2. wappa/api/controllers/webhook_controller.py +5 -2
  3. wappa/api/dependencies/__init__.py +0 -5
  4. wappa/api/middleware/error_handler.py +4 -4
  5. wappa/api/middleware/owner.py +11 -5
  6. wappa/api/routes/webhooks.py +2 -2
  7. wappa/cli/__init__.py +1 -1
  8. wappa/cli/examples/init/app/main.py +2 -1
  9. wappa/cli/examples/init/app/master_event.py +5 -3
  10. wappa/cli/examples/json_cache_example/app/__init__.py +1 -1
  11. wappa/cli/examples/json_cache_example/app/main.py +56 -44
  12. wappa/cli/examples/json_cache_example/app/master_event.py +181 -145
  13. wappa/cli/examples/json_cache_example/app/models/__init__.py +1 -1
  14. wappa/cli/examples/json_cache_example/app/models/json_demo_models.py +32 -51
  15. wappa/cli/examples/json_cache_example/app/scores/__init__.py +2 -2
  16. wappa/cli/examples/json_cache_example/app/scores/score_base.py +52 -46
  17. wappa/cli/examples/json_cache_example/app/scores/score_cache_statistics.py +70 -62
  18. wappa/cli/examples/json_cache_example/app/scores/score_message_history.py +41 -44
  19. wappa/cli/examples/json_cache_example/app/scores/score_state_commands.py +83 -71
  20. wappa/cli/examples/json_cache_example/app/scores/score_user_management.py +73 -57
  21. wappa/cli/examples/json_cache_example/app/utils/__init__.py +2 -2
  22. wappa/cli/examples/json_cache_example/app/utils/cache_utils.py +54 -56
  23. wappa/cli/examples/json_cache_example/app/utils/message_utils.py +85 -80
  24. wappa/cli/examples/openai_transcript/app/main.py +2 -1
  25. wappa/cli/examples/openai_transcript/app/master_event.py +31 -22
  26. wappa/cli/examples/openai_transcript/app/openai_utils/__init__.py +1 -1
  27. wappa/cli/examples/openai_transcript/app/openai_utils/audio_processing.py +37 -24
  28. wappa/cli/examples/redis_cache_example/app/__init__.py +1 -1
  29. wappa/cli/examples/redis_cache_example/app/main.py +56 -44
  30. wappa/cli/examples/redis_cache_example/app/master_event.py +181 -145
  31. wappa/cli/examples/redis_cache_example/app/models/redis_demo_models.py +31 -50
  32. wappa/cli/examples/redis_cache_example/app/scores/__init__.py +2 -2
  33. wappa/cli/examples/redis_cache_example/app/scores/score_base.py +52 -46
  34. wappa/cli/examples/redis_cache_example/app/scores/score_cache_statistics.py +70 -62
  35. wappa/cli/examples/redis_cache_example/app/scores/score_message_history.py +41 -44
  36. wappa/cli/examples/redis_cache_example/app/scores/score_state_commands.py +83 -71
  37. wappa/cli/examples/redis_cache_example/app/scores/score_user_management.py +73 -57
  38. wappa/cli/examples/redis_cache_example/app/utils/__init__.py +2 -2
  39. wappa/cli/examples/redis_cache_example/app/utils/cache_utils.py +54 -56
  40. wappa/cli/examples/redis_cache_example/app/utils/message_utils.py +85 -80
  41. wappa/cli/examples/simple_echo_example/app/__init__.py +1 -1
  42. wappa/cli/examples/simple_echo_example/app/main.py +41 -33
  43. wappa/cli/examples/simple_echo_example/app/master_event.py +78 -57
  44. wappa/cli/examples/wappa_full_example/app/__init__.py +1 -1
  45. wappa/cli/examples/wappa_full_example/app/handlers/__init__.py +1 -1
  46. wappa/cli/examples/wappa_full_example/app/handlers/command_handlers.py +134 -126
  47. wappa/cli/examples/wappa_full_example/app/handlers/message_handlers.py +237 -229
  48. wappa/cli/examples/wappa_full_example/app/handlers/state_handlers.py +170 -148
  49. wappa/cli/examples/wappa_full_example/app/main.py +51 -39
  50. wappa/cli/examples/wappa_full_example/app/master_event.py +179 -120
  51. wappa/cli/examples/wappa_full_example/app/models/__init__.py +1 -1
  52. wappa/cli/examples/wappa_full_example/app/models/state_models.py +113 -104
  53. wappa/cli/examples/wappa_full_example/app/models/user_models.py +92 -76
  54. wappa/cli/examples/wappa_full_example/app/models/webhook_metadata.py +109 -83
  55. wappa/cli/examples/wappa_full_example/app/utils/__init__.py +1 -1
  56. wappa/cli/examples/wappa_full_example/app/utils/cache_utils.py +132 -113
  57. wappa/cli/examples/wappa_full_example/app/utils/media_handler.py +175 -132
  58. wappa/cli/examples/wappa_full_example/app/utils/metadata_extractor.py +126 -87
  59. wappa/cli/main.py +9 -4
  60. wappa/core/__init__.py +18 -23
  61. wappa/core/config/settings.py +7 -5
  62. wappa/core/events/default_handlers.py +1 -1
  63. wappa/core/factory/wappa_builder.py +38 -25
  64. wappa/core/plugins/redis_plugin.py +1 -3
  65. wappa/core/plugins/wappa_core_plugin.py +7 -6
  66. wappa/core/types.py +12 -12
  67. wappa/core/wappa_app.py +10 -8
  68. wappa/database/__init__.py +3 -4
  69. wappa/domain/enums/messenger_platform.py +1 -2
  70. wappa/domain/factories/media_factory.py +5 -20
  71. wappa/domain/factories/message_factory.py +5 -20
  72. wappa/domain/factories/messenger_factory.py +2 -4
  73. wappa/domain/interfaces/cache_interface.py +7 -7
  74. wappa/domain/interfaces/media_interface.py +2 -5
  75. wappa/domain/models/media_result.py +1 -3
  76. wappa/domain/models/platforms/platform_config.py +1 -3
  77. wappa/messaging/__init__.py +9 -12
  78. wappa/messaging/whatsapp/handlers/whatsapp_media_handler.py +20 -22
  79. wappa/models/__init__.py +27 -35
  80. wappa/persistence/__init__.py +12 -15
  81. wappa/persistence/cache_factory.py +0 -1
  82. wappa/persistence/json/__init__.py +1 -1
  83. wappa/persistence/json/cache_adapters.py +37 -25
  84. wappa/persistence/json/handlers/state_handler.py +60 -52
  85. wappa/persistence/json/handlers/table_handler.py +51 -49
  86. wappa/persistence/json/handlers/user_handler.py +71 -55
  87. wappa/persistence/json/handlers/utils/file_manager.py +42 -39
  88. wappa/persistence/json/handlers/utils/key_factory.py +1 -1
  89. wappa/persistence/json/handlers/utils/serialization.py +13 -11
  90. wappa/persistence/json/json_cache_factory.py +4 -8
  91. wappa/persistence/json/storage_manager.py +66 -79
  92. wappa/persistence/memory/__init__.py +1 -1
  93. wappa/persistence/memory/cache_adapters.py +37 -25
  94. wappa/persistence/memory/handlers/state_handler.py +62 -52
  95. wappa/persistence/memory/handlers/table_handler.py +59 -53
  96. wappa/persistence/memory/handlers/user_handler.py +75 -55
  97. wappa/persistence/memory/handlers/utils/key_factory.py +1 -1
  98. wappa/persistence/memory/handlers/utils/memory_store.py +75 -71
  99. wappa/persistence/memory/handlers/utils/ttl_manager.py +59 -67
  100. wappa/persistence/memory/memory_cache_factory.py +3 -7
  101. wappa/persistence/memory/storage_manager.py +52 -62
  102. wappa/persistence/redis/cache_adapters.py +27 -21
  103. wappa/persistence/redis/ops.py +11 -11
  104. wappa/persistence/redis/redis_client.py +4 -6
  105. wappa/persistence/redis/redis_manager.py +12 -4
  106. wappa/processors/factory.py +5 -5
  107. wappa/schemas/factory.py +2 -5
  108. wappa/schemas/whatsapp/message_types/errors.py +3 -12
  109. wappa/schemas/whatsapp/validators.py +3 -3
  110. wappa/webhooks/__init__.py +17 -18
  111. wappa/webhooks/factory.py +3 -5
  112. wappa/webhooks/whatsapp/__init__.py +10 -13
  113. wappa/webhooks/whatsapp/message_types/audio.py +0 -4
  114. wappa/webhooks/whatsapp/message_types/document.py +1 -9
  115. wappa/webhooks/whatsapp/message_types/errors.py +3 -12
  116. wappa/webhooks/whatsapp/message_types/location.py +1 -21
  117. wappa/webhooks/whatsapp/message_types/sticker.py +1 -5
  118. wappa/webhooks/whatsapp/message_types/text.py +0 -6
  119. wappa/webhooks/whatsapp/message_types/video.py +1 -20
  120. wappa/webhooks/whatsapp/status_models.py +2 -2
  121. wappa/webhooks/whatsapp/validators.py +3 -3
  122. {wappa-0.1.9.dist-info → wappa-0.1.10.dist-info}/METADATA +362 -8
  123. {wappa-0.1.9.dist-info → wappa-0.1.10.dist-info}/RECORD +126 -126
  124. {wappa-0.1.9.dist-info → wappa-0.1.10.dist-info}/WHEEL +0 -0
  125. {wappa-0.1.9.dist-info → wappa-0.1.10.dist-info}/entry_points.txt +0 -0
  126. {wappa-0.1.9.dist-info → wappa-0.1.10.dist-info}/licenses/LICENSE +0 -0
@@ -11,80 +11,82 @@ This module defines the main WappaEventHandler that:
11
11
  - Follows Dependency Inversion with injected dependencies
12
12
  """
13
13
 
14
- import logging
15
- from typing import Any, Dict
14
+ from typing import Any
16
15
 
17
- from .scores import AVAILABLE_SCORES, ScoreBase, ScoreDependencies
18
- from .scores.score_base import ScoreRegistry
19
- from .utils.message_utils import extract_user_data, sanitize_message_text
20
16
  from wappa import WappaEventHandler
21
17
  from wappa.webhooks import ErrorWebhook, IncomingMessageWebhook, StatusWebhook
22
18
 
19
+ from .scores import AVAILABLE_SCORES, ScoreDependencies
20
+ from .scores.score_base import ScoreRegistry
21
+ from .utils.message_utils import extract_user_data, sanitize_message_text
22
+
23
23
 
24
24
  class JSONCacheExampleHandler(WappaEventHandler):
25
25
  """
26
26
  Main WappaEventHandler implementation for JSON cache example following SOLID principles.
27
-
27
+
28
28
  This handler serves as the main entry point for the Wappa framework and demonstrates:
29
29
  - Proper WappaEventHandler method implementations
30
30
  - SOLID architecture with score module orchestration
31
31
  - Dependency injection and lifecycle management
32
32
  - Professional error handling and logging
33
33
  """
34
-
34
+
35
35
  def __init__(self):
36
36
  """Initialize the JSON cache example handler."""
37
37
  super().__init__()
38
-
38
+
39
39
  # Score module registry (following Open/Closed Principle)
40
40
  self.score_registry = ScoreRegistry()
41
-
41
+
42
42
  # Processing statistics
43
43
  self._total_messages = 0
44
44
  self._successful_processing = 0
45
45
  self._failed_processing = 0
46
-
46
+
47
47
  # Master handler state
48
48
  self._initialized = False
49
-
50
- self.logger.info("🎯 JSONCacheExampleHandler initialized - ready for SOLID architecture setup")
51
-
49
+
50
+ self.logger.info(
51
+ "🎯 JSONCacheExampleHandler initialized - ready for SOLID architecture setup"
52
+ )
53
+
52
54
  async def process_message(self, webhook: IncomingMessageWebhook) -> None:
53
55
  """
54
56
  Main message processing method required by WappaEventHandler.
55
-
57
+
56
58
  This method orchestrates score modules following SOLID principles and
57
59
  demonstrates proper webhook processing with dependency injection.
58
-
60
+
59
61
  Args:
60
62
  webhook: Incoming message webhook to process
61
63
  """
62
64
  self._total_messages += 1
63
65
  start_time = self._get_current_timestamp()
64
-
66
+
65
67
  try:
66
68
  # Initialize SOLID architecture on first message if not already done
67
69
  if not self._initialized:
68
70
  await self._initialize_solid_architecture()
69
-
71
+
70
72
  # Extract basic user information for logging
71
73
  user_data = extract_user_data(webhook)
72
- user_id = user_data['user_id']
74
+ user_id = user_data["user_id"]
73
75
  message_text = webhook.get_message_text() or "[NON-TEXT MESSAGE]"
74
-
76
+
75
77
  self.logger.info(
76
78
  f"📨 Processing message from {user_id}: "
77
79
  f"{sanitize_message_text(message_text)[:50]}..."
78
80
  )
79
-
81
+
80
82
  # Execute score module processing pipeline
81
83
  processing_result = await self._execute_score_pipeline(webhook)
82
-
84
+
83
85
  # Record processing results
84
- if processing_result['success']:
86
+ if processing_result["success"]:
85
87
  self._successful_processing += 1
86
88
  processing_time = self._get_current_timestamp() - start_time
87
-
89
+
88
90
  self.logger.info(
89
91
  f"✅ Message processed successfully in {processing_time:.2f}s "
90
92
  f"(processed by {processing_result['processed_count']} score modules)"
@@ -95,89 +97,99 @@ class JSONCacheExampleHandler(WappaEventHandler):
95
97
  f"⚠️ Message processing completed with issues: "
96
98
  f"{processing_result.get('error', 'Unknown error')}"
97
99
  )
98
-
100
+
99
101
  # Send fallback response to user
100
- await self._send_error_response(webhook, processing_result.get('error', 'Processing error'))
101
-
102
+ await self._send_error_response(
103
+ webhook, processing_result.get("error", "Processing error")
104
+ )
105
+
102
106
  except Exception as e:
103
107
  self._failed_processing += 1
104
- self.logger.error(f"❌ Critical error in message processing: {e}", exc_info=True)
108
+ self.logger.error(
109
+ f"❌ Critical error in message processing: {e}", exc_info=True
110
+ )
105
111
  await self._send_error_response(webhook, f"System error: {str(e)}")
106
-
112
+
107
113
  async def process_status(self, webhook: StatusWebhook) -> None:
108
114
  """
109
115
  Process status webhooks from WhatsApp Business API.
110
-
116
+
111
117
  Args:
112
118
  webhook: Status webhook containing delivery status information
113
119
  """
114
120
  try:
115
121
  status_value = webhook.status.value
116
122
  recipient = webhook.recipient_id
117
-
118
- self.logger.info(f"📊 Message status: {status_value.upper()} for {recipient}")
119
-
123
+
124
+ self.logger.info(
125
+ f"📊 Message status: {status_value.upper()} for {recipient}"
126
+ )
127
+
120
128
  # You can add custom status processing logic here
121
129
  # For example, updating delivery statistics or handling failed deliveries
122
-
130
+
123
131
  except Exception as e:
124
132
  self.logger.error(f"❌ Error processing status webhook: {e}", exc_info=True)
125
-
133
+
126
134
  async def process_error(self, webhook: ErrorWebhook) -> None:
127
135
  """
128
136
  Process error webhooks from WhatsApp Business API.
129
-
137
+
130
138
  Args:
131
139
  webhook: Error webhook containing error information
132
140
  """
133
141
  try:
134
142
  error_count = webhook.get_error_count()
135
143
  primary_error = webhook.get_primary_error()
136
-
144
+
137
145
  self.logger.error(
138
146
  f"🚨 WhatsApp API error: {error_count} errors, "
139
147
  f"primary: {primary_error.error_code} - {primary_error.error_title}"
140
148
  )
141
-
149
+
142
150
  # Record error in statistics
143
151
  self._failed_processing += 1
144
-
152
+
145
153
  # You can add custom error handling logic here
146
154
  # For example, alerting systems or retry mechanisms
147
-
155
+
148
156
  except Exception as e:
149
157
  self.logger.error(f"❌ Error processing error webhook: {e}", exc_info=True)
150
-
158
+
151
159
  async def _initialize_solid_architecture(self) -> None:
152
160
  """
153
161
  Initialize SOLID architecture with score modules and dependency injection.
154
-
162
+
155
163
  This method demonstrates Dependency Inversion Principle by injecting
156
164
  abstractions and follows Single Responsibility Principle.
157
165
  """
158
166
  try:
159
167
  if not self.validate_dependencies():
160
- self.logger.error("❌ Dependencies not properly injected - cannot initialize SOLID architecture")
168
+ self.logger.error(
169
+ "❌ Dependencies not properly injected - cannot initialize SOLID architecture"
170
+ )
161
171
  return
162
-
172
+
163
173
  if not self.cache_factory:
164
- self.logger.error("❌ Cache factory not available - cannot initialize SOLID architecture")
174
+ self.logger.error(
175
+ "❌ Cache factory not available - cannot initialize SOLID architecture"
176
+ )
165
177
  return
166
-
178
+
167
179
  # Create cache instances from factory (Dependency Inversion)
168
180
  user_cache = self.cache_factory.create_user_cache()
169
181
  table_cache = self.cache_factory.create_table_cache()
170
182
  state_cache = self.cache_factory.create_state_cache()
171
-
183
+
172
184
  # Create dependencies container
173
185
  dependencies = ScoreDependencies(
174
- messenger=self.messenger,
186
+ messenger=self.messenger,
175
187
  user_cache=user_cache,
176
188
  table_cache=table_cache,
177
189
  state_cache=state_cache,
178
- logger=self.logger
190
+ logger=self.logger,
179
191
  )
180
-
192
+
181
193
  # Auto-register all available score modules (Open/Closed Principle)
182
194
  registered_count = 0
183
195
  for score_class in AVAILABLE_SCORES:
@@ -186,142 +198,162 @@ class JSONCacheExampleHandler(WappaEventHandler):
186
198
  score_instance = score_class(dependencies)
187
199
  self.score_registry.register_score(score_instance)
188
200
  registered_count += 1
189
-
201
+
190
202
  self.logger.info(
191
203
  f"✅ Registered score module: {score_instance.score_name}"
192
204
  )
193
-
205
+
194
206
  except Exception as e:
195
207
  self.logger.error(
196
208
  f"❌ Failed to register {score_class.__name__}: {e}"
197
209
  )
198
-
210
+
199
211
  self._initialized = True
200
212
  self.logger.info(
201
213
  f"🎯 SOLID architecture initialized successfully: {registered_count} score modules registered"
202
214
  )
203
-
215
+
204
216
  except Exception as e:
205
- self.logger.error(f"❌ Critical error initializing SOLID architecture: {e}", exc_info=True)
217
+ self.logger.error(
218
+ f"❌ Critical error initializing SOLID architecture: {e}", exc_info=True
219
+ )
206
220
  raise
207
-
208
- async def _execute_score_pipeline(self, webhook: IncomingMessageWebhook) -> Dict[str, Any]:
221
+
222
+ async def _execute_score_pipeline(
223
+ self, webhook: IncomingMessageWebhook
224
+ ) -> dict[str, Any]:
209
225
  """
210
226
  Execute the score module processing pipeline.
211
-
227
+
212
228
  Processes webhook through all applicable score modules following
213
229
  the Chain of Responsibility pattern.
214
-
230
+
215
231
  Args:
216
232
  webhook: Webhook to process
217
-
233
+
218
234
  Returns:
219
235
  Processing result with success status and metadata
220
236
  """
221
237
  try:
222
238
  if not self._initialized:
223
239
  return {
224
- 'success': False,
225
- 'error': 'SOLID architecture not initialized',
226
- 'processed_count': 0
240
+ "success": False,
241
+ "error": "SOLID architecture not initialized",
242
+ "processed_count": 0,
227
243
  }
228
-
244
+
229
245
  scores = self.score_registry.get_scores()
230
246
  processed_count = 0
231
247
  processing_errors = []
232
-
248
+
233
249
  # Process webhook through all applicable score modules
234
250
  for score in scores:
235
251
  try:
236
252
  # Check if score can handle this webhook (Interface Segregation)
237
253
  can_handle = await score.can_handle(webhook)
238
-
254
+
239
255
  if can_handle:
240
256
  self.logger.debug(f"🎯 Processing with {score.score_name}")
241
-
257
+
242
258
  # Process with the score module
243
259
  success = await score.process(webhook)
244
-
260
+
245
261
  if success:
246
262
  processed_count += 1
247
- self.logger.debug(f"✅ {score.score_name} completed successfully")
263
+ self.logger.debug(
264
+ f"✅ {score.score_name} completed successfully"
265
+ )
248
266
  else:
249
- processing_errors.append(f"{score.score_name}: Processing failed")
250
- self.logger.warning(f"⚠️ {score.score_name} reported processing failure")
267
+ processing_errors.append(
268
+ f"{score.score_name}: Processing failed"
269
+ )
270
+ self.logger.warning(
271
+ f"⚠️ {score.score_name} reported processing failure"
272
+ )
251
273
  else:
252
- self.logger.debug(f"⏭️ {score.score_name} skipped (cannot handle this webhook)")
253
-
274
+ self.logger.debug(
275
+ f"⏭️ {score.score_name} skipped (cannot handle this webhook)"
276
+ )
277
+
254
278
  except Exception as score_error:
255
279
  processing_errors.append(f"{score.score_name}: {str(score_error)}")
256
280
  self.logger.error(
257
- f"❌ Error in {score.score_name}: {score_error}",
258
- exc_info=True
281
+ f"❌ Error in {score.score_name}: {score_error}", exc_info=True
259
282
  )
260
-
283
+
261
284
  # Determine overall success
262
285
  overall_success = processed_count > 0 and len(processing_errors) == 0
263
-
286
+
264
287
  return {
265
- 'success': overall_success,
266
- 'processed_count': processed_count,
267
- 'total_scores': len(scores),
268
- 'errors': processing_errors if processing_errors else None,
269
- 'message': (
288
+ "success": overall_success,
289
+ "processed_count": processed_count,
290
+ "total_scores": len(scores),
291
+ "errors": processing_errors if processing_errors else None,
292
+ "message": (
270
293
  f"Processed by {processed_count}/{len(scores)} score modules"
271
- + (f" with {len(processing_errors)} errors" if processing_errors else "")
272
- )
294
+ + (
295
+ f" with {len(processing_errors)} errors"
296
+ if processing_errors
297
+ else ""
298
+ )
299
+ ),
273
300
  }
274
-
301
+
275
302
  except Exception as e:
276
- self.logger.error(f"❌ Critical error in score pipeline: {e}", exc_info=True)
303
+ self.logger.error(
304
+ f"❌ Critical error in score pipeline: {e}", exc_info=True
305
+ )
277
306
  return {
278
- 'success': False,
279
- 'processed_count': 0,
280
- 'error': f"Pipeline error: {str(e)}"
307
+ "success": False,
308
+ "processed_count": 0,
309
+ "error": f"Pipeline error: {str(e)}",
281
310
  }
282
-
283
- async def _send_error_response(self, webhook: IncomingMessageWebhook, error_details: str) -> None:
311
+
312
+ async def _send_error_response(
313
+ self, webhook: IncomingMessageWebhook, error_details: str
314
+ ) -> None:
284
315
  """
285
316
  Send user-friendly error response when processing fails.
286
-
317
+
287
318
  Args:
288
319
  webhook: Original webhook that failed to process
289
320
  error_details: Details about the error for logging
290
321
  """
291
322
  try:
292
323
  user_data = extract_user_data(webhook)
293
- user_id = user_data['user_id']
294
-
324
+ user_id = user_data["user_id"]
325
+
295
326
  error_message = (
296
327
  "🚨 SOLID JSON Cache Example\n\n"
297
328
  "❌ An error occurred while processing your message.\n"
298
329
  "Our team has been notified and will resolve this issue soon.\n\n"
299
330
  "Please try again later or contact support if the problem persists."
300
331
  )
301
-
332
+
302
333
  result = await self.messenger.send_text(
303
334
  recipient=user_id,
304
335
  text=error_message,
305
- reply_to_message_id=webhook.message.message_id
336
+ reply_to_message_id=webhook.message.message_id,
306
337
  )
307
-
338
+
308
339
  if result.success:
309
340
  self.logger.info(f"🚨 Error response sent to {user_id}")
310
341
  else:
311
342
  self.logger.error(f"❌ Failed to send error response: {result.error}")
312
-
343
+
313
344
  except Exception as e:
314
345
  self.logger.error(f"❌ Error sending error response: {e}")
315
-
346
+
316
347
  def _get_current_timestamp(self) -> float:
317
348
  """Get current timestamp for performance measurement."""
318
349
  import time
350
+
319
351
  return time.time()
320
-
321
- async def get_handler_statistics(self) -> Dict[str, Any]:
352
+
353
+ async def get_handler_statistics(self) -> dict[str, Any]:
322
354
  """
323
355
  Get comprehensive handler and score module statistics.
324
-
356
+
325
357
  Returns:
326
358
  Dictionary with processing statistics and score module metrics
327
359
  """
@@ -329,58 +361,63 @@ class JSONCacheExampleHandler(WappaEventHandler):
329
361
  # Calculate success rate
330
362
  success_rate = (
331
363
  (self._successful_processing / self._total_messages)
332
- if self._total_messages > 0 else 0.0
364
+ if self._total_messages > 0
365
+ else 0.0
333
366
  )
334
-
367
+
335
368
  # Get score-specific statistics if initialized
336
369
  score_stats = {}
337
370
  if self._initialized:
338
371
  score_stats = self.score_registry.get_score_stats()
339
-
372
+
340
373
  return {
341
- 'handler_status': 'initialized' if self._initialized else 'pending_initialization',
342
- 'total_messages': self._total_messages,
343
- 'successful_processing': self._successful_processing,
344
- 'failed_processing': self._failed_processing,
345
- 'success_rate': success_rate,
346
- 'registered_scores': len(self.score_registry.get_scores()) if self._initialized else 0,
347
- 'score_modules': score_stats
374
+ "handler_status": "initialized"
375
+ if self._initialized
376
+ else "pending_initialization",
377
+ "total_messages": self._total_messages,
378
+ "successful_processing": self._successful_processing,
379
+ "failed_processing": self._failed_processing,
380
+ "success_rate": success_rate,
381
+ "registered_scores": len(self.score_registry.get_scores())
382
+ if self._initialized
383
+ else 0,
384
+ "score_modules": score_stats,
348
385
  }
349
-
386
+
350
387
  except Exception as e:
351
388
  self.logger.error(f"❌ Error collecting handler statistics: {e}")
352
- return {
353
- 'error': f"Statistics collection failed: {str(e)}"
354
- }
355
-
356
- async def validate_system_health(self) -> Dict[str, Any]:
389
+ return {"error": f"Statistics collection failed: {str(e)}"}
390
+
391
+ async def validate_system_health(self) -> dict[str, Any]:
357
392
  """
358
393
  Validate system health including all score modules and dependencies.
359
-
394
+
360
395
  Returns:
361
396
  Health check results for the entire system
362
397
  """
363
398
  try:
364
399
  health_results = {
365
- 'overall_healthy': True,
366
- 'initialized': self._initialized,
367
- 'components': {},
368
- 'registered_scores': len(self.score_registry.get_scores()) if self._initialized else 0
400
+ "overall_healthy": True,
401
+ "initialized": self._initialized,
402
+ "components": {},
403
+ "registered_scores": len(self.score_registry.get_scores())
404
+ if self._initialized
405
+ else 0,
369
406
  }
370
-
407
+
371
408
  # Check core dependencies
372
409
  core_components = {
373
- 'messenger': self.messenger,
374
- 'cache_factory': self.cache_factory
410
+ "messenger": self.messenger,
411
+ "cache_factory": self.cache_factory,
375
412
  }
376
-
413
+
377
414
  for component_name, component in core_components.items():
378
415
  if component is not None:
379
- health_results['components'][component_name] = 'Available'
416
+ health_results["components"][component_name] = "Available"
380
417
  else:
381
- health_results['components'][component_name] = 'Missing'
382
- health_results['overall_healthy'] = False
383
-
418
+ health_results["components"][component_name] = "Missing"
419
+ health_results["overall_healthy"] = False
420
+
384
421
  # Check score modules if initialized
385
422
  if self._initialized:
386
423
  scores = self.score_registry.get_scores()
@@ -388,32 +425,31 @@ class JSONCacheExampleHandler(WappaEventHandler):
388
425
  try:
389
426
  # Basic validation check
390
427
  is_valid = await score.validate_dependencies()
391
- health_results['components'][score.score_name] = (
392
- 'Healthy' if is_valid else 'Dependency Issues'
428
+ health_results["components"][score.score_name] = (
429
+ "Healthy" if is_valid else "Dependency Issues"
393
430
  )
394
431
  if not is_valid:
395
- health_results['overall_healthy'] = False
396
-
432
+ health_results["overall_healthy"] = False
433
+
397
434
  except Exception as e:
398
- health_results['components'][score.score_name] = f'Error: {str(e)}'
399
- health_results['overall_healthy'] = False
400
-
435
+ health_results["components"][score.score_name] = (
436
+ f"Error: {str(e)}"
437
+ )
438
+ health_results["overall_healthy"] = False
439
+
401
440
  return health_results
402
-
441
+
403
442
  except Exception as e:
404
443
  self.logger.error(f"❌ Error validating system health: {e}")
405
- return {
406
- 'overall_healthy': False,
407
- 'error': f"Health check failed: {str(e)}"
408
- }
409
-
444
+ return {"overall_healthy": False, "error": f"Health check failed: {str(e)}"}
445
+
410
446
  def __str__(self) -> str:
411
447
  """String representation of the handler."""
412
448
  return (
413
449
  f"JSONCacheExampleHandler("
414
450
  f"messages={self._total_messages}, "
415
- f"success_rate={self._successful_processing/max(1, self._total_messages):.2%}, "
451
+ f"success_rate={self._successful_processing / max(1, self._total_messages):.2%}, "
416
452
  f"scores={len(self.score_registry.get_scores()) if self._initialized else 'pending'}, "
417
453
  f"initialized={self._initialized}"
418
454
  f")"
419
- )
455
+ )
@@ -1 +1 @@
1
- """JSON cache example models package."""
1
+ """JSON cache example models package."""