mc5-api-client 1.0.16__py3-none-any.whl → 1.0.18__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,259 @@
1
+ #!/usr/bin/env python3
2
+ # ────────────[ CHIZOBA ]────────────────────────────
3
+ # | Email : chizoba2026@hotmail.com
4
+ # | File : debug.py
5
+ # | License | MIT License © 2026 Chizoba
6
+ # | Brief | Enhanced debugging utilities for MC5 API Client
7
+ # ────────────────★─────────────────────────────────
8
+
9
+ import sys
10
+ import traceback
11
+ import json
12
+ from typing import Optional, Dict, Any, Callable
13
+ from datetime import datetime
14
+ from .telemetry import is_telemetry_enabled, report_error
15
+
16
+ class DebugContext:
17
+ """Context manager for debugging function calls."""
18
+
19
+ def __init__(self, function_name: str, **kwargs):
20
+ self.function_name = function_name
21
+ self.kwargs = kwargs
22
+ self.start_time = None
23
+
24
+ def __enter__(self):
25
+ self.start_time = datetime.now()
26
+ # if is_telemetry_enabled():
27
+ # print(f"🔍 Debug: Starting {self.function_name}")
28
+ # if self.kwargs:
29
+ # print(f"🔍 Debug: Parameters: {json.dumps(self.kwargs, indent=2)}")
30
+ return self
31
+
32
+ def __exit__(self, exc_type, exc_val, exc_tb):
33
+ duration = (datetime.now() - self.start_time).total_seconds()
34
+
35
+ if exc_type is None:
36
+ # if is_telemetry_enabled():
37
+ # print(f"✅ Debug: {self.function_name} completed successfully ({duration:.2f}s)")
38
+ pass
39
+ else:
40
+ # if is_telemetry_enabled():
41
+ # print(f"❌ Debug: {self.function_name} failed after {duration:.2f}s")
42
+ # print(f"❌ Debug: Error: {exc_type.__name__}: {exc_val}")
43
+ # print(f"❌ Debug: Traceback:\n{traceback.format_exc()}")
44
+
45
+ # Report the error
46
+ report_error(exc_val, self.function_name, {
47
+ "duration": duration,
48
+ "parameters": self.kwargs
49
+ })
50
+
51
+ def debug_function(func: Callable) -> Callable:
52
+ """
53
+ Decorator to add debugging to any function.
54
+
55
+ Args:
56
+ func: Function to debug
57
+
58
+ Returns:
59
+ Wrapped function with debugging
60
+ """
61
+ def wrapper(*args, **kwargs):
62
+ function_name = f"{func.__module__}.{func.__name__}"
63
+
64
+ # Sanitize arguments for JSON serialization
65
+ safe_args = []
66
+ for arg in args:
67
+ if hasattr(arg, '__dict__'):
68
+ safe_args.append(f"<{type(arg).__name__} object>")
69
+ else:
70
+ safe_args.append(str(arg))
71
+
72
+ safe_kwargs = {}
73
+ for key, value in kwargs.items():
74
+ if hasattr(value, '__dict__'):
75
+ safe_kwargs[key] = f"<{type(value).__name__} object>"
76
+ else:
77
+ safe_kwargs[key] = str(value)
78
+
79
+ with DebugContext(function_name, args=safe_args, kwargs=safe_kwargs):
80
+ try:
81
+ result = func(*args, **kwargs)
82
+ return result
83
+ except Exception as e:
84
+ # Re-raise the exception after reporting
85
+ raise
86
+
87
+ return wrapper
88
+
89
+ def debug_print(message: str, level: str = "info") -> None:
90
+ """
91
+ Print debug message with timestamp and level.
92
+
93
+ Args:
94
+ message: Message to print
95
+ level: Debug level (info, warning, error, success)
96
+ """
97
+ timestamp = datetime.now().strftime("%H:%M:%S")
98
+
99
+ icons = {
100
+ "info": "🔍",
101
+ "warning": "⚠️",
102
+ "error": "❌",
103
+ "success": "✅",
104
+ "request": "📤",
105
+ "response": "📥"
106
+ }
107
+
108
+ icon = icons.get(level, "🔍")
109
+ print(f"[{timestamp}] {icon} {message}")
110
+
111
+ def debug_request(method: str, url: str, data: Optional[Dict[str, Any]] = None) -> None:
112
+ """
113
+ Debug HTTP request information.
114
+
115
+ Args:
116
+ method: HTTP method
117
+ url: Request URL
118
+ data: Request data
119
+ """
120
+ debug_print(f"{method} {url}", "request")
121
+ if data:
122
+ debug_print(f"Data: {json.dumps(data, indent=2)}", "info")
123
+
124
+ def debug_response(status_code: int, data: Optional[Dict[str, Any]] = None) -> None:
125
+ """
126
+ Debug HTTP response information.
127
+
128
+ Args:
129
+ status_code: HTTP status code
130
+ data: Response data
131
+ """
132
+ if 200 <= status_code < 300:
133
+ debug_print(f"Response {status_code}: Success", "success")
134
+ else:
135
+ debug_print(f"Response {status_code}: Error", "error")
136
+
137
+ if data:
138
+ # Truncate large responses for readability
139
+ data_str = json.dumps(data, indent=2)
140
+ if len(data_str) > 500:
141
+ data_str = data_str[:500] + "...\n[Response truncated]"
142
+ debug_print(f"Response data: {data_str}", "response")
143
+
144
+ def analyze_error(error: Exception) -> Dict[str, Any]:
145
+ """
146
+ Analyze an error and provide debugging information.
147
+
148
+ Args:
149
+ error: Exception to analyze
150
+
151
+ Returns:
152
+ Dictionary with error analysis
153
+ """
154
+ error_type = type(error).__name__
155
+ error_message = str(error)
156
+ traceback_str = traceback.format_exc()
157
+
158
+ analysis = {
159
+ "error_type": error_type,
160
+ "error_message": error_message,
161
+ "traceback": traceback_str,
162
+ "suggestions": []
163
+ }
164
+
165
+ # Provide specific suggestions based on error type
166
+ if "AuthenticationError" in error_type or "401" in error_message:
167
+ analysis["suggestions"].extend([
168
+ "Check your username and password",
169
+ "Verify your account is not banned",
170
+ "Try re-authenticating with a fresh token"
171
+ ])
172
+
173
+ elif "RateLimitError" in error_type or "429" in error_message:
174
+ analysis["suggestions"].extend([
175
+ "Wait before making more requests",
176
+ "Implement exponential backoff",
177
+ "Check rate limit headers for retry time"
178
+ ])
179
+
180
+ elif "NetworkError" in error_type or "timeout" in error_message.lower():
181
+ analysis["suggestions"].extend([
182
+ "Check your internet connection",
183
+ "Try increasing timeout value",
184
+ "Verify MC5 servers are accessible"
185
+ ])
186
+
187
+ elif "TokenExpiredError" in error_type:
188
+ analysis["suggestions"].extend([
189
+ "Enable auto_refresh in client",
190
+ "Call authenticate() again",
191
+ "Check token expiration time"
192
+ ])
193
+
194
+ return analysis
195
+
196
+ def print_error_analysis(error: Exception) -> None:
197
+ """
198
+ Print detailed error analysis with suggestions.
199
+
200
+ Args:
201
+ error: Exception to analyze
202
+ """
203
+ analysis = analyze_error(error)
204
+
205
+ debug_print(f"Error Analysis: {analysis['error_type']}", "error")
206
+ debug_print(f"Message: {analysis['error_message']}", "error")
207
+
208
+ if analysis["suggestions"]:
209
+ debug_print("Suggestions:", "warning")
210
+ for i, suggestion in enumerate(analysis["suggestions"], 1):
211
+ debug_print(f" {i}. {suggestion}", "warning")
212
+
213
+ def create_debug_report() -> Dict[str, Any]:
214
+ """
215
+ Create a comprehensive debug report.
216
+
217
+ Returns:
218
+ Debug report dictionary
219
+ """
220
+ import platform
221
+ import sys
222
+
223
+ report = {
224
+ "timestamp": datetime.now().isoformat(),
225
+ "python_version": sys.version,
226
+ "platform": platform.platform(),
227
+ "architecture": platform.architecture(),
228
+ "system": platform.system(),
229
+ "mc5_client_version": "1.0.16",
230
+ "telemetry_enabled": is_telemetry_enabled()
231
+ }
232
+
233
+ return report
234
+
235
+ def print_debug_report() -> None:
236
+ """Print a comprehensive debug report."""
237
+ report = create_debug_report()
238
+
239
+ debug_print("MC5 API Client Debug Report", "info")
240
+ debug_print("=" * 40, "info")
241
+
242
+ for key, value in report.items():
243
+ debug_print(f"{key}: {value}", "info")
244
+
245
+ # Convenience function for quick debugging
246
+ def debug_mode(enable: bool = False) -> None:
247
+ """
248
+ Enable or disable debug mode.
249
+
250
+ Args:
251
+ enable: Whether to enable debug mode (default: False)
252
+ """
253
+ if enable:
254
+ telemetry(True)
255
+ print_debug_report()
256
+ print("✅ Debug mode enabled")
257
+ else:
258
+ telemetry(False)
259
+ print("🔇 Debug mode disabled")