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,557 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CREATESONLINE Series Implementation
|
|
3
|
+
|
|
4
|
+
Pure Python series data structure.
|
|
5
|
+
Lightweight alternative to Pandas Series.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from typing import Any, Dict, List, Optional, Union, Iterator, Callable
|
|
10
|
+
|
|
11
|
+
# Optional numpy import with fallback
|
|
12
|
+
try:
|
|
13
|
+
import numpy as np
|
|
14
|
+
NUMPY_AVAILABLE = True
|
|
15
|
+
NDArrayType = np.ndarray
|
|
16
|
+
except ImportError:
|
|
17
|
+
NUMPY_AVAILABLE = False
|
|
18
|
+
np = None
|
|
19
|
+
NDArrayType = Any # Fallback type
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CreatesonlineSeries:
|
|
23
|
+
"""
|
|
24
|
+
CREATESONLINE Series - One-dimensional data structure
|
|
25
|
+
|
|
26
|
+
Pure Python implementation of a series data structure similar to Pandas Series
|
|
27
|
+
but with zero external dependencies (except numpy for numerical operations).
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
data: Union[List[Any], Dict[str, Any]] = None,
|
|
33
|
+
index: Optional[List[str]] = None,
|
|
34
|
+
name: Optional[str] = None,
|
|
35
|
+
dtype: Optional[str] = None
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
Initialize CREATESONLINE Series
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
data: Series data as list, array, or dict
|
|
42
|
+
index: Index labels for the data
|
|
43
|
+
name: Name of the series
|
|
44
|
+
dtype: Data type hint
|
|
45
|
+
"""
|
|
46
|
+
self.name = name
|
|
47
|
+
self.dtype = dtype
|
|
48
|
+
|
|
49
|
+
if data is None:
|
|
50
|
+
self._data = []
|
|
51
|
+
self._index = []
|
|
52
|
+
elif isinstance(data, dict):
|
|
53
|
+
self._index = list(data.keys())
|
|
54
|
+
self._data = list(data.values())
|
|
55
|
+
elif isinstance(data, (list, tuple)):
|
|
56
|
+
self._data = list(data)
|
|
57
|
+
self._index = index or list(range(len(self._data)))
|
|
58
|
+
elif NUMPY_AVAILABLE and hasattr(data, 'tolist'): # numpy array
|
|
59
|
+
self._data = data.tolist()
|
|
60
|
+
self._index = index or list(range(len(self._data)))
|
|
61
|
+
else:
|
|
62
|
+
self._data = [data]
|
|
63
|
+
self._index = index or [0]
|
|
64
|
+
|
|
65
|
+
# Ensure index and data have same length
|
|
66
|
+
if len(self._index) != len(self._data):
|
|
67
|
+
if index is None:
|
|
68
|
+
self._index = list(range(len(self._data)))
|
|
69
|
+
else:
|
|
70
|
+
raise ValueError("Index length must match data length")
|
|
71
|
+
|
|
72
|
+
def __len__(self) -> int:
|
|
73
|
+
"""Return length of series"""
|
|
74
|
+
return len(self._data)
|
|
75
|
+
|
|
76
|
+
def __getitem__(self, key: Union[str, int, slice, List[Union[str, int]]]) -> Union[Any, 'CreatesonlineSeries']:
|
|
77
|
+
"""Get item(s) from series"""
|
|
78
|
+
if isinstance(key, (int, slice)):
|
|
79
|
+
if isinstance(key, slice):
|
|
80
|
+
return CreatesonlineSeries(
|
|
81
|
+
data=self._data[key],
|
|
82
|
+
index=self._index[key],
|
|
83
|
+
name=self.name
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
return self._data[key]
|
|
87
|
+
elif isinstance(key, str):
|
|
88
|
+
if key in self._index:
|
|
89
|
+
idx = self._index.index(key)
|
|
90
|
+
return self._data[idx]
|
|
91
|
+
else:
|
|
92
|
+
raise KeyError(f"Key '{key}' not found in series")
|
|
93
|
+
elif isinstance(key, list):
|
|
94
|
+
result_data = []
|
|
95
|
+
result_index = []
|
|
96
|
+
for k in key:
|
|
97
|
+
if isinstance(k, str) and k in self._index:
|
|
98
|
+
idx = self._index.index(k)
|
|
99
|
+
result_data.append(self._data[idx])
|
|
100
|
+
result_index.append(k)
|
|
101
|
+
elif isinstance(k, int) and 0 <= k < len(self._data):
|
|
102
|
+
result_data.append(self._data[k])
|
|
103
|
+
result_index.append(self._index[k])
|
|
104
|
+
else:
|
|
105
|
+
raise KeyError(f"Key '{k}' not found in series")
|
|
106
|
+
return CreatesonlineSeries(
|
|
107
|
+
data=result_data,
|
|
108
|
+
index=result_index,
|
|
109
|
+
name=self.name
|
|
110
|
+
)
|
|
111
|
+
else:
|
|
112
|
+
raise TypeError(f"Invalid key type: {type(key)}")
|
|
113
|
+
|
|
114
|
+
def __setitem__(self, key: Union[str, int], value: Any):
|
|
115
|
+
"""Set item in series"""
|
|
116
|
+
if isinstance(key, int):
|
|
117
|
+
if 0 <= key < len(self._data):
|
|
118
|
+
self._data[key] = value
|
|
119
|
+
else:
|
|
120
|
+
raise IndexError("Index out of range")
|
|
121
|
+
elif isinstance(key, str):
|
|
122
|
+
if key in self._index:
|
|
123
|
+
idx = self._index.index(key)
|
|
124
|
+
self._data[idx] = value
|
|
125
|
+
else:
|
|
126
|
+
# Add new item
|
|
127
|
+
self._index.append(key)
|
|
128
|
+
self._data.append(value)
|
|
129
|
+
else:
|
|
130
|
+
raise TypeError(f"Invalid key type: {type(key)}")
|
|
131
|
+
|
|
132
|
+
def __iter__(self) -> Iterator[Any]:
|
|
133
|
+
"""Iterate over series values"""
|
|
134
|
+
return iter(self._data)
|
|
135
|
+
|
|
136
|
+
def __str__(self) -> str:
|
|
137
|
+
"""String representation"""
|
|
138
|
+
lines = []
|
|
139
|
+
for i, (idx, val) in enumerate(zip(self._index, self._data)):
|
|
140
|
+
lines.append(f"{idx} {val}")
|
|
141
|
+
if i >= 20: # Limit display
|
|
142
|
+
lines.append("...")
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
if self.name:
|
|
146
|
+
lines.append(f"Name: {self.name}")
|
|
147
|
+
|
|
148
|
+
return "\n".join(lines)
|
|
149
|
+
|
|
150
|
+
def __repr__(self) -> str:
|
|
151
|
+
"""String representation"""
|
|
152
|
+
return self.__str__()
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def values(self) -> List[Any]:
|
|
156
|
+
"""Get series values as list"""
|
|
157
|
+
return self._data.copy()
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def index(self) -> List[str]:
|
|
161
|
+
"""Get series index"""
|
|
162
|
+
return self._index.copy()
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def shape(self) -> tuple:
|
|
166
|
+
"""Get series shape"""
|
|
167
|
+
return (len(self._data),)
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def size(self) -> int:
|
|
171
|
+
"""Get series size"""
|
|
172
|
+
return len(self._data)
|
|
173
|
+
|
|
174
|
+
def head(self, n: int = 5) -> 'CreatesonlineSeries':
|
|
175
|
+
"""Get first n elements"""
|
|
176
|
+
return self[:n]
|
|
177
|
+
|
|
178
|
+
def tail(self, n: int = 5) -> 'CreatesonlineSeries':
|
|
179
|
+
"""Get last n elements"""
|
|
180
|
+
return self[-n:]
|
|
181
|
+
|
|
182
|
+
def copy(self) -> 'CreatesonlineSeries':
|
|
183
|
+
"""Create a copy of the series"""
|
|
184
|
+
return CreatesonlineSeries(
|
|
185
|
+
data=self._data.copy(),
|
|
186
|
+
index=self._index.copy(),
|
|
187
|
+
name=self.name,
|
|
188
|
+
dtype=self.dtype
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def reset_index(self, drop: bool = True) -> 'CreatesonlineSeries':
|
|
192
|
+
"""Reset index to default integer index"""
|
|
193
|
+
if drop:
|
|
194
|
+
return CreatesonlineSeries(
|
|
195
|
+
data=self._data.copy(),
|
|
196
|
+
name=self.name,
|
|
197
|
+
dtype=self.dtype
|
|
198
|
+
)
|
|
199
|
+
else:
|
|
200
|
+
# Return DataFrame with old index as column
|
|
201
|
+
from .dataframe import CreatesonlineDataFrame
|
|
202
|
+
return CreatesonlineDataFrame({
|
|
203
|
+
'index': self._index.copy(),
|
|
204
|
+
self.name or 'value': self._data.copy()
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
def sort_values(self, ascending: bool = True) -> 'CreatesonlineSeries':
|
|
208
|
+
"""Sort series by values"""
|
|
209
|
+
paired = list(zip(self._data, self._index))
|
|
210
|
+
paired.sort(key=lambda x: x[0], reverse=not ascending)
|
|
211
|
+
|
|
212
|
+
sorted_data, sorted_index = zip(*paired)
|
|
213
|
+
return CreatesonlineSeries(
|
|
214
|
+
data=list(sorted_data),
|
|
215
|
+
index=list(sorted_index),
|
|
216
|
+
name=self.name,
|
|
217
|
+
dtype=self.dtype
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
def sort_index(self, ascending: bool = True) -> 'CreatesonlineSeries':
|
|
221
|
+
"""Sort series by index"""
|
|
222
|
+
paired = list(zip(self._index, self._data))
|
|
223
|
+
paired.sort(key=lambda x: x[0], reverse=not ascending)
|
|
224
|
+
|
|
225
|
+
sorted_index, sorted_data = zip(*paired)
|
|
226
|
+
return CreatesonlineSeries(
|
|
227
|
+
data=list(sorted_data),
|
|
228
|
+
index=list(sorted_index),
|
|
229
|
+
name=self.name,
|
|
230
|
+
dtype=self.dtype
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def unique(self) -> 'CreatesonlineSeries':
|
|
234
|
+
"""Get unique values"""
|
|
235
|
+
seen = set()
|
|
236
|
+
unique_data = []
|
|
237
|
+
unique_index = []
|
|
238
|
+
|
|
239
|
+
for val, idx in zip(self._data, self._index):
|
|
240
|
+
if val not in seen:
|
|
241
|
+
seen.add(val)
|
|
242
|
+
unique_data.append(val)
|
|
243
|
+
unique_index.append(idx)
|
|
244
|
+
|
|
245
|
+
return CreatesonlineSeries(
|
|
246
|
+
data=unique_data,
|
|
247
|
+
index=unique_index,
|
|
248
|
+
name=self.name,
|
|
249
|
+
dtype=self.dtype
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def value_counts(self) -> 'CreatesonlineSeries':
|
|
253
|
+
"""Count occurrences of each value"""
|
|
254
|
+
counts = {}
|
|
255
|
+
for val in self._data:
|
|
256
|
+
counts[val] = counts.get(val, 0) + 1
|
|
257
|
+
|
|
258
|
+
return CreatesonlineSeries(
|
|
259
|
+
data=list(counts.values()),
|
|
260
|
+
index=list(counts.keys()),
|
|
261
|
+
name='count'
|
|
262
|
+
).sort_values(ascending=False)
|
|
263
|
+
|
|
264
|
+
def apply(self, func: Callable[[Any], Any]) -> 'CreatesonlineSeries':
|
|
265
|
+
"""Apply function to each element"""
|
|
266
|
+
new_data = [func(val) for val in self._data]
|
|
267
|
+
return CreatesonlineSeries(
|
|
268
|
+
data=new_data,
|
|
269
|
+
index=self._index.copy(),
|
|
270
|
+
name=self.name,
|
|
271
|
+
dtype=self.dtype
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
def map(self, mapping: Union[Dict[Any, Any], Callable[[Any], Any]]) -> 'CreatesonlineSeries':
|
|
275
|
+
"""Map values using dictionary or function"""
|
|
276
|
+
if callable(mapping):
|
|
277
|
+
return self.apply(mapping)
|
|
278
|
+
else:
|
|
279
|
+
new_data = [mapping.get(val, val) for val in self._data]
|
|
280
|
+
return CreatesonlineSeries(
|
|
281
|
+
data=new_data,
|
|
282
|
+
index=self._index.copy(),
|
|
283
|
+
name=self.name,
|
|
284
|
+
dtype=self.dtype
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
def filter(self, condition: Callable[[Any], bool]) -> 'CreatesonlineSeries':
|
|
288
|
+
"""Filter series based on condition"""
|
|
289
|
+
filtered_data = []
|
|
290
|
+
filtered_index = []
|
|
291
|
+
|
|
292
|
+
for val, idx in zip(self._data, self._index):
|
|
293
|
+
if condition(val):
|
|
294
|
+
filtered_data.append(val)
|
|
295
|
+
filtered_index.append(idx)
|
|
296
|
+
|
|
297
|
+
return CreatesonlineSeries(
|
|
298
|
+
data=filtered_data,
|
|
299
|
+
index=filtered_index,
|
|
300
|
+
name=self.name,
|
|
301
|
+
dtype=self.dtype
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def dropna(self) -> 'CreatesonlineSeries':
|
|
305
|
+
"""Drop null/None values"""
|
|
306
|
+
return self.filter(lambda x: x is not None)
|
|
307
|
+
|
|
308
|
+
def fillna(self, value: Any) -> 'CreatesonlineSeries':
|
|
309
|
+
"""Fill null/None values with specified value"""
|
|
310
|
+
return self.map(lambda x: value if x is None else x)
|
|
311
|
+
|
|
312
|
+
def isna(self) -> 'CreatesonlineSeries':
|
|
313
|
+
"""Check for null/None values"""
|
|
314
|
+
return CreatesonlineSeries(
|
|
315
|
+
data=[val is None for val in self._data],
|
|
316
|
+
index=self._index.copy(),
|
|
317
|
+
name=f'{self.name}_isna' if self.name else 'isna'
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
def sum(self) -> Union[float, int]:
|
|
321
|
+
"""Sum of numeric values"""
|
|
322
|
+
numeric_values = [val for val in self._data if isinstance(val, (int, float))]
|
|
323
|
+
return sum(numeric_values) if numeric_values else 0
|
|
324
|
+
|
|
325
|
+
def mean(self) -> float:
|
|
326
|
+
"""Mean of numeric values"""
|
|
327
|
+
numeric_values = [val for val in self._data if isinstance(val, (int, float))]
|
|
328
|
+
return sum(numeric_values) / len(numeric_values) if numeric_values else 0.0
|
|
329
|
+
|
|
330
|
+
def median(self) -> float:
|
|
331
|
+
"""Median of numeric values"""
|
|
332
|
+
numeric_values = sorted([val for val in self._data if isinstance(val, (int, float))])
|
|
333
|
+
n = len(numeric_values)
|
|
334
|
+
if n == 0:
|
|
335
|
+
return 0.0
|
|
336
|
+
elif n % 2 == 0:
|
|
337
|
+
return (numeric_values[n//2 - 1] + numeric_values[n//2]) / 2
|
|
338
|
+
else:
|
|
339
|
+
return numeric_values[n//2]
|
|
340
|
+
|
|
341
|
+
def std(self) -> float:
|
|
342
|
+
"""Standard deviation of numeric values"""
|
|
343
|
+
numeric_values = [val for val in self._data if isinstance(val, (int, float))]
|
|
344
|
+
if len(numeric_values) < 2:
|
|
345
|
+
return 0.0
|
|
346
|
+
|
|
347
|
+
mean_val = self.mean()
|
|
348
|
+
variance = sum((val - mean_val) ** 2 for val in numeric_values) / (len(numeric_values) - 1)
|
|
349
|
+
return variance ** 0.5
|
|
350
|
+
|
|
351
|
+
def min(self) -> Any:
|
|
352
|
+
"""Minimum value"""
|
|
353
|
+
return min(self._data) if self._data else None
|
|
354
|
+
|
|
355
|
+
def max(self) -> Any:
|
|
356
|
+
"""Maximum value"""
|
|
357
|
+
return max(self._data) if self._data else None
|
|
358
|
+
|
|
359
|
+
def describe(self) -> Dict[str, Any]:
|
|
360
|
+
"""Descriptive statistics"""
|
|
361
|
+
numeric_values = [val for val in self._data if isinstance(val, (int, float))]
|
|
362
|
+
|
|
363
|
+
if not numeric_values:
|
|
364
|
+
return {
|
|
365
|
+
'count': len(self._data),
|
|
366
|
+
'unique': len(set(self._data)),
|
|
367
|
+
'top': max(set(self._data), key=self._data.count) if self._data else None,
|
|
368
|
+
'freq': max([self._data.count(val) for val in set(self._data)]) if self._data else 0
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
'count': len(numeric_values),
|
|
373
|
+
'mean': self.mean(),
|
|
374
|
+
'std': self.std(),
|
|
375
|
+
'min': min(numeric_values),
|
|
376
|
+
'25%': self._quantile(numeric_values, 0.25),
|
|
377
|
+
'50%': self.median(),
|
|
378
|
+
'75%': self._quantile(numeric_values, 0.75),
|
|
379
|
+
'max': max(numeric_values)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
def _quantile(self, values: List[Union[int, float]], q: float) -> float:
|
|
383
|
+
"""Calculate quantile"""
|
|
384
|
+
sorted_values = sorted(values)
|
|
385
|
+
n = len(sorted_values)
|
|
386
|
+
index = q * (n - 1)
|
|
387
|
+
|
|
388
|
+
if index.is_integer():
|
|
389
|
+
return sorted_values[int(index)]
|
|
390
|
+
else:
|
|
391
|
+
lower = sorted_values[int(index)]
|
|
392
|
+
upper = sorted_values[int(index) + 1]
|
|
393
|
+
return lower + (upper - lower) * (index - int(index))
|
|
394
|
+
|
|
395
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
396
|
+
"""Convert series to dictionary"""
|
|
397
|
+
return dict(zip(self._index, self._data))
|
|
398
|
+
|
|
399
|
+
def to_list(self) -> List[Any]:
|
|
400
|
+
"""Convert series to list"""
|
|
401
|
+
return self._data.copy()
|
|
402
|
+
|
|
403
|
+
def to_json(self, indent: Optional[int] = None) -> str:
|
|
404
|
+
"""Convert series to JSON string"""
|
|
405
|
+
return json.dumps(self.to_dict(), indent=indent, default=str)
|
|
406
|
+
|
|
407
|
+
def to_numpy(self) -> NDArrayType:
|
|
408
|
+
"""Convert series to numpy array"""
|
|
409
|
+
return np.array(self._data)
|
|
410
|
+
|
|
411
|
+
# Mathematical operations
|
|
412
|
+
def __add__(self, other: Union['CreatesonlineSeries', int, float]) -> 'CreatesonlineSeries':
|
|
413
|
+
"""Addition"""
|
|
414
|
+
if isinstance(other, CreatesonlineSeries):
|
|
415
|
+
if len(self) != len(other):
|
|
416
|
+
raise ValueError("Series lengths must match")
|
|
417
|
+
new_data = [a + b for a, b in zip(self._data, other._data)]
|
|
418
|
+
else:
|
|
419
|
+
new_data = [val + other if isinstance(val, (int, float)) else val for val in self._data]
|
|
420
|
+
|
|
421
|
+
return CreatesonlineSeries(
|
|
422
|
+
data=new_data,
|
|
423
|
+
index=self._index.copy(),
|
|
424
|
+
name=self.name
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
def __sub__(self, other: Union['CreatesonlineSeries', int, float]) -> 'CreatesonlineSeries':
|
|
428
|
+
"""Subtraction"""
|
|
429
|
+
if isinstance(other, CreatesonlineSeries):
|
|
430
|
+
if len(self) != len(other):
|
|
431
|
+
raise ValueError("Series lengths must match")
|
|
432
|
+
new_data = [a - b for a, b in zip(self._data, other._data)]
|
|
433
|
+
else:
|
|
434
|
+
new_data = [val - other if isinstance(val, (int, float)) else val for val in self._data]
|
|
435
|
+
|
|
436
|
+
return CreatesonlineSeries(
|
|
437
|
+
data=new_data,
|
|
438
|
+
index=self._index.copy(),
|
|
439
|
+
name=self.name
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
def __mul__(self, other: Union['CreatesonlineSeries', int, float]) -> 'CreatesonlineSeries':
|
|
443
|
+
"""Multiplication"""
|
|
444
|
+
if isinstance(other, CreatesonlineSeries):
|
|
445
|
+
if len(self) != len(other):
|
|
446
|
+
raise ValueError("Series lengths must match")
|
|
447
|
+
new_data = [a * b for a, b in zip(self._data, other._data)]
|
|
448
|
+
else:
|
|
449
|
+
new_data = [val * other if isinstance(val, (int, float)) else val for val in self._data]
|
|
450
|
+
|
|
451
|
+
return CreatesonlineSeries(
|
|
452
|
+
data=new_data,
|
|
453
|
+
index=self._index.copy(),
|
|
454
|
+
name=self.name
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
def __truediv__(self, other: Union['CreatesonlineSeries', int, float]) -> 'CreatesonlineSeries':
|
|
458
|
+
"""Division"""
|
|
459
|
+
if isinstance(other, CreatesonlineSeries):
|
|
460
|
+
if len(self) != len(other):
|
|
461
|
+
raise ValueError("Series lengths must match")
|
|
462
|
+
new_data = [a / b if b != 0 else float('inf') for a, b in zip(self._data, other._data)]
|
|
463
|
+
else:
|
|
464
|
+
if other == 0:
|
|
465
|
+
raise ZeroDivisionError("Division by zero")
|
|
466
|
+
new_data = [val / other if isinstance(val, (int, float)) else val for val in self._data]
|
|
467
|
+
|
|
468
|
+
return CreatesonlineSeries(
|
|
469
|
+
data=new_data,
|
|
470
|
+
index=self._index.copy(),
|
|
471
|
+
name=self.name
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
# Comparison operations
|
|
475
|
+
def __eq__(self, other: Union['CreatesonlineSeries', Any]) -> 'CreatesonlineSeries':
|
|
476
|
+
"""Equality comparison"""
|
|
477
|
+
if isinstance(other, CreatesonlineSeries):
|
|
478
|
+
new_data = [a == b for a, b in zip(self._data, other._data)]
|
|
479
|
+
else:
|
|
480
|
+
new_data = [val == other for val in self._data]
|
|
481
|
+
|
|
482
|
+
return CreatesonlineSeries(
|
|
483
|
+
data=new_data,
|
|
484
|
+
index=self._index.copy(),
|
|
485
|
+
name=f'{self.name}_eq' if self.name else 'eq'
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
def __ne__(self, other: Union['CreatesonlineSeries', Any]) -> 'CreatesonlineSeries':
|
|
489
|
+
"""Not equal comparison"""
|
|
490
|
+
return ~(self == other)
|
|
491
|
+
|
|
492
|
+
def __lt__(self, other: Union['CreatesonlineSeries', Any]) -> 'CreatesonlineSeries':
|
|
493
|
+
"""Less than comparison"""
|
|
494
|
+
if isinstance(other, CreatesonlineSeries):
|
|
495
|
+
new_data = [a < b for a, b in zip(self._data, other._data)]
|
|
496
|
+
else:
|
|
497
|
+
new_data = [val < other if isinstance(val, (int, float)) else False for val in self._data]
|
|
498
|
+
|
|
499
|
+
return CreatesonlineSeries(
|
|
500
|
+
data=new_data,
|
|
501
|
+
index=self._index.copy(),
|
|
502
|
+
name=f'{self.name}_lt' if self.name else 'lt'
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
def __le__(self, other: Union['CreatesonlineSeries', Any]) -> 'CreatesonlineSeries':
|
|
506
|
+
"""Less than or equal comparison"""
|
|
507
|
+
return (self < other) | (self == other)
|
|
508
|
+
|
|
509
|
+
def __gt__(self, other: Union['CreatesonlineSeries', Any]) -> 'CreatesonlineSeries':
|
|
510
|
+
"""Greater than comparison"""
|
|
511
|
+
if isinstance(other, CreatesonlineSeries):
|
|
512
|
+
new_data = [a > b for a, b in zip(self._data, other._data)]
|
|
513
|
+
else:
|
|
514
|
+
new_data = [val > other if isinstance(val, (int, float)) else False for val in self._data]
|
|
515
|
+
|
|
516
|
+
return CreatesonlineSeries(
|
|
517
|
+
data=new_data,
|
|
518
|
+
index=self._index.copy(),
|
|
519
|
+
name=f'{self.name}_gt' if self.name else 'gt'
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
def __ge__(self, other: Union['CreatesonlineSeries', Any]) -> 'CreatesonlineSeries':
|
|
523
|
+
"""Greater than or equal comparison"""
|
|
524
|
+
return (self > other) | (self == other)
|
|
525
|
+
|
|
526
|
+
def __invert__(self) -> 'CreatesonlineSeries':
|
|
527
|
+
"""Logical NOT for boolean series"""
|
|
528
|
+
new_data = [not val for val in self._data]
|
|
529
|
+
return CreatesonlineSeries(
|
|
530
|
+
data=new_data,
|
|
531
|
+
index=self._index.copy(),
|
|
532
|
+
name=f'{self.name}_not' if self.name else 'not'
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
def __or__(self, other: 'CreatesonlineSeries') -> 'CreatesonlineSeries':
|
|
536
|
+
"""Logical OR for boolean series"""
|
|
537
|
+
if len(self) != len(other):
|
|
538
|
+
raise ValueError("Series lengths must match")
|
|
539
|
+
|
|
540
|
+
new_data = [a or b for a, b in zip(self._data, other._data)]
|
|
541
|
+
return CreatesonlineSeries(
|
|
542
|
+
data=new_data,
|
|
543
|
+
index=self._index.copy(),
|
|
544
|
+
name=f'{self.name}_or' if self.name else 'or'
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
def __and__(self, other: 'CreatesonlineSeries') -> 'CreatesonlineSeries':
|
|
548
|
+
"""Logical AND for boolean series"""
|
|
549
|
+
if len(self) != len(other):
|
|
550
|
+
raise ValueError("Series lengths must match")
|
|
551
|
+
|
|
552
|
+
new_data = [a and b for a, b in zip(self._data, other._data)]
|
|
553
|
+
return CreatesonlineSeries(
|
|
554
|
+
data=new_data,
|
|
555
|
+
index=self._index.copy(),
|
|
556
|
+
name=f'{self.name}_and' if self.name else 'and'
|
|
557
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CREATESONLINE Database Abstraction Layer
|
|
3
|
+
|
|
4
|
+
Pure Python database abstraction with zero external dependencies (except SQLAlchemy).
|
|
5
|
+
Clean API that hides SQLAlchemy complexity while providing AI-native features.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .abstraction import Database, Connection, Transaction
|
|
9
|
+
from .models import CreatesonlineModel, QueryBuilder
|
|
10
|
+
from .fields import (
|
|
11
|
+
CreatesonlineField, StringField, IntegerField, FloatField,
|
|
12
|
+
BooleanField, DateTimeField, TextField, JSONField,
|
|
13
|
+
EmbeddingField, SlugField, EmailField, URLField
|
|
14
|
+
)
|
|
15
|
+
from .migrations import MigrationManager, Migration
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
# Core database
|
|
19
|
+
'Database',
|
|
20
|
+
'Connection',
|
|
21
|
+
'Transaction',
|
|
22
|
+
|
|
23
|
+
# Models
|
|
24
|
+
'CreatesonlineModel',
|
|
25
|
+
'QueryBuilder',
|
|
26
|
+
|
|
27
|
+
# Fields
|
|
28
|
+
'CreatesonlineField',
|
|
29
|
+
'StringField',
|
|
30
|
+
'IntegerField',
|
|
31
|
+
'FloatField',
|
|
32
|
+
'BooleanField',
|
|
33
|
+
'DateTimeField',
|
|
34
|
+
'TextField',
|
|
35
|
+
'JSONField',
|
|
36
|
+
'EmbeddingField',
|
|
37
|
+
'SlugField',
|
|
38
|
+
'EmailField',
|
|
39
|
+
'URLField',
|
|
40
|
+
|
|
41
|
+
# Migrations
|
|
42
|
+
'MigrationManager',
|
|
43
|
+
'Migration'
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# Global database instance
|
|
47
|
+
_database_instance = None
|
|
48
|
+
|
|
49
|
+
def get_database() -> Database:
|
|
50
|
+
"""Get global database instance"""
|
|
51
|
+
global _database_instance
|
|
52
|
+
if _database_instance is None:
|
|
53
|
+
_database_instance = Database()
|
|
54
|
+
return _database_instance
|
|
55
|
+
|
|
56
|
+
def init_database(database_url: str = None, **kwargs) -> Database:
|
|
57
|
+
"""Initialize database with custom configuration"""
|
|
58
|
+
global _database_instance
|
|
59
|
+
_database_instance = Database(database_url=database_url, **kwargs)
|
|
60
|
+
return _database_instance
|