createsonline 0.1.26__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.
- createsonline/__init__.py +46 -0
- createsonline/admin/__init__.py +7 -0
- createsonline/admin/content.py +526 -0
- createsonline/admin/crud.py +805 -0
- createsonline/admin/field_builder.py +559 -0
- createsonline/admin/integration.py +482 -0
- createsonline/admin/interface.py +2562 -0
- createsonline/admin/model_creator.py +513 -0
- createsonline/admin/model_manager.py +388 -0
- createsonline/admin/modern_dashboard.py +498 -0
- createsonline/admin/permissions.py +264 -0
- createsonline/admin/user_forms.py +594 -0
- createsonline/ai/__init__.py +202 -0
- createsonline/ai/fields.py +1226 -0
- createsonline/ai/orm.py +325 -0
- createsonline/ai/services.py +1244 -0
- createsonline/app.py +506 -0
- createsonline/auth/__init__.py +8 -0
- createsonline/auth/management.py +228 -0
- createsonline/auth/models.py +552 -0
- createsonline/cli/__init__.py +5 -0
- createsonline/cli/commands/__init__.py +122 -0
- createsonline/cli/commands/database.py +416 -0
- createsonline/cli/commands/info.py +173 -0
- createsonline/cli/commands/initdb.py +218 -0
- createsonline/cli/commands/project.py +545 -0
- createsonline/cli/commands/serve.py +173 -0
- createsonline/cli/commands/shell.py +93 -0
- createsonline/cli/commands/users.py +148 -0
- createsonline/cli/main.py +2041 -0
- createsonline/cli/manage.py +274 -0
- createsonline/config/__init__.py +9 -0
- createsonline/config/app.py +2577 -0
- createsonline/config/database.py +179 -0
- createsonline/config/docs.py +384 -0
- createsonline/config/errors.py +160 -0
- createsonline/config/orm.py +43 -0
- createsonline/config/request.py +93 -0
- createsonline/config/settings.py +176 -0
- createsonline/data/__init__.py +23 -0
- createsonline/data/dataframe.py +925 -0
- createsonline/data/io.py +453 -0
- createsonline/data/series.py +557 -0
- createsonline/database/__init__.py +60 -0
- createsonline/database/abstraction.py +440 -0
- createsonline/database/assistant.py +585 -0
- createsonline/database/fields.py +442 -0
- createsonline/database/migrations.py +132 -0
- createsonline/database/models.py +604 -0
- createsonline/database.py +438 -0
- createsonline/http/__init__.py +28 -0
- createsonline/http/client.py +535 -0
- createsonline/ml/__init__.py +55 -0
- createsonline/ml/classification.py +552 -0
- createsonline/ml/clustering.py +680 -0
- createsonline/ml/metrics.py +542 -0
- createsonline/ml/neural.py +560 -0
- createsonline/ml/preprocessing.py +784 -0
- createsonline/ml/regression.py +501 -0
- createsonline/performance/__init__.py +19 -0
- createsonline/performance/cache.py +444 -0
- createsonline/performance/compression.py +335 -0
- createsonline/performance/core.py +419 -0
- createsonline/project_init.py +789 -0
- createsonline/routing.py +528 -0
- createsonline/security/__init__.py +34 -0
- createsonline/security/core.py +811 -0
- createsonline/security/encryption.py +349 -0
- createsonline/server.py +295 -0
- createsonline/static/css/admin.css +263 -0
- createsonline/static/css/common.css +358 -0
- createsonline/static/css/dashboard.css +89 -0
- createsonline/static/favicon.ico +0 -0
- createsonline/static/icons/icon-128x128.png +0 -0
- createsonline/static/icons/icon-128x128.webp +0 -0
- createsonline/static/icons/icon-16x16.png +0 -0
- createsonline/static/icons/icon-16x16.webp +0 -0
- createsonline/static/icons/icon-180x180.png +0 -0
- createsonline/static/icons/icon-180x180.webp +0 -0
- createsonline/static/icons/icon-192x192.png +0 -0
- createsonline/static/icons/icon-192x192.webp +0 -0
- createsonline/static/icons/icon-256x256.png +0 -0
- createsonline/static/icons/icon-256x256.webp +0 -0
- createsonline/static/icons/icon-32x32.png +0 -0
- createsonline/static/icons/icon-32x32.webp +0 -0
- createsonline/static/icons/icon-384x384.png +0 -0
- createsonline/static/icons/icon-384x384.webp +0 -0
- createsonline/static/icons/icon-48x48.png +0 -0
- createsonline/static/icons/icon-48x48.webp +0 -0
- createsonline/static/icons/icon-512x512.png +0 -0
- createsonline/static/icons/icon-512x512.webp +0 -0
- createsonline/static/icons/icon-64x64.png +0 -0
- createsonline/static/icons/icon-64x64.webp +0 -0
- createsonline/static/image/android-chrome-192x192.png +0 -0
- createsonline/static/image/android-chrome-512x512.png +0 -0
- createsonline/static/image/apple-touch-icon.png +0 -0
- createsonline/static/image/favicon-16x16.png +0 -0
- createsonline/static/image/favicon-32x32.png +0 -0
- createsonline/static/image/favicon.ico +0 -0
- createsonline/static/image/favicon.svg +17 -0
- createsonline/static/image/icon-128x128.png +0 -0
- createsonline/static/image/icon-128x128.webp +0 -0
- createsonline/static/image/icon-16x16.png +0 -0
- createsonline/static/image/icon-16x16.webp +0 -0
- createsonline/static/image/icon-180x180.png +0 -0
- createsonline/static/image/icon-180x180.webp +0 -0
- createsonline/static/image/icon-192x192.png +0 -0
- createsonline/static/image/icon-192x192.webp +0 -0
- createsonline/static/image/icon-256x256.png +0 -0
- createsonline/static/image/icon-256x256.webp +0 -0
- createsonline/static/image/icon-32x32.png +0 -0
- createsonline/static/image/icon-32x32.webp +0 -0
- createsonline/static/image/icon-384x384.png +0 -0
- createsonline/static/image/icon-384x384.webp +0 -0
- createsonline/static/image/icon-48x48.png +0 -0
- createsonline/static/image/icon-48x48.webp +0 -0
- createsonline/static/image/icon-512x512.png +0 -0
- createsonline/static/image/icon-512x512.webp +0 -0
- createsonline/static/image/icon-64x64.png +0 -0
- createsonline/static/image/icon-64x64.webp +0 -0
- createsonline/static/image/logo-header-h100.png +0 -0
- createsonline/static/image/logo-header-h100.webp +0 -0
- createsonline/static/image/logo-header-h200@2x.png +0 -0
- createsonline/static/image/logo-header-h200@2x.webp +0 -0
- createsonline/static/image/logo.png +0 -0
- createsonline/static/js/admin.js +274 -0
- createsonline/static/site.webmanifest +35 -0
- createsonline/static/templates/admin/base.html +87 -0
- createsonline/static/templates/admin/dashboard.html +217 -0
- createsonline/static/templates/admin/model_form.html +270 -0
- createsonline/static/templates/admin/model_list.html +202 -0
- createsonline/static/test_script.js +15 -0
- createsonline/static/test_styles.css +59 -0
- createsonline/static_files.py +365 -0
- createsonline/templates/404.html +100 -0
- createsonline/templates/admin_login.html +169 -0
- createsonline/templates/base.html +102 -0
- createsonline/templates/index.html +151 -0
- createsonline/templates.py +205 -0
- createsonline/testing.py +322 -0
- createsonline/utils.py +448 -0
- createsonline/validation/__init__.py +49 -0
- createsonline/validation/fields.py +598 -0
- createsonline/validation/models.py +504 -0
- createsonline/validation/validators.py +561 -0
- createsonline/views.py +184 -0
- createsonline-0.1.26.dist-info/METADATA +46 -0
- createsonline-0.1.26.dist-info/RECORD +152 -0
- createsonline-0.1.26.dist-info/WHEEL +5 -0
- createsonline-0.1.26.dist-info/entry_points.txt +2 -0
- createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
- createsonline-0.1.26.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# createsonline/performance/compression.py
|
|
2
|
+
"""
|
|
3
|
+
Ultra-Fast Response Compression for CREATESONLINE
|
|
4
|
+
|
|
5
|
+
Advanced compression algorithms that reduce bandwidth and improve speed:
|
|
6
|
+
- Brotli compression
|
|
7
|
+
- Gzip compression with custom levels
|
|
8
|
+
- Smart compression detection
|
|
9
|
+
- Streaming compression
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import gzip
|
|
13
|
+
import zlib
|
|
14
|
+
import json
|
|
15
|
+
from typing import Union, Dict, Any, Optional
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ResponseCompression:
|
|
19
|
+
"""
|
|
20
|
+
Ultra-fast response compression system
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
self.compression_threshold = 1024 # Only compress responses > 1KB
|
|
25
|
+
self.compression_level = 6 # Balance between speed and ratio
|
|
26
|
+
|
|
27
|
+
# Try to import brotli for better compression
|
|
28
|
+
try:
|
|
29
|
+
import brotli
|
|
30
|
+
self.brotli_available = True
|
|
31
|
+
self.brotli = brotli
|
|
32
|
+
except ImportError:
|
|
33
|
+
self.brotli_available = False
|
|
34
|
+
|
|
35
|
+
def compress_response(self, content: Union[str, bytes], accept_encoding: str = "") -> Dict[str, Any]:
|
|
36
|
+
"""
|
|
37
|
+
Compress response content with optimal algorithm
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
{
|
|
41
|
+
'content': compressed_bytes,
|
|
42
|
+
'encoding': 'br'|'gzip'|'deflate'|None,
|
|
43
|
+
'original_size': int,
|
|
44
|
+
'compressed_size': int,
|
|
45
|
+
'compression_ratio': float
|
|
46
|
+
}
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
# Convert to bytes if needed
|
|
50
|
+
if isinstance(content, str):
|
|
51
|
+
content_bytes = content.encode('utf-8')
|
|
52
|
+
else:
|
|
53
|
+
content_bytes = content
|
|
54
|
+
|
|
55
|
+
original_size = len(content_bytes)
|
|
56
|
+
|
|
57
|
+
# Don't compress small responses
|
|
58
|
+
if original_size < self.compression_threshold:
|
|
59
|
+
return {
|
|
60
|
+
'content': content_bytes,
|
|
61
|
+
'encoding': None,
|
|
62
|
+
'original_size': original_size,
|
|
63
|
+
'compressed_size': original_size,
|
|
64
|
+
'compression_ratio': 1.0
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Determine best compression method
|
|
68
|
+
if self.brotli_available and 'br' in accept_encoding:
|
|
69
|
+
return self._compress_brotli(content_bytes, original_size)
|
|
70
|
+
elif 'gzip' in accept_encoding:
|
|
71
|
+
return self._compress_gzip(content_bytes, original_size)
|
|
72
|
+
elif 'deflate' in accept_encoding:
|
|
73
|
+
return self._compress_deflate(content_bytes, original_size)
|
|
74
|
+
else:
|
|
75
|
+
# No compression
|
|
76
|
+
return {
|
|
77
|
+
'content': content_bytes,
|
|
78
|
+
'encoding': None,
|
|
79
|
+
'original_size': original_size,
|
|
80
|
+
'compressed_size': original_size,
|
|
81
|
+
'compression_ratio': 1.0
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
def _compress_brotli(self, content: bytes, original_size: int) -> Dict[str, Any]:
|
|
85
|
+
"""Compress with Brotli (best compression ratio)"""
|
|
86
|
+
|
|
87
|
+
compressed = self.brotli.compress(
|
|
88
|
+
content,
|
|
89
|
+
quality=4, # Fast compression
|
|
90
|
+
lgwin=22 # Window size for better compression
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
'content': compressed,
|
|
95
|
+
'encoding': 'br',
|
|
96
|
+
'original_size': original_size,
|
|
97
|
+
'compressed_size': len(compressed),
|
|
98
|
+
'compression_ratio': original_size / len(compressed)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
def _compress_gzip(self, content: bytes, original_size: int) -> Dict[str, Any]:
|
|
102
|
+
"""Compress with Gzip"""
|
|
103
|
+
|
|
104
|
+
compressed = gzip.compress(content, compresslevel=self.compression_level)
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
'content': compressed,
|
|
108
|
+
'encoding': 'gzip',
|
|
109
|
+
'original_size': original_size,
|
|
110
|
+
'compressed_size': len(compressed),
|
|
111
|
+
'compression_ratio': original_size / len(compressed)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
def _compress_deflate(self, content: bytes, original_size: int) -> Dict[str, Any]:
|
|
115
|
+
"""Compress with Deflate"""
|
|
116
|
+
|
|
117
|
+
compressed = zlib.compress(content, level=self.compression_level)
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
'content': compressed,
|
|
121
|
+
'encoding': 'deflate',
|
|
122
|
+
'original_size': original_size,
|
|
123
|
+
'compressed_size': len(compressed),
|
|
124
|
+
'compression_ratio': original_size / len(compressed)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
def should_compress(self, content_type: str, content_length: int) -> bool:
|
|
128
|
+
"""Determine if content should be compressed"""
|
|
129
|
+
|
|
130
|
+
# Don't compress small content
|
|
131
|
+
if content_length < self.compression_threshold:
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
# Don't compress already compressed content
|
|
135
|
+
non_compressible = [
|
|
136
|
+
'image/', 'video/', 'audio/',
|
|
137
|
+
'application/zip', 'application/gzip',
|
|
138
|
+
'application/x-rar', 'application/pdf'
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
for non_comp in non_compressible:
|
|
142
|
+
if non_comp in content_type.lower():
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
# Compress text-based content
|
|
146
|
+
compressible = [
|
|
147
|
+
'text/', 'application/json', 'application/xml',
|
|
148
|
+
'application/javascript', 'application/css',
|
|
149
|
+
'application/html'
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
for comp in compressible:
|
|
153
|
+
if comp in content_type.lower():
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
def get_best_encoding(self, accept_encoding: str) -> Optional[str]:
|
|
159
|
+
"""Get the best compression encoding from Accept-Encoding header"""
|
|
160
|
+
|
|
161
|
+
if not accept_encoding:
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
accept_encoding = accept_encoding.lower()
|
|
165
|
+
|
|
166
|
+
# Prefer brotli if available and supported
|
|
167
|
+
if self.brotli_available and 'br' in accept_encoding:
|
|
168
|
+
return 'br'
|
|
169
|
+
elif 'gzip' in accept_encoding:
|
|
170
|
+
return 'gzip'
|
|
171
|
+
elif 'deflate' in accept_encoding:
|
|
172
|
+
return 'deflate'
|
|
173
|
+
else:
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class StreamingCompression:
|
|
178
|
+
"""
|
|
179
|
+
Streaming compression for large responses
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
def __init__(self, encoding: str = 'gzip'):
|
|
183
|
+
self.encoding = encoding
|
|
184
|
+
|
|
185
|
+
if encoding == 'gzip':
|
|
186
|
+
self.compressor = zlib.compressobj(
|
|
187
|
+
level=6,
|
|
188
|
+
method=zlib.DEFLATED,
|
|
189
|
+
wbits=zlib.MAX_WBITS | 16 # Add gzip header
|
|
190
|
+
)
|
|
191
|
+
elif encoding == 'deflate':
|
|
192
|
+
self.compressor = zlib.compressobj(level=6)
|
|
193
|
+
else:
|
|
194
|
+
raise ValueError(f"Unsupported encoding: {encoding}")
|
|
195
|
+
|
|
196
|
+
def compress_chunk(self, chunk: bytes) -> bytes:
|
|
197
|
+
"""Compress a chunk of data"""
|
|
198
|
+
return self.compressor.compress(chunk)
|
|
199
|
+
|
|
200
|
+
def finalize(self) -> bytes:
|
|
201
|
+
"""Finalize compression and return remaining data"""
|
|
202
|
+
return self.compressor.flush()
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class JSONCompression:
|
|
206
|
+
"""
|
|
207
|
+
Specialized JSON compression with optimizations
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
def __init__(self):
|
|
211
|
+
self.common_keys = [
|
|
212
|
+
'id', 'name', 'type', 'value', 'data', 'status', 'message',
|
|
213
|
+
'error', 'success', 'timestamp', 'created', 'updated'
|
|
214
|
+
]
|
|
215
|
+
|
|
216
|
+
# Build key mapping for compression
|
|
217
|
+
self.key_map = {key: chr(65 + i) for i, key in enumerate(self.common_keys)}
|
|
218
|
+
self.reverse_key_map = {v: k for k, v in self.key_map.items()}
|
|
219
|
+
|
|
220
|
+
def compress_json(self, data: Dict[str, Any]) -> str:
|
|
221
|
+
"""Compress JSON by replacing common keys with single characters"""
|
|
222
|
+
|
|
223
|
+
def replace_keys(obj):
|
|
224
|
+
if isinstance(obj, dict):
|
|
225
|
+
new_obj = {}
|
|
226
|
+
for key, value in obj.items():
|
|
227
|
+
new_key = self.key_map.get(key, key)
|
|
228
|
+
new_obj[new_key] = replace_keys(value)
|
|
229
|
+
return new_obj
|
|
230
|
+
elif isinstance(obj, list):
|
|
231
|
+
return [replace_keys(item) for item in obj]
|
|
232
|
+
else:
|
|
233
|
+
return obj
|
|
234
|
+
|
|
235
|
+
compressed_data = replace_keys(data)
|
|
236
|
+
return json.dumps(compressed_data, separators=(',', ':'))
|
|
237
|
+
|
|
238
|
+
def decompress_json(self, compressed_str: str) -> Dict[str, Any]:
|
|
239
|
+
"""Decompress JSON by restoring original keys"""
|
|
240
|
+
|
|
241
|
+
def restore_keys(obj):
|
|
242
|
+
if isinstance(obj, dict):
|
|
243
|
+
new_obj = {}
|
|
244
|
+
for key, value in obj.items():
|
|
245
|
+
original_key = self.reverse_key_map.get(key, key)
|
|
246
|
+
new_obj[original_key] = restore_keys(value)
|
|
247
|
+
return new_obj
|
|
248
|
+
elif isinstance(obj, list):
|
|
249
|
+
return [restore_keys(item) for item in obj]
|
|
250
|
+
else:
|
|
251
|
+
return obj
|
|
252
|
+
|
|
253
|
+
data = json.loads(compressed_str)
|
|
254
|
+
return restore_keys(data)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# Global compression instance
|
|
258
|
+
_global_compressor = None
|
|
259
|
+
|
|
260
|
+
def get_compressor() -> ResponseCompression:
|
|
261
|
+
"""Get global compression instance"""
|
|
262
|
+
global _global_compressor
|
|
263
|
+
if _global_compressor is None:
|
|
264
|
+
_global_compressor = ResponseCompression()
|
|
265
|
+
return _global_compressor
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def compress_middleware():
|
|
269
|
+
"""Middleware for automatic response compression"""
|
|
270
|
+
|
|
271
|
+
def middleware(app):
|
|
272
|
+
original_call = app.__call__
|
|
273
|
+
compressor = get_compressor()
|
|
274
|
+
|
|
275
|
+
async def compressed_app(scope, receive, send):
|
|
276
|
+
if scope['type'] != 'http':
|
|
277
|
+
await original_call(scope, receive, send)
|
|
278
|
+
return
|
|
279
|
+
|
|
280
|
+
# Get Accept-Encoding header
|
|
281
|
+
headers = dict(scope.get('headers', []))
|
|
282
|
+
accept_encoding = headers.get(b'accept-encoding', b'').decode()
|
|
283
|
+
|
|
284
|
+
# Wrap send to compress response
|
|
285
|
+
async def compressed_send(message):
|
|
286
|
+
if message['type'] == 'http.response.start':
|
|
287
|
+
# Store response start for later
|
|
288
|
+
compressed_send.response_start = message
|
|
289
|
+
elif message['type'] == 'http.response.body':
|
|
290
|
+
body = message.get('body', b'')
|
|
291
|
+
|
|
292
|
+
if body and hasattr(compressed_send, 'response_start'):
|
|
293
|
+
# Get content type
|
|
294
|
+
headers = dict(compressed_send.response_start.get('headers', []))
|
|
295
|
+
content_type = headers.get(b'content-type', b'').decode()
|
|
296
|
+
|
|
297
|
+
# Compress if appropriate
|
|
298
|
+
if compressor.should_compress(content_type, len(body)):
|
|
299
|
+
result = compressor.compress_response(body, accept_encoding)
|
|
300
|
+
|
|
301
|
+
if result['encoding']:
|
|
302
|
+
# Update headers
|
|
303
|
+
new_headers = []
|
|
304
|
+
for name, value in compressed_send.response_start.get('headers', []):
|
|
305
|
+
if name.lower() != b'content-length':
|
|
306
|
+
new_headers.append([name, value])
|
|
307
|
+
|
|
308
|
+
new_headers.extend([
|
|
309
|
+
[b'content-encoding', result['encoding'].encode()],
|
|
310
|
+
[b'content-length', str(result['compressed_size']).encode()],
|
|
311
|
+
[b'x-compression-ratio', f"{result['compression_ratio']:.2f}".encode()]
|
|
312
|
+
])
|
|
313
|
+
|
|
314
|
+
compressed_send.response_start['headers'] = new_headers
|
|
315
|
+
body = result['content']
|
|
316
|
+
|
|
317
|
+
# Send response start if not sent yet
|
|
318
|
+
if hasattr(compressed_send, 'response_start'):
|
|
319
|
+
await send(compressed_send.response_start)
|
|
320
|
+
del compressed_send.response_start
|
|
321
|
+
|
|
322
|
+
# Send compressed body
|
|
323
|
+
await send({
|
|
324
|
+
'type': 'http.response.body',
|
|
325
|
+
'body': body,
|
|
326
|
+
'more_body': message.get('more_body', False)
|
|
327
|
+
})
|
|
328
|
+
else:
|
|
329
|
+
await send(message)
|
|
330
|
+
|
|
331
|
+
await original_call(scope, receive, compressed_send)
|
|
332
|
+
|
|
333
|
+
return compressed_app
|
|
334
|
+
|
|
335
|
+
return middleware
|