django-nativemojo 0.1.10__py3-none-any.whl → 0.1.15__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.
- django_nativemojo-0.1.15.dist-info/METADATA +136 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/RECORD +105 -65
- mojo/__init__.py +1 -1
- mojo/apps/account/management/__init__.py +5 -0
- mojo/apps/account/management/commands/__init__.py +6 -0
- mojo/apps/account/management/commands/serializer_admin.py +531 -0
- mojo/apps/account/migrations/0004_user_avatar.py +20 -0
- mojo/apps/account/migrations/0005_group_last_activity.py +18 -0
- mojo/apps/account/models/group.py +25 -7
- mojo/apps/account/models/member.py +15 -4
- mojo/apps/account/models/user.py +197 -20
- mojo/apps/account/rest/group.py +1 -0
- mojo/apps/account/rest/user.py +6 -2
- mojo/apps/aws/rest/__init__.py +1 -0
- mojo/apps/aws/rest/s3.py +64 -0
- mojo/apps/fileman/README.md +8 -8
- mojo/apps/fileman/backends/base.py +76 -70
- mojo/apps/fileman/backends/filesystem.py +86 -86
- mojo/apps/fileman/backends/s3.py +200 -108
- mojo/apps/fileman/migrations/0001_initial.py +106 -0
- mojo/apps/fileman/migrations/0002_filemanager_parent_alter_filemanager_max_file_size.py +24 -0
- mojo/apps/fileman/migrations/0003_remove_file_fileman_fil_upload__c4bc35_idx_and_more.py +25 -0
- mojo/apps/fileman/migrations/0004_remove_file_original_filename_and_more.py +39 -0
- mojo/apps/fileman/migrations/0005_alter_file_upload_token.py +18 -0
- mojo/apps/fileman/migrations/0006_file_download_url_filemanager_forever_urls.py +23 -0
- mojo/apps/fileman/migrations/0007_remove_filemanager_forever_urls_and_more.py +22 -0
- mojo/apps/fileman/migrations/0008_file_category.py +18 -0
- mojo/apps/fileman/migrations/0009_rename_file_path_file_storage_file_path.py +18 -0
- mojo/apps/fileman/migrations/0010_filerendition.py +33 -0
- mojo/apps/fileman/migrations/0011_alter_filerendition_original_file.py +19 -0
- mojo/apps/fileman/models/__init__.py +1 -5
- mojo/apps/fileman/models/file.py +204 -58
- mojo/apps/fileman/models/manager.py +161 -31
- mojo/apps/fileman/models/rendition.py +118 -0
- mojo/apps/fileman/renderer/__init__.py +111 -0
- mojo/apps/fileman/renderer/audio.py +403 -0
- mojo/apps/fileman/renderer/base.py +205 -0
- mojo/apps/fileman/renderer/document.py +404 -0
- mojo/apps/fileman/renderer/image.py +222 -0
- mojo/apps/fileman/renderer/utils.py +297 -0
- mojo/apps/fileman/renderer/video.py +304 -0
- mojo/apps/fileman/rest/__init__.py +1 -18
- mojo/apps/fileman/rest/upload.py +22 -32
- mojo/apps/fileman/signals.py +58 -0
- mojo/apps/fileman/tasks.py +254 -0
- mojo/apps/fileman/utils/__init__.py +40 -16
- mojo/apps/incident/migrations/0005_incidenthistory.py +39 -0
- mojo/apps/incident/migrations/0006_alter_incident_state.py +18 -0
- mojo/apps/incident/models/__init__.py +1 -0
- mojo/apps/incident/models/history.py +36 -0
- mojo/apps/incident/models/incident.py +1 -1
- mojo/apps/incident/reporter.py +3 -1
- mojo/apps/incident/rest/event.py +7 -1
- mojo/apps/logit/migrations/0004_alter_log_level.py +18 -0
- mojo/apps/logit/models/log.py +4 -1
- mojo/apps/metrics/utils.py +2 -2
- mojo/apps/notify/handlers/ses/message.py +1 -1
- mojo/apps/notify/providers/aws.py +2 -2
- mojo/apps/tasks/__init__.py +34 -1
- mojo/apps/tasks/manager.py +200 -45
- mojo/apps/tasks/rest/tasks.py +24 -10
- mojo/apps/tasks/runner.py +283 -18
- mojo/apps/tasks/task.py +99 -0
- mojo/apps/tasks/tq_handlers.py +118 -0
- mojo/decorators/auth.py +6 -1
- mojo/decorators/http.py +7 -2
- mojo/helpers/aws/__init__.py +41 -0
- mojo/helpers/aws/ec2.py +804 -0
- mojo/helpers/aws/iam.py +748 -0
- mojo/helpers/aws/s3.py +451 -11
- mojo/helpers/aws/ses.py +483 -0
- mojo/helpers/aws/sns.py +461 -0
- mojo/helpers/crypto/__pycache__/hash.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/sign.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/utils.cpython-310.pyc +0 -0
- mojo/helpers/dates.py +18 -0
- mojo/helpers/response.py +6 -2
- mojo/helpers/settings/__init__.py +2 -0
- mojo/helpers/{settings.py → settings/helper.py} +1 -37
- mojo/helpers/settings/parser.py +132 -0
- mojo/middleware/logging.py +1 -1
- mojo/middleware/mojo.py +5 -0
- mojo/models/rest.py +261 -46
- mojo/models/secrets.py +13 -4
- mojo/serializers/__init__.py +100 -0
- mojo/serializers/advanced/README.md +363 -0
- mojo/serializers/advanced/__init__.py +247 -0
- mojo/serializers/advanced/formats/__init__.py +28 -0
- mojo/serializers/advanced/formats/csv.py +416 -0
- mojo/serializers/advanced/formats/excel.py +516 -0
- mojo/serializers/advanced/formats/json.py +239 -0
- mojo/serializers/advanced/formats/localizers.py +509 -0
- mojo/serializers/advanced/formats/response.py +485 -0
- mojo/serializers/advanced/serializer.py +568 -0
- mojo/serializers/manager.py +501 -0
- mojo/serializers/optimized.py +618 -0
- mojo/serializers/settings_example.py +322 -0
- mojo/serializers/{models.py → simple.py} +38 -15
- testit/helpers.py +21 -4
- django_nativemojo-0.1.10.dist-info/METADATA +0 -96
- mojo/apps/metrics/rest/db.py +0 -0
- mojo/helpers/aws/setup_email.py +0 -0
- mojo/ws4redis/README.md +0 -174
- mojo/ws4redis/__init__.py +0 -2
- mojo/ws4redis/client.py +0 -283
- mojo/ws4redis/connection.py +0 -327
- mojo/ws4redis/exceptions.py +0 -32
- mojo/ws4redis/redis.py +0 -183
- mojo/ws4redis/servers/base.py +0 -86
- mojo/ws4redis/servers/django.py +0 -171
- mojo/ws4redis/servers/uwsgi.py +0 -63
- mojo/ws4redis/settings.py +0 -45
- mojo/ws4redis/utf8validator.py +0 -128
- mojo/ws4redis/websocket.py +0 -403
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/LICENSE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/NOTICE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/WHEEL +0 -0
- /mojo/{ws4redis/servers → apps/aws}/__init__.py +0 -0
- /mojo/apps/{fileman/models/render.py → aws/models/__init__.py} +0 -0
- /mojo/apps/fileman/{rest/__init__ → migrations/__init__.py} +0 -0
@@ -0,0 +1,501 @@
|
|
1
|
+
"""
|
2
|
+
Serializer Manager for Django-MOJO
|
3
|
+
|
4
|
+
Provides a unified interface for switching between different serializers and managing
|
5
|
+
serialization strategies across the application. Supports:
|
6
|
+
|
7
|
+
- Multiple serializer backends (simple, advanced, optimized, custom)
|
8
|
+
- Runtime serializer switching
|
9
|
+
- Performance monitoring and comparison
|
10
|
+
- Configuration via Django settings
|
11
|
+
- Fallback mechanisms for robustness
|
12
|
+
- Easy integration with MojoModel REST operations
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
# Use default configured serializer
|
16
|
+
manager = SerializerManager()
|
17
|
+
serializer = manager.get_serializer(instance, graph="list")
|
18
|
+
|
19
|
+
# Force specific serializer
|
20
|
+
serializer = manager.get_serializer(instance, serializer_type="optimized")
|
21
|
+
|
22
|
+
# Performance comparison
|
23
|
+
results = manager.benchmark_serializers(queryset)
|
24
|
+
"""
|
25
|
+
|
26
|
+
import time
|
27
|
+
import importlib
|
28
|
+
from typing import Dict, Any, Optional, Type, Union, List
|
29
|
+
from threading import RLock
|
30
|
+
|
31
|
+
from django.conf import settings
|
32
|
+
from django.db.models import QuerySet, Model
|
33
|
+
from django.http import HttpResponse
|
34
|
+
|
35
|
+
from mojo.helpers import logit
|
36
|
+
|
37
|
+
logger = logit.get_logger("serializer_manager", "serializer_manager.log")
|
38
|
+
|
39
|
+
# Thread-safe lock for serializer registry operations
|
40
|
+
_registry_lock = RLock()
|
41
|
+
|
42
|
+
# Default serializer configurations
|
43
|
+
DEFAULT_SERIALIZERS = {
|
44
|
+
'simple': 'mojo.serializers.simple.GraphSerializer',
|
45
|
+
'optimized': 'mojo.serializers.optimized.OptimizedGraphSerializer',
|
46
|
+
'advanced': 'mojo.serializers.advanced.AdvancedGraphSerializer',
|
47
|
+
}
|
48
|
+
|
49
|
+
# Global serializer registry
|
50
|
+
_SERIALIZER_REGISTRY = {}
|
51
|
+
|
52
|
+
# Performance tracking
|
53
|
+
_PERFORMANCE_DATA = {
|
54
|
+
'serializer_usage': {},
|
55
|
+
'performance_history': [],
|
56
|
+
'benchmark_results': {}
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
class SerializerRegistry:
|
61
|
+
"""Registry for managing available serializers."""
|
62
|
+
|
63
|
+
def __init__(self):
|
64
|
+
self.serializers = {}
|
65
|
+
self.default_serializer = None
|
66
|
+
self.lock = RLock()
|
67
|
+
|
68
|
+
def register(self, name: str, serializer_class_or_path: Union[str, Type],
|
69
|
+
description: str = None, is_default: bool = False):
|
70
|
+
"""
|
71
|
+
Register a serializer.
|
72
|
+
|
73
|
+
:param name: Unique name for the serializer
|
74
|
+
:param serializer_class_or_path: Serializer class or import path string
|
75
|
+
:param description: Optional description
|
76
|
+
:param is_default: Set as default serializer
|
77
|
+
"""
|
78
|
+
with self.lock:
|
79
|
+
# Handle string import path
|
80
|
+
if isinstance(serializer_class_or_path, str):
|
81
|
+
try:
|
82
|
+
module_path, class_name = serializer_class_or_path.rsplit('.', 1)
|
83
|
+
module = importlib.import_module(module_path)
|
84
|
+
serializer_class = getattr(module, class_name)
|
85
|
+
except (ImportError, AttributeError) as e:
|
86
|
+
logger.error(f"Failed to import serializer '{serializer_class_or_path}': {e}")
|
87
|
+
return False
|
88
|
+
else:
|
89
|
+
serializer_class = serializer_class_or_path
|
90
|
+
|
91
|
+
self.serializers[name] = {
|
92
|
+
'class': serializer_class,
|
93
|
+
'description': description or f"{name} serializer",
|
94
|
+
'registered_at': time.time()
|
95
|
+
}
|
96
|
+
|
97
|
+
if is_default or self.default_serializer is None:
|
98
|
+
self.default_serializer = name
|
99
|
+
|
100
|
+
logger.info(f"Registered serializer: {name}")
|
101
|
+
return True
|
102
|
+
|
103
|
+
def get(self, name: str):
|
104
|
+
"""Get serializer class by name."""
|
105
|
+
with self.lock:
|
106
|
+
serializer_info = self.serializers.get(name)
|
107
|
+
return serializer_info['class'] if serializer_info else None
|
108
|
+
|
109
|
+
def list_serializers(self):
|
110
|
+
"""List all registered serializers."""
|
111
|
+
with self.lock:
|
112
|
+
return {
|
113
|
+
name: {
|
114
|
+
'description': info['description'],
|
115
|
+
'class_name': info['class'].__name__,
|
116
|
+
'is_default': name == self.default_serializer
|
117
|
+
}
|
118
|
+
for name, info in self.serializers.items()
|
119
|
+
}
|
120
|
+
|
121
|
+
def get_default(self):
|
122
|
+
"""Get the default serializer name."""
|
123
|
+
with self.lock:
|
124
|
+
return self.default_serializer
|
125
|
+
|
126
|
+
def set_default(self, name: str):
|
127
|
+
"""Set default serializer."""
|
128
|
+
with self.lock:
|
129
|
+
if name in self.serializers:
|
130
|
+
self.default_serializer = name
|
131
|
+
logger.info(f"Default serializer set to: {name}")
|
132
|
+
return True
|
133
|
+
return False
|
134
|
+
|
135
|
+
|
136
|
+
# Global serializer registry
|
137
|
+
_registry = SerializerRegistry()
|
138
|
+
|
139
|
+
|
140
|
+
class SerializerManager:
|
141
|
+
"""
|
142
|
+
Main serializer manager providing unified interface for all serialization operations.
|
143
|
+
"""
|
144
|
+
|
145
|
+
def __init__(self, default_serializer: str = None, enable_performance_tracking: bool = True):
|
146
|
+
"""
|
147
|
+
Initialize serializer manager.
|
148
|
+
|
149
|
+
:param default_serializer: Override default serializer
|
150
|
+
:param enable_performance_tracking: Enable performance monitoring
|
151
|
+
"""
|
152
|
+
self.default_serializer = default_serializer
|
153
|
+
self.performance_tracking = enable_performance_tracking
|
154
|
+
self.registry = _registry
|
155
|
+
|
156
|
+
# Initialize default serializers if not already done
|
157
|
+
self._ensure_default_serializers()
|
158
|
+
|
159
|
+
# Load configuration from Django settings
|
160
|
+
self._load_configuration()
|
161
|
+
|
162
|
+
def _ensure_default_serializers(self):
|
163
|
+
"""Ensure default serializers are registered."""
|
164
|
+
if not self.registry.serializers:
|
165
|
+
for name, import_path in DEFAULT_SERIALIZERS.items():
|
166
|
+
self.registry.register(
|
167
|
+
name=name,
|
168
|
+
serializer_class_or_path=import_path,
|
169
|
+
is_default=(name == 'optimized') # Set optimized as default
|
170
|
+
)
|
171
|
+
|
172
|
+
def _load_configuration(self):
|
173
|
+
"""Load configuration from Django settings."""
|
174
|
+
# Get default serializer from settings
|
175
|
+
default_from_settings = getattr(settings, 'MOJO_DEFAULT_SERIALIZER', None)
|
176
|
+
if default_from_settings and not self.default_serializer:
|
177
|
+
self.default_serializer = default_from_settings
|
178
|
+
|
179
|
+
# Register custom serializers from settings
|
180
|
+
custom_serializers = getattr(settings, 'MOJO_CUSTOM_SERIALIZERS', {})
|
181
|
+
for name, config in custom_serializers.items():
|
182
|
+
if isinstance(config, str):
|
183
|
+
# Simple string path
|
184
|
+
self.registry.register(name, config)
|
185
|
+
elif isinstance(config, dict):
|
186
|
+
# Detailed configuration
|
187
|
+
self.registry.register(
|
188
|
+
name=name,
|
189
|
+
serializer_class_or_path=config.get('class'),
|
190
|
+
description=config.get('description'),
|
191
|
+
is_default=config.get('is_default', False)
|
192
|
+
)
|
193
|
+
|
194
|
+
def get_serializer(self, instance, graph: str = "default", many: bool = None,
|
195
|
+
serializer_type: str = None, **kwargs):
|
196
|
+
"""
|
197
|
+
Get appropriate serializer for the given instance and parameters.
|
198
|
+
|
199
|
+
:param instance: Model instance, QuerySet, or list of objects
|
200
|
+
:param graph: Graph configuration name
|
201
|
+
:param many: Force many=True for list serialization
|
202
|
+
:param serializer_type: Override serializer type
|
203
|
+
:param kwargs: Additional serializer arguments
|
204
|
+
:return: Configured serializer instance
|
205
|
+
"""
|
206
|
+
# Determine serializer type
|
207
|
+
if serializer_type is None:
|
208
|
+
serializer_type = self.default_serializer or self.registry.get_default()
|
209
|
+
|
210
|
+
# Get serializer class
|
211
|
+
serializer_class = self.registry.get(serializer_type)
|
212
|
+
if serializer_class is None:
|
213
|
+
logger.warning(f"Serializer '{serializer_type}' not found, using default")
|
214
|
+
serializer_type = self.registry.get_default()
|
215
|
+
serializer_class = self.registry.get(serializer_type)
|
216
|
+
|
217
|
+
if serializer_class is None:
|
218
|
+
raise ValueError("No serializer available")
|
219
|
+
|
220
|
+
# Auto-detect many parameter for QuerySets
|
221
|
+
if many is None and isinstance(instance, QuerySet):
|
222
|
+
many = True
|
223
|
+
|
224
|
+
# Track usage for performance monitoring
|
225
|
+
if self.performance_tracking:
|
226
|
+
self._track_usage(serializer_type, instance)
|
227
|
+
|
228
|
+
# Create and return serializer instance
|
229
|
+
try:
|
230
|
+
return serializer_class(instance, graph=graph, many=many, **kwargs)
|
231
|
+
except Exception as e:
|
232
|
+
logger.error(f"Failed to create serializer '{serializer_type}': {e}")
|
233
|
+
# Fallback to simple serializer
|
234
|
+
fallback_class = self.registry.get('simple')
|
235
|
+
if fallback_class and fallback_class != serializer_class:
|
236
|
+
logger.info("Falling back to simple serializer")
|
237
|
+
return fallback_class(instance, graph=graph, many=many)
|
238
|
+
raise
|
239
|
+
|
240
|
+
def serialize(self, instance, graph: str = "default", many: bool = None,
|
241
|
+
serializer_type: str = None, **kwargs):
|
242
|
+
"""
|
243
|
+
Direct serialization method.
|
244
|
+
|
245
|
+
:param instance: Object(s) to serialize
|
246
|
+
:param graph: Graph configuration
|
247
|
+
:param many: Force many=True
|
248
|
+
:param serializer_type: Override serializer type
|
249
|
+
:param kwargs: Additional arguments
|
250
|
+
:return: Serialized data
|
251
|
+
"""
|
252
|
+
serializer = self.get_serializer(
|
253
|
+
instance=instance,
|
254
|
+
graph=graph,
|
255
|
+
many=many,
|
256
|
+
serializer_type=serializer_type,
|
257
|
+
**kwargs
|
258
|
+
)
|
259
|
+
return serializer.serialize()
|
260
|
+
|
261
|
+
def to_json(self, instance, graph: str = "default", many: bool = None,
|
262
|
+
serializer_type: str = None, **kwargs):
|
263
|
+
"""
|
264
|
+
Serialize to JSON string.
|
265
|
+
|
266
|
+
:param instance: Object(s) to serialize
|
267
|
+
:param graph: Graph configuration
|
268
|
+
:param many: Force many=True
|
269
|
+
:param serializer_type: Override serializer type
|
270
|
+
:param kwargs: Additional JSON arguments
|
271
|
+
:return: JSON string
|
272
|
+
"""
|
273
|
+
serializer = self.get_serializer(
|
274
|
+
instance=instance,
|
275
|
+
graph=graph,
|
276
|
+
many=many,
|
277
|
+
serializer_type=serializer_type
|
278
|
+
)
|
279
|
+
return serializer.to_json(**kwargs)
|
280
|
+
|
281
|
+
def to_response(self, instance, request, graph: str = "default", many: bool = None,
|
282
|
+
serializer_type: str = None, **kwargs):
|
283
|
+
"""
|
284
|
+
Serialize to HTTP response.
|
285
|
+
|
286
|
+
:param instance: Object(s) to serialize
|
287
|
+
:param request: Django request object
|
288
|
+
:param graph: Graph configuration
|
289
|
+
:param many: Force many=True
|
290
|
+
:param serializer_type: Override serializer type
|
291
|
+
:param kwargs: Additional response arguments
|
292
|
+
:return: HttpResponse
|
293
|
+
"""
|
294
|
+
serializer = self.get_serializer(
|
295
|
+
instance=instance,
|
296
|
+
graph=graph,
|
297
|
+
many=many,
|
298
|
+
serializer_type=serializer_type
|
299
|
+
)
|
300
|
+
return serializer.to_response(request, **kwargs)
|
301
|
+
|
302
|
+
def benchmark_serializers(self, instance, graph: str = "default",
|
303
|
+
serializer_types: List[str] = None, iterations: int = 10):
|
304
|
+
"""
|
305
|
+
Benchmark multiple serializers for performance comparison.
|
306
|
+
|
307
|
+
:param instance: Test instance or queryset
|
308
|
+
:param graph: Graph configuration to test
|
309
|
+
:param serializer_types: List of serializers to test (default: all)
|
310
|
+
:param iterations: Number of iterations per serializer
|
311
|
+
:return: Benchmark results
|
312
|
+
"""
|
313
|
+
if serializer_types is None:
|
314
|
+
serializer_types = list(self.registry.list_serializers().keys())
|
315
|
+
|
316
|
+
results = {}
|
317
|
+
|
318
|
+
for serializer_type in serializer_types:
|
319
|
+
logger.info(f"Benchmarking {serializer_type} serializer...")
|
320
|
+
|
321
|
+
times = []
|
322
|
+
errors = 0
|
323
|
+
|
324
|
+
for i in range(iterations):
|
325
|
+
try:
|
326
|
+
start_time = time.perf_counter()
|
327
|
+
|
328
|
+
serializer = self.get_serializer(
|
329
|
+
instance=instance,
|
330
|
+
graph=graph,
|
331
|
+
serializer_type=serializer_type
|
332
|
+
)
|
333
|
+
data = serializer.serialize()
|
334
|
+
json_output = serializer.to_json()
|
335
|
+
|
336
|
+
end_time = time.perf_counter()
|
337
|
+
times.append(end_time - start_time)
|
338
|
+
|
339
|
+
except Exception as e:
|
340
|
+
logger.error(f"Benchmark error for {serializer_type}: {e}")
|
341
|
+
errors += 1
|
342
|
+
|
343
|
+
if times:
|
344
|
+
results[serializer_type] = {
|
345
|
+
'min_time': min(times),
|
346
|
+
'max_time': max(times),
|
347
|
+
'avg_time': sum(times) / len(times),
|
348
|
+
'total_time': sum(times),
|
349
|
+
'iterations': len(times),
|
350
|
+
'errors': errors,
|
351
|
+
'objects_per_second': len(times) / sum(times) if sum(times) > 0 else 0
|
352
|
+
}
|
353
|
+
else:
|
354
|
+
results[serializer_type] = {
|
355
|
+
'error': 'All iterations failed',
|
356
|
+
'errors': errors
|
357
|
+
}
|
358
|
+
|
359
|
+
# Store benchmark results
|
360
|
+
if self.performance_tracking:
|
361
|
+
_PERFORMANCE_DATA['benchmark_results'][time.time()] = results
|
362
|
+
|
363
|
+
return results
|
364
|
+
|
365
|
+
def get_performance_stats(self):
|
366
|
+
"""Get performance statistics for all serializers."""
|
367
|
+
stats = {
|
368
|
+
'usage_stats': _PERFORMANCE_DATA['serializer_usage'].copy(),
|
369
|
+
'registered_serializers': self.registry.list_serializers(),
|
370
|
+
'default_serializer': self.registry.get_default()
|
371
|
+
}
|
372
|
+
|
373
|
+
# Add serializer-specific stats
|
374
|
+
for name in self.registry.serializers.keys():
|
375
|
+
serializer_class = self.registry.get(name)
|
376
|
+
if hasattr(serializer_class, 'get_performance_stats'):
|
377
|
+
try:
|
378
|
+
stats[f'{name}_stats'] = serializer_class.get_performance_stats()
|
379
|
+
except Exception as e:
|
380
|
+
logger.warning(f"Failed to get stats for {name}: {e}")
|
381
|
+
|
382
|
+
return stats
|
383
|
+
|
384
|
+
def clear_caches(self, serializer_type: str = None):
|
385
|
+
"""
|
386
|
+
Clear caches for specified serializer or all serializers.
|
387
|
+
|
388
|
+
:param serializer_type: Specific serializer to clear, or None for all
|
389
|
+
"""
|
390
|
+
if serializer_type:
|
391
|
+
serializer_class = self.registry.get(serializer_type)
|
392
|
+
if serializer_class and hasattr(serializer_class, 'clear_caches'):
|
393
|
+
serializer_class.clear_caches()
|
394
|
+
logger.info(f"Cleared caches for {serializer_type}")
|
395
|
+
else:
|
396
|
+
# Clear all serializer caches
|
397
|
+
for name in self.registry.serializers.keys():
|
398
|
+
serializer_class = self.registry.get(name)
|
399
|
+
if serializer_class and hasattr(serializer_class, 'clear_caches'):
|
400
|
+
try:
|
401
|
+
serializer_class.clear_caches()
|
402
|
+
except Exception as e:
|
403
|
+
logger.warning(f"Failed to clear cache for {name}: {e}")
|
404
|
+
logger.info("Cleared all serializer caches")
|
405
|
+
|
406
|
+
def register_serializer(self, name: str, serializer_class_or_path: Union[str, Type],
|
407
|
+
description: str = None, is_default: bool = False):
|
408
|
+
"""
|
409
|
+
Register a new serializer.
|
410
|
+
|
411
|
+
:param name: Unique serializer name
|
412
|
+
:param serializer_class_or_path: Serializer class or import path
|
413
|
+
:param description: Optional description
|
414
|
+
:param is_default: Set as default serializer
|
415
|
+
:return: True if successful
|
416
|
+
"""
|
417
|
+
return self.registry.register(name, serializer_class_or_path, description, is_default)
|
418
|
+
|
419
|
+
def set_default_serializer(self, name: str):
|
420
|
+
"""
|
421
|
+
Set the default serializer.
|
422
|
+
|
423
|
+
:param name: Serializer name
|
424
|
+
:return: True if successful
|
425
|
+
"""
|
426
|
+
success = self.registry.set_default(name)
|
427
|
+
if success:
|
428
|
+
self.default_serializer = name
|
429
|
+
return success
|
430
|
+
|
431
|
+
def _track_usage(self, serializer_type: str, instance):
|
432
|
+
"""Track serializer usage for performance monitoring."""
|
433
|
+
if not self.performance_tracking:
|
434
|
+
return
|
435
|
+
|
436
|
+
usage_key = f"{serializer_type}"
|
437
|
+
if usage_key not in _PERFORMANCE_DATA['serializer_usage']:
|
438
|
+
_PERFORMANCE_DATA['serializer_usage'][usage_key] = {
|
439
|
+
'count': 0,
|
440
|
+
'last_used': None,
|
441
|
+
'total_objects': 0
|
442
|
+
}
|
443
|
+
|
444
|
+
stats = _PERFORMANCE_DATA['serializer_usage'][usage_key]
|
445
|
+
stats['count'] += 1
|
446
|
+
stats['last_used'] = time.time()
|
447
|
+
|
448
|
+
# Count objects being serialized
|
449
|
+
if isinstance(instance, QuerySet):
|
450
|
+
try:
|
451
|
+
stats['total_objects'] += instance.count()
|
452
|
+
except Exception:
|
453
|
+
stats['total_objects'] += 1
|
454
|
+
elif isinstance(instance, (list, tuple)):
|
455
|
+
stats['total_objects'] += len(instance)
|
456
|
+
else:
|
457
|
+
stats['total_objects'] += 1
|
458
|
+
|
459
|
+
|
460
|
+
# Global manager instance
|
461
|
+
_default_manager = None
|
462
|
+
|
463
|
+
def get_serializer_manager():
|
464
|
+
"""Get the global serializer manager instance."""
|
465
|
+
global _default_manager
|
466
|
+
if _default_manager is None:
|
467
|
+
_default_manager = SerializerManager()
|
468
|
+
return _default_manager
|
469
|
+
|
470
|
+
def register_serializer(name: str, serializer_class_or_path: Union[str, Type],
|
471
|
+
description: str = None, is_default: bool = False):
|
472
|
+
"""Register a serializer globally."""
|
473
|
+
return get_serializer_manager().register_serializer(name, serializer_class_or_path, description, is_default)
|
474
|
+
|
475
|
+
def set_default_serializer(name: str):
|
476
|
+
"""Set the global default serializer."""
|
477
|
+
return get_serializer_manager().set_default_serializer(name)
|
478
|
+
|
479
|
+
def serialize(instance, graph: str = "default", many: bool = None, serializer_type: str = None, **kwargs):
|
480
|
+
"""Global serialize function."""
|
481
|
+
return get_serializer_manager().serialize(instance, graph, many, serializer_type, **kwargs)
|
482
|
+
|
483
|
+
def to_json(instance, graph: str = "default", many: bool = None, serializer_type: str = None, **kwargs):
|
484
|
+
"""Global to_json function."""
|
485
|
+
return get_serializer_manager().to_json(instance, graph, many, serializer_type, **kwargs)
|
486
|
+
|
487
|
+
def to_response(instance, request, graph: str = "default", many: bool = None, serializer_type: str = None, **kwargs):
|
488
|
+
"""Global to_response function."""
|
489
|
+
return get_serializer_manager().to_response(instance, request, graph, many, serializer_type, **kwargs)
|
490
|
+
|
491
|
+
def get_performance_stats():
|
492
|
+
"""Get global performance statistics."""
|
493
|
+
return get_serializer_manager().get_performance_stats()
|
494
|
+
|
495
|
+
def clear_serializer_caches(serializer_type: str = None):
|
496
|
+
"""Clear serializer caches globally."""
|
497
|
+
return get_serializer_manager().clear_caches(serializer_type)
|
498
|
+
|
499
|
+
def benchmark_serializers(instance, graph: str = "default", serializer_types: List[str] = None, iterations: int = 10):
|
500
|
+
"""Benchmark serializers globally."""
|
501
|
+
return get_serializer_manager().benchmark_serializers(instance, graph, serializer_types, iterations)
|