db-attribute 2.1__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.
- db_attribute/__init__.py +320 -0
- db_attribute/connector.py +31 -0
- db_attribute/db_class.py +942 -0
- db_attribute/db_types.py +178 -0
- db_attribute/db_work.py +365 -0
- db_attribute/discriptor.py +176 -0
- db_attribute-2.1.dist-info/METADATA +398 -0
- db_attribute-2.1.dist-info/RECORD +11 -0
- db_attribute-2.1.dist-info/WHEEL +5 -0
- db_attribute-2.1.dist-info/licenses/LICENSE +21 -0
- db_attribute-2.1.dist-info/top_level.txt +1 -0
db_attribute/db_class.py
ADDED
|
@@ -0,0 +1,942 @@
|
|
|
1
|
+
import copy, ast, functools, inspect, sys
|
|
2
|
+
import datetime
|
|
3
|
+
import pickle
|
|
4
|
+
import json
|
|
5
|
+
import orjson
|
|
6
|
+
import collections
|
|
7
|
+
|
|
8
|
+
def MethodDecorator(func=None, /, convert_arguments=True, call_the_decoreted_func=False, call_update_obj=True):
|
|
9
|
+
"""
|
|
10
|
+
decorator for methods, where updated obj | args can convert
|
|
11
|
+
:param convert_arguments: if True (default), convert all arguments from args and kwargs to DbClass objects (if this type obj is supported) (not convert if this class methode)
|
|
12
|
+
:param call_the_decoreted_func: if False (default), call this func from self._standart_class, if True, call from self.__class__
|
|
13
|
+
:param call_update_obj: if True (default), call the self._update_obj(), set False if func not updated the obj
|
|
14
|
+
:return:
|
|
15
|
+
"""
|
|
16
|
+
def wrap(func):
|
|
17
|
+
@functools.wraps(func)
|
|
18
|
+
def wrapper(self, *args, **kwargs):
|
|
19
|
+
if convert_arguments:
|
|
20
|
+
args = (cheaker.create_db_class(i, _first_container=self._first_container if self._first_container else _FirstContainer(self)) for i in args)
|
|
21
|
+
kwargs = {key: cheaker.create_db_class(kwargs[key], _first_container=self._first_container if self._first_container else _FirstContainer(self)) for key in kwargs}
|
|
22
|
+
|
|
23
|
+
if call_the_decoreted_func:
|
|
24
|
+
data = func(self, *args, **kwargs)
|
|
25
|
+
if call_update_obj:
|
|
26
|
+
self._update_obj()
|
|
27
|
+
return data
|
|
28
|
+
|
|
29
|
+
data = getattr(self._standart_class, func.__name__)(self, *args, **kwargs)
|
|
30
|
+
if call_update_obj:
|
|
31
|
+
self._update_obj()
|
|
32
|
+
return data
|
|
33
|
+
return wrapper
|
|
34
|
+
if func:
|
|
35
|
+
return wrap(func)
|
|
36
|
+
return wrap
|
|
37
|
+
|
|
38
|
+
def DbClassDecorator(cls=None, /, convert_arguments_ioperation_methodes=False, convert_arguments_changes_methodes=True, list_of_non_replaceable_methodes=None, list_of_methodes_with_converted_arguments=None, methode__new__needs_arguments=False):
|
|
39
|
+
"""
|
|
40
|
+
Use DbClassDecorator for
|
|
41
|
+
1) set cls._standart_class (example: for DbList standart class is list)
|
|
42
|
+
2) automatic create __setitem__, __delitem__, __setattr__, __delattr__, __iadd__, __isub__, __imul__, __imatmul__, __ipow__, __idiv__, __ifloordiv__, __itruediv__, __ilshift__, __irshift__, __imod__, __ior__, __iand__, __ixor__
|
|
43
|
+
(DbClassDecorator not created __add__, __sub__, __mul__ and other methodes!)
|
|
44
|
+
If a class has any methods (example: __iadd__), these methods are not replaced.
|
|
45
|
+
But if the parent class has these methods, they will be replaced.
|
|
46
|
+
So use the list_of_non_replaceable_methodes to set a list of non-replaceable methods
|
|
47
|
+
:param convert_arguments_ioperation_methodes: convert input arguments of i operation metodes (__iadd__) to DbClasses
|
|
48
|
+
:param convert_arguments_changes_methodes: convert input arguments of changes metodes (__delitem__, __setattr__) to DbClasses
|
|
49
|
+
:param list_of_non_replaceable_methodes: list of method names that belong to the parent class and will not be replaced by the decorator, ex: ['__iadd__']
|
|
50
|
+
:param list_of_methodes_with_converted_arguments: list of methods that need to be individually replaced with arguments, but param convert_arguments... is False, ex: ['__iadd__']
|
|
51
|
+
:return:
|
|
52
|
+
"""
|
|
53
|
+
if list_of_non_replaceable_methodes is None:
|
|
54
|
+
list_of_non_replaceable_methodes = []
|
|
55
|
+
if list_of_methodes_with_converted_arguments is None:
|
|
56
|
+
list_of_methodes_with_converted_arguments = []
|
|
57
|
+
def wrapper(cls):
|
|
58
|
+
if cls.__dict__.get('_standart_class', None) is None:
|
|
59
|
+
ind = cls.__mro__.index(DbClass)
|
|
60
|
+
if ind + 1 == len(cls.__mro__):
|
|
61
|
+
raise f'The DbClass the last in {cls}.__mro__, please set _standart_class, or add perent to class'
|
|
62
|
+
cls._standart_class = cls.__mro__[ind + 1]
|
|
63
|
+
if cls.__dict__.get('_methode__new__needs_arguments', None) is None:
|
|
64
|
+
cls._methode__new__needs_arguments = methode__new__needs_arguments
|
|
65
|
+
|
|
66
|
+
def getimethod(truefunc, namefunc=''):
|
|
67
|
+
convert_arguments = convert_arguments_ioperation_methodes
|
|
68
|
+
if namefunc in list_of_methodes_with_converted_arguments:
|
|
69
|
+
convert_arguments = True
|
|
70
|
+
def wrapper(self, *args, _update=True, **kwargs):
|
|
71
|
+
if convert_arguments:
|
|
72
|
+
args = (cheaker.create_db_class(i, _first_container=self._first_container) for i in args)
|
|
73
|
+
kwargs = {key: cheaker.create_db_class(kwargs[key], _first_container=self._first_container) for key in kwargs}
|
|
74
|
+
obj = truefunc(self, *args, **kwargs)
|
|
75
|
+
if _update and isinstance(obj, DbClass):
|
|
76
|
+
obj._update_obj()
|
|
77
|
+
return obj
|
|
78
|
+
return wrapper
|
|
79
|
+
|
|
80
|
+
def getmethod(truefunc, namefunc=''):
|
|
81
|
+
convert_arguments = convert_arguments_changes_methodes
|
|
82
|
+
if namefunc in list_of_methodes_with_converted_arguments:
|
|
83
|
+
convert_arguments = True
|
|
84
|
+
def wrapper(self, *args, _update=True, **kwargs):
|
|
85
|
+
if convert_arguments:
|
|
86
|
+
args = (cheaker.create_db_class(i, _first_container=self._first_container) for i in args)
|
|
87
|
+
kwargs = {key: cheaker.create_db_class(kwargs[key], _first_container=self._first_container) for key in kwargs}
|
|
88
|
+
|
|
89
|
+
data = truefunc(self, *args, **kwargs)
|
|
90
|
+
if _update: self._update_obj()
|
|
91
|
+
return data
|
|
92
|
+
return wrapper
|
|
93
|
+
|
|
94
|
+
for namefunc in ['__iadd__', '__isub__', '__imul__', '__imatmul__', '__ipow__', '__idiv__', '__ifloordiv__', '__itruediv__', '__ilshift__', '__irshift__', '__imod__', '__ior__', '__iand__', '__ixor__']:
|
|
95
|
+
if hasattr(cls, namefunc) and namefunc not in cls.__dict__ and namefunc not in list_of_non_replaceable_methodes:
|
|
96
|
+
func = getimethod(getattr(cls, namefunc), namefunc)
|
|
97
|
+
setattr(cls, namefunc, func)
|
|
98
|
+
for namefunc in ['__setitem__', '__delitem__', '__setattr__', '__delattr__']:
|
|
99
|
+
if hasattr(cls, namefunc) and namefunc not in cls.__dict__ and namefunc not in list_of_non_replaceable_methodes:
|
|
100
|
+
func = getmethod(getattr(cls, namefunc), namefunc)
|
|
101
|
+
setattr(cls, namefunc, func)
|
|
102
|
+
return cls
|
|
103
|
+
if cls is None:
|
|
104
|
+
return wrapper
|
|
105
|
+
return wrapper(cls)
|
|
106
|
+
|
|
107
|
+
class _FirstContainer:
|
|
108
|
+
def __init__(self, _first_container=None):
|
|
109
|
+
self.container = _first_container.container if isinstance(_first_container, _FirstContainer) else _first_container
|
|
110
|
+
|
|
111
|
+
@DbClassDecorator
|
|
112
|
+
class DbClass:
|
|
113
|
+
_standart_class = object
|
|
114
|
+
_obj_dbattribute = None
|
|
115
|
+
_name_attribute = None
|
|
116
|
+
_first_container = None
|
|
117
|
+
_call_init_when_reconstruct = False
|
|
118
|
+
_methode__new__needs_arguments = False
|
|
119
|
+
|
|
120
|
+
def __new__(cls, *args, _use_db=False, _obj_dbattribute=None, _convert_arguments=True, _name_attribute=None, _first_container=None, **kwargs):
|
|
121
|
+
if not _use_db:
|
|
122
|
+
if cls._methode__new__needs_arguments:
|
|
123
|
+
obj = cls._standart_class.__new__(cls._standart_class, *args, **kwargs)
|
|
124
|
+
else:
|
|
125
|
+
obj = cls._standart_class.__new__(cls._standart_class)
|
|
126
|
+
obj.__init__(*args, **kwargs)
|
|
127
|
+
return obj
|
|
128
|
+
if cls._methode__new__needs_arguments:
|
|
129
|
+
return cls._standart_class.__new__(cls, *args, **kwargs)
|
|
130
|
+
return cls._standart_class.__new__(cls)
|
|
131
|
+
|
|
132
|
+
def __init__(self, *args, _use_db=False, _obj_dbattribute=None, _convert_arguments=True, _name_attribute=None, _first_container=None, _call_init=True, **kwargs):
|
|
133
|
+
if _obj_dbattribute:
|
|
134
|
+
self.__dict__['_obj_dbattribute'] = _obj_dbattribute
|
|
135
|
+
if _name_attribute:
|
|
136
|
+
self.__dict__['_name_attribute'] = _name_attribute
|
|
137
|
+
if self._first_container is None:
|
|
138
|
+
if _first_container is None:
|
|
139
|
+
self.__dict__['_first_container'] = _FirstContainer(self)
|
|
140
|
+
else:
|
|
141
|
+
if not isinstance(_first_container, _FirstContainer):
|
|
142
|
+
_first_container = _FirstContainer(_first_container)
|
|
143
|
+
self.__dict__['_first_container'] = _first_container
|
|
144
|
+
if _call_init:
|
|
145
|
+
super().__init__(*args, **kwargs)
|
|
146
|
+
def __repr__(self):
|
|
147
|
+
return self.__get_repr__(set()) if hasattr(self, '__get_repr__') else super().__repr__()
|
|
148
|
+
def __reduce_ex__(self, protocol):
|
|
149
|
+
temp = super().__reduce_ex__(protocol)
|
|
150
|
+
if len(temp) >= 3 and temp[2] is not None:
|
|
151
|
+
temp = list(temp)
|
|
152
|
+
temp[2] = {key: convert_atr_value_to_json_value(temp[2][key]) for key in temp[2] if key not in {'_obj_dbattribute', '_name_attribute', '_first_container'}}
|
|
153
|
+
if len(temp[2]) == 0:
|
|
154
|
+
temp[2] = None
|
|
155
|
+
temp = tuple(temp)
|
|
156
|
+
return temp
|
|
157
|
+
|
|
158
|
+
def _update_obj(self):
|
|
159
|
+
#print(f'update {self} {self._first_container.container if self._first_container else self._first_container}')
|
|
160
|
+
if self._first_container and self._first_container.container and self._first_container.container._obj_dbattribute:
|
|
161
|
+
self._first_container.container._obj_dbattribute._db_attribute_container_update(self._first_container.container._name_attribute, self._first_container.container)
|
|
162
|
+
|
|
163
|
+
def dumps(self, _return_json=True):
|
|
164
|
+
"""
|
|
165
|
+
If you create dumps methode for your class, yours methode must return the dict object with keys:
|
|
166
|
+
key 't': type - type of this obj, example: {'t': 'DbList', 'd': [1, 2, 3]} (required key).
|
|
167
|
+
key 'd': data - main data (if you realeseted loads methode, tou can rename this key: use 'd'/'data' and other, it doesn't matter),
|
|
168
|
+
example1 (DbDict): {'t': 'DbDict', 'd': {'0': 1, '1': 2, '2': 3}, 'dk': {'0': 'int', '1': 'int', '2': 'int'}}
|
|
169
|
+
example2 (Develp's Db class): {'t': 'DbUserClass', 'd': {'name': *name*, 'age': *age*, 'books': *jsonDbList*}}
|
|
170
|
+
*and others keys | Develop's keys*
|
|
171
|
+
key 'dk': data key (used DbDict)
|
|
172
|
+
Develop ken create his own keys in dump, and use in load - all dict object dump and load, with json
|
|
173
|
+
required param: _return_json - see documentation
|
|
174
|
+
:param _return_json: if false - return dict, if true - return str: json.dumps(dict)
|
|
175
|
+
"""
|
|
176
|
+
data = pickle.dumps(self).decode('latin1')
|
|
177
|
+
if _return_json:
|
|
178
|
+
return json.dumps({'t': self.__class__.__name__, 'd': data}, ensure_ascii=False)
|
|
179
|
+
return {'t': self.__class__.__name__, 'd': data}
|
|
180
|
+
|
|
181
|
+
@classmethod
|
|
182
|
+
def loads(cls, tempdata: str | dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
183
|
+
"""
|
|
184
|
+
(the use of these parameters (_obj_dbattribute, _name_attribute and _first_container) is not intended - they are used inside the project.)
|
|
185
|
+
If you need to create a "loads" method, please give it the name "_loads".
|
|
186
|
+
For create loads methode you can:
|
|
187
|
+
1) see the _loads methodes of DbList, DbDict, DbDatetime and other... (for example)
|
|
188
|
+
2) It's all :) What do you do? Do you read this? Who are you? How much time do you spend on documentation?
|
|
189
|
+
Did you know that this documentation is already outdated by several versions?
|
|
190
|
+
An anecdote: A programmer once created a function and wrote its documentation.
|
|
191
|
+
After a few versions, the function changed completely, and the documentation became outdated.
|
|
192
|
+
Another programmer read the anecdote and was confused about the documentation, as it was no longer relevant.
|
|
193
|
+
|
|
194
|
+
:param tempdata: the dumps obj, example: tempdata = {'t': DbList, 'd': [1, 2, 3]}, or json.loads(tempdata) = {'t': DbList, 'd': [1, 2, 3]}
|
|
195
|
+
:param _obj_dbattribute: link to dbattribute obj
|
|
196
|
+
:param _name_attribute: name this attribute
|
|
197
|
+
:param _first_container: link to 'first container', example: a = [1, [2]] for [2] the 'first container' the [1, [2]]
|
|
198
|
+
:return:
|
|
199
|
+
"""
|
|
200
|
+
if isinstance(tempdata, str):
|
|
201
|
+
tempdata = orjson.loads(tempdata)
|
|
202
|
+
if (not isinstance(tempdata, dict)) or 't' not in tempdata:
|
|
203
|
+
raise Exception(
|
|
204
|
+
f"load error: {tempdata} is not dict or don't have the 't' key"
|
|
205
|
+
)
|
|
206
|
+
loadcls = cheaker.db_class_name_to_db_class.get(tempdata['t'], None)
|
|
207
|
+
if loadcls is None:
|
|
208
|
+
raise Exception(
|
|
209
|
+
f"load error: cheaker don't support the {tempdata['t']}, add this class to cheaker"
|
|
210
|
+
)
|
|
211
|
+
if hasattr(loadcls, '_loads'):
|
|
212
|
+
return loadcls._loads(tempdata, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
213
|
+
return cheaker.create_db_class(pickle.loads(tempdata['d'].encode('latin1')), _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
214
|
+
|
|
215
|
+
@DbClassDecorator(list_of_methodes_with_converted_arguments=['__iadd__'])
|
|
216
|
+
class DbList(DbClass, list):
|
|
217
|
+
_methode__new__needs_arguments = True
|
|
218
|
+
def __init__(self, *args, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
219
|
+
super().__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False)
|
|
220
|
+
list.__init__(self, *args, **kwargs)
|
|
221
|
+
if _convert_arguments:
|
|
222
|
+
self.__convert_arguments__()
|
|
223
|
+
def __get_repr__(self, Objs: set, now: int = 0):
|
|
224
|
+
return '[' + ', '.join([i.__get_repr__(Objs, now + 1) if hasattr(i, '__get_repr__') else repr(i) for i in self]) + ']'
|
|
225
|
+
@classmethod
|
|
226
|
+
def __convert_to_db__(cls, obj: list, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
227
|
+
"""Converted obj to db object: changed type from list to DbList (you can create yourclass method '__convert_to_db__')"""
|
|
228
|
+
if isinstance(obj, Tlist):
|
|
229
|
+
obj.__class__ = cls
|
|
230
|
+
DbClass.__init__(obj, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
231
|
+
obj.__convert_arguments__()
|
|
232
|
+
return obj
|
|
233
|
+
return cls(obj, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
234
|
+
|
|
235
|
+
def __convert_from_db__(self):
|
|
236
|
+
"""
|
|
237
|
+
Currently, this method is not implemented and is not supported. However, we plan to implement and support it in future updates.
|
|
238
|
+
Converted db object to object: changed type from DbList to list (you can create yourclass method '__convert_from_db__')
|
|
239
|
+
"""
|
|
240
|
+
return NotImplemented
|
|
241
|
+
|
|
242
|
+
def __convert_arguments__(self):
|
|
243
|
+
"""Only DbList uses this method"""
|
|
244
|
+
_first_container = self._first_container
|
|
245
|
+
setitem = list.__setitem__
|
|
246
|
+
for key in range(len(self)):
|
|
247
|
+
setitem(self, key, cheaker.create_db_class(self[key], _first_container=_first_container))
|
|
248
|
+
|
|
249
|
+
@MethodDecorator
|
|
250
|
+
def append(self, item, /): pass
|
|
251
|
+
@MethodDecorator
|
|
252
|
+
def insert(self, i, item): pass
|
|
253
|
+
@MethodDecorator
|
|
254
|
+
def pop(self, i=-1): pass
|
|
255
|
+
@MethodDecorator
|
|
256
|
+
def remove(self, item): pass
|
|
257
|
+
@MethodDecorator
|
|
258
|
+
def clear(self): pass
|
|
259
|
+
@MethodDecorator
|
|
260
|
+
def reverse(self): pass
|
|
261
|
+
@MethodDecorator
|
|
262
|
+
def sort(self, /, key=None, reverse=False): pass
|
|
263
|
+
@MethodDecorator
|
|
264
|
+
def extend(self, other): pass
|
|
265
|
+
|
|
266
|
+
def dumps(self, _return_json=True):
|
|
267
|
+
data = [convert_atr_value_to_json_value(i) for i in self]
|
|
268
|
+
if _return_json:
|
|
269
|
+
return json.dumps({'t': self.__class__.__name__, 'd': data})
|
|
270
|
+
return {'t': self.__class__.__name__, 'd': data}
|
|
271
|
+
|
|
272
|
+
@classmethod
|
|
273
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
274
|
+
obj = cls.__new__(cls, _use_db=True)
|
|
275
|
+
if _first_container is None:
|
|
276
|
+
_first_container = _FirstContainer(obj)
|
|
277
|
+
data = [conver_json_value_to_atr_value(value, _first_container=_first_container) for value in tempdata['d']]
|
|
278
|
+
obj.__init__(data, _convert_arguments=False, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
279
|
+
return obj
|
|
280
|
+
|
|
281
|
+
@DbClassDecorator(list_of_methodes_with_converted_arguments=['__ior__', '__iand__'])
|
|
282
|
+
class DbSet(DbClass, set):
|
|
283
|
+
_call_init_when_reconstruct = True
|
|
284
|
+
_methode__new__needs_arguments = True
|
|
285
|
+
|
|
286
|
+
def __init__(self, *args, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
287
|
+
super().__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False)
|
|
288
|
+
iterable = set(args[0])
|
|
289
|
+
if _convert_arguments:
|
|
290
|
+
iterable = {cheaker.create_db_class(i, _first_container=self._first_container) for i in iterable}
|
|
291
|
+
set.__init__(self, iterable)
|
|
292
|
+
|
|
293
|
+
def __repr__(self):
|
|
294
|
+
return set(self).__repr__()
|
|
295
|
+
|
|
296
|
+
@classmethod
|
|
297
|
+
def __convert_to_db__(cls, obj: set, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
298
|
+
return cls(obj, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
299
|
+
|
|
300
|
+
@MethodDecorator
|
|
301
|
+
def add(self, __element, /): pass
|
|
302
|
+
@MethodDecorator
|
|
303
|
+
def remove(self, __element, /): pass
|
|
304
|
+
@MethodDecorator
|
|
305
|
+
def discard(self, __element, /): pass
|
|
306
|
+
@MethodDecorator
|
|
307
|
+
def update(self, *s): pass
|
|
308
|
+
@MethodDecorator
|
|
309
|
+
def difference_update(self, *s): pass
|
|
310
|
+
@MethodDecorator
|
|
311
|
+
def intersection_update(self, *s): pass
|
|
312
|
+
@MethodDecorator
|
|
313
|
+
def symmetric_difference_update(self, __s, /): pass
|
|
314
|
+
|
|
315
|
+
def dumps(self, _return_json=True):
|
|
316
|
+
data = [convert_atr_value_to_json_value(i) for i in self]
|
|
317
|
+
if _return_json:
|
|
318
|
+
return json.dumps({'t': self.__class__.__name__, 'd': data})
|
|
319
|
+
return {'t': self.__class__.__name__, 'd': data}
|
|
320
|
+
|
|
321
|
+
@classmethod
|
|
322
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
323
|
+
obj = cls.__new__(cls, _use_db=True)
|
|
324
|
+
if _first_container is None:
|
|
325
|
+
_first_container = _FirstContainer(obj)
|
|
326
|
+
data = {conver_json_value_to_atr_value(value, _first_container=_first_container) for value in tempdata['d']}
|
|
327
|
+
obj.__init__(data, _convert_arguments=False, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
328
|
+
return obj
|
|
329
|
+
|
|
330
|
+
@DbClassDecorator(list_of_methodes_with_converted_arguments=['__ior__'])
|
|
331
|
+
class DbDict(DbClass, dict):
|
|
332
|
+
_methode__new__needs_arguments = True
|
|
333
|
+
def __init__(self, *args, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
334
|
+
super().__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False)
|
|
335
|
+
dict.__init__(self, *args, **kwargs)
|
|
336
|
+
if _convert_arguments:
|
|
337
|
+
_first_container = self._first_container
|
|
338
|
+
setitem = dict.__setitem__
|
|
339
|
+
for key in self:
|
|
340
|
+
setitem(self, key, cheaker.create_db_class(self[key], _first_container=_first_container))
|
|
341
|
+
|
|
342
|
+
@classmethod
|
|
343
|
+
def __convert_to_db__(cls, obj: dict, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
344
|
+
return cls(obj, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
345
|
+
|
|
346
|
+
@MethodDecorator
|
|
347
|
+
def clear(self): pass
|
|
348
|
+
@MethodDecorator
|
|
349
|
+
def pop(self, __key, /): pass
|
|
350
|
+
@MethodDecorator
|
|
351
|
+
def popitem(self): pass
|
|
352
|
+
@MethodDecorator
|
|
353
|
+
def update(self, __m, /, **kwargs): pass
|
|
354
|
+
|
|
355
|
+
def dumps(self, _return_json=True):
|
|
356
|
+
data = {convert_atr_key_to_json_key(i): convert_atr_value_to_json_value(self[i]) for i in self}
|
|
357
|
+
data_key = {convert_atr_key_to_json_key(key): key.__class__.__name__ for key in self if key.__class__ in [tuple, int, bool]}
|
|
358
|
+
if _return_json:
|
|
359
|
+
return json.dumps({'t': self.__class__.__name__, 'dk': data_key, 'd': data})
|
|
360
|
+
return {'t': self.__class__.__name__, 'dk': data_key, 'd': data}
|
|
361
|
+
|
|
362
|
+
@classmethod
|
|
363
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
364
|
+
obj = cls.__new__(cls, _use_db=True)
|
|
365
|
+
if _first_container is None:
|
|
366
|
+
_first_container = _FirstContainer(obj)
|
|
367
|
+
data = {convert_json_key_to_atr_key(key, tempdata['dk'][key] if key in tempdata['dk'] else None)
|
|
368
|
+
: conver_json_value_to_atr_value(value, _first_container=_first_container)
|
|
369
|
+
for key, value in tempdata['d'].items()}
|
|
370
|
+
obj.__init__(data, _convert_arguments=False, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
371
|
+
return obj
|
|
372
|
+
|
|
373
|
+
@DbClassDecorator
|
|
374
|
+
class DbTuple(DbClass, tuple):
|
|
375
|
+
_methode__new__needs_arguments = True
|
|
376
|
+
_call_init_when_reconstruct = True
|
|
377
|
+
def __new__(cls, *args, _use_db=False, _loads_iterable=False, _obj_dbattribute=None, _convert_arguments=True, _name_attribute=None, _first_container=None, **kwargs):
|
|
378
|
+
if not _use_db:
|
|
379
|
+
return tuple.__new__(DbTuple, *args, **kwargs)
|
|
380
|
+
|
|
381
|
+
if _first_container is None:
|
|
382
|
+
_first_container = _FirstContainer()
|
|
383
|
+
|
|
384
|
+
iterable = tuple(args[0])
|
|
385
|
+
if (not _loads_iterable) and _convert_arguments:
|
|
386
|
+
iterable = tuple((cheaker.create_db_class(i, _first_container=_first_container) for i in iterable))
|
|
387
|
+
if _loads_iterable:
|
|
388
|
+
iterable = tuple((conver_json_value_to_atr_value(value, _first_container=_first_container) for value in iterable))
|
|
389
|
+
|
|
390
|
+
obj = tuple.__new__(DbTuple, iterable)
|
|
391
|
+
if _first_container.container is None:
|
|
392
|
+
_first_container.container = obj
|
|
393
|
+
obj.__dict__['_first_container'] = _first_container
|
|
394
|
+
return obj
|
|
395
|
+
|
|
396
|
+
def __init__(self, *args, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
397
|
+
super().__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False)
|
|
398
|
+
|
|
399
|
+
def __iadd__(self, other):
|
|
400
|
+
obj = self.__class__(self.__add__(other), _use_db=True, _obj_dbattribute=self._obj_dbattribute, _name_attribute=self._name_attribute, _first_container=self._first_container)
|
|
401
|
+
if self._first_container.container is self:
|
|
402
|
+
obj.__dict__['_first_container'].container = obj
|
|
403
|
+
return obj
|
|
404
|
+
|
|
405
|
+
@classmethod
|
|
406
|
+
def __convert_to_db__(cls, obj: tuple, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
407
|
+
return cls(obj, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
408
|
+
|
|
409
|
+
def dumps(self, _return_json=True):
|
|
410
|
+
data = [convert_atr_value_to_json_value(i) for i in self]
|
|
411
|
+
if _return_json:
|
|
412
|
+
return json.dumps({'t': self.__class__.__name__, 'd': data})
|
|
413
|
+
return {'t': self.__class__.__name__, 'd': data}
|
|
414
|
+
|
|
415
|
+
@classmethod
|
|
416
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
417
|
+
obj = cls.__new__(cls, tempdata['d'], _use_db=True, _loads_iterable=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
418
|
+
obj.__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
419
|
+
return obj
|
|
420
|
+
|
|
421
|
+
@DbClassDecorator
|
|
422
|
+
class Dbfrozenset(DbClass, frozenset): pass
|
|
423
|
+
|
|
424
|
+
@DbClassDecorator
|
|
425
|
+
class DbDeque(DbClass, collections.deque):
|
|
426
|
+
_methode__new__needs_arguments = True
|
|
427
|
+
def __init__(self, *args, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
428
|
+
super().__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False)
|
|
429
|
+
|
|
430
|
+
iterable = args[0]
|
|
431
|
+
if _convert_arguments:
|
|
432
|
+
iterable = [cheaker.create_db_class(i, _first_container=self._first_container) for i in iterable]
|
|
433
|
+
collections.deque.__init__(self, iterable)
|
|
434
|
+
|
|
435
|
+
@classmethod
|
|
436
|
+
def __convert_to_db__(cls, obj: collections.deque, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
437
|
+
return cls(obj, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
438
|
+
|
|
439
|
+
@DbClassDecorator
|
|
440
|
+
class DbDatetime(DbClass, datetime.datetime):
|
|
441
|
+
_methode__new__needs_arguments = True
|
|
442
|
+
def __init__(self, year, month=None, day=None, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
443
|
+
super().__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False, **kwargs)
|
|
444
|
+
def __iadd__(self, other):
|
|
445
|
+
obj = cheaker.create_db_class(self.__add__(other), _obj_dbattribute=self._obj_dbattribute, _name_attribute=self._name_attribute, _first_container=self._first_container)
|
|
446
|
+
if self._first_container.container is self: obj.__dict__['_first_container'].container = obj
|
|
447
|
+
return obj
|
|
448
|
+
def __isub__(self, other):
|
|
449
|
+
obj = cheaker.create_db_class(self.__sub__(other), _obj_dbattribute=self._obj_dbattribute, _name_attribute=self._name_attribute, _first_container=self._first_container)
|
|
450
|
+
if self._first_container.container is self: obj.__dict__['_first_container'].container = obj
|
|
451
|
+
return obj
|
|
452
|
+
|
|
453
|
+
@classmethod
|
|
454
|
+
def __convert_to_db__(cls, obj: datetime.datetime, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
455
|
+
return cls(year=obj.year, month=obj.month, day=obj.day, hour=obj.hour, minute=obj.minute, second=obj.second, microsecond=obj.microsecond, tzinfo=obj.tzinfo, fold=obj.fold, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
456
|
+
|
|
457
|
+
def dumps(self, _return_json=True):
|
|
458
|
+
if _return_json: return json.dumps({'t': self.__class__.__name__, 'd': self.isoformat()})
|
|
459
|
+
return {'t': self.__class__.__name__, 'd': self.isoformat()}
|
|
460
|
+
|
|
461
|
+
@classmethod
|
|
462
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
463
|
+
return cls.__convert_to_db__(cls.fromisoformat(tempdata['d']), _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
464
|
+
|
|
465
|
+
@DbClassDecorator
|
|
466
|
+
class DbDate(DbClass, datetime.date):
|
|
467
|
+
_methode__new__needs_arguments = True
|
|
468
|
+
def __init__(self, year, month=None, day=None, *, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
469
|
+
super().__init__(year=year, month=month, day=day, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False, **kwargs)
|
|
470
|
+
def __iadd__(self, other):
|
|
471
|
+
obj = cheaker.create_db_class(self.__add__(other), _obj_dbattribute=self._obj_dbattribute, _name_attribute=self._name_attribute, _first_container=self._first_container)
|
|
472
|
+
if self._first_container.container is self: obj.__dict__['_first_container'].container = obj
|
|
473
|
+
return obj
|
|
474
|
+
def __isub__(self, other):
|
|
475
|
+
obj = cheaker.create_db_class(self.__sub__(other), _obj_dbattribute=self._obj_dbattribute, _name_attribute=self._name_attribute, _first_container=self._first_container)
|
|
476
|
+
if self._first_container.container is self: obj.__dict__['_first_container'].container = obj
|
|
477
|
+
return obj
|
|
478
|
+
@classmethod
|
|
479
|
+
def __convert_to_db__(cls, obj: datetime.datetime, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
480
|
+
return cls(year=obj.year, month=obj.month, day=obj.day, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
481
|
+
def dumps(self, _return_json=True):
|
|
482
|
+
if _return_json: return json.dumps({'t': self.__class__.__name__, 'd': self.isoformat()})
|
|
483
|
+
return {'t': self.__class__.__name__, 'd': self.isoformat()}
|
|
484
|
+
@classmethod
|
|
485
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
486
|
+
return cls.__convert_to_db__(cls.fromisoformat(tempdata['d']), _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
487
|
+
|
|
488
|
+
@DbClassDecorator
|
|
489
|
+
class DbTime(DbClass, datetime.time):
|
|
490
|
+
_methode__new__needs_arguments = True
|
|
491
|
+
def __init__(self, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
492
|
+
super().__init__(_obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False, **kwargs)
|
|
493
|
+
|
|
494
|
+
def __iadd__(self, other):
|
|
495
|
+
obj = cheaker.create_db_class(self.__add__(other), _obj_dbattribute=self._obj_dbattribute, _name_attribute=self._name_attribute, _first_container=self._first_container)
|
|
496
|
+
if self._first_container.container is self: obj.__dict__['_first_container'].container = obj
|
|
497
|
+
return obj
|
|
498
|
+
def __isub__(self, other):
|
|
499
|
+
obj = cheaker.create_db_class(self.__sub__(other), _obj_dbattribute=self._obj_dbattribute, _name_attribute=self._name_attribute, _first_container=self._first_container)
|
|
500
|
+
if self._first_container.container is self: obj.__dict__['_first_container'].container = obj
|
|
501
|
+
return obj
|
|
502
|
+
|
|
503
|
+
@classmethod
|
|
504
|
+
def __convert_to_db__(cls, obj: datetime.time, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
505
|
+
return DbTime(hour=obj.hour, minute=obj.minute, second=obj.second, microsecond=obj.microsecond, tzinfo=obj.tzinfo, fold=obj.fold, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
506
|
+
|
|
507
|
+
def dumps(self, _return_json=True):
|
|
508
|
+
if _return_json: return json.dumps({'t': self.__class__.__name__, 'd': self.isoformat()})
|
|
509
|
+
return {'t': self.__class__.__name__, 'd': self.isoformat()}
|
|
510
|
+
@classmethod
|
|
511
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
512
|
+
return cls.__convert_to_db__(cls.fromisoformat(tempdata['d']), _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
513
|
+
|
|
514
|
+
@DbClassDecorator
|
|
515
|
+
class DbTimedelta(DbClass, datetime.timedelta):
|
|
516
|
+
_methode__new__needs_arguments = True
|
|
517
|
+
def __init__(self, *args, _use_db=False, _convert_arguments=True, _obj_dbattribute=None, _name_attribute=None, _first_container=None, **kwargs):
|
|
518
|
+
super().__init__(*args, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container, _call_init=False, **kwargs)
|
|
519
|
+
|
|
520
|
+
def dumps(self, _return_json=True):
|
|
521
|
+
if _return_json: return json.dumps({'t': self.__class__.__name__, 'd': self.total_seconds()})
|
|
522
|
+
return {'t': self.__class__.__name__, 'd': self.total_seconds()}
|
|
523
|
+
|
|
524
|
+
@classmethod
|
|
525
|
+
def _loads(cls, tempdata: dict, *, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
526
|
+
return cls(seconds=tempdata['d'], _use_db=True, _first_container=_first_container)
|
|
527
|
+
|
|
528
|
+
class Cheaker:
|
|
529
|
+
"""
|
|
530
|
+
cheak, if this class is db_class. Convert obj if his class is db_class. And other.
|
|
531
|
+
|
|
532
|
+
db_class_name_to_db_class: {'DbList': DbList, 'DbSet': DbSet, 'DbDict': DbDict} | *other db classes*
|
|
533
|
+
class_name_to_db_class = {'list': DbList, 'dict': DbDict, 'set': DbSet} | *other db classes*
|
|
534
|
+
class_to_db_class = {list: DbList, dict: DbDict, set: DbSet} | *other db classes*
|
|
535
|
+
"""
|
|
536
|
+
def __init__(self, _db_classes:dict = None):
|
|
537
|
+
"""
|
|
538
|
+
:param _db_classes: example: {datetime.datetime: DbDatetime}
|
|
539
|
+
:type _db_classes: dict
|
|
540
|
+
"""
|
|
541
|
+
self._db_classes = _db_classes
|
|
542
|
+
if not _db_classes:
|
|
543
|
+
self._db_classes = dict()
|
|
544
|
+
self.db_class_name_to_db_class = {self._db_classes[i].__name__ : self._db_classes[i] for i in self._db_classes}
|
|
545
|
+
self.class_name_to_db_class = {i.__name__: self._db_classes[i] for i in self._db_classes}
|
|
546
|
+
self.db_class_name_to_clasic_class = {self._db_classes[i].__name__: i for i in self._db_classes}
|
|
547
|
+
self.all_db_classes = set(_db_classes.values())
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
def set_db_classes(self, _db_classes: dict):
|
|
551
|
+
"""
|
|
552
|
+
:param _db_classes: example: {datetime.datetime: DbDatetime}
|
|
553
|
+
:type _db_classes: dict
|
|
554
|
+
"""
|
|
555
|
+
self._db_classes = _db_classes
|
|
556
|
+
if not _db_classes:
|
|
557
|
+
self._db_classes = dict()
|
|
558
|
+
self.db_class_name_to_db_class = {self._db_classes[i].__name__ : self._db_classes[i] for i in self._db_classes}
|
|
559
|
+
self.class_name_to_db_class = {i.__name__: self._db_classes[i] for i in self._db_classes}
|
|
560
|
+
self.db_class_name_to_clasic_class = {self._db_classes[i].__name__: i for i in self._db_classes}
|
|
561
|
+
self.all_db_classes = set(_db_classes.values())
|
|
562
|
+
|
|
563
|
+
def add_db_class(self, _db_class: tuple):
|
|
564
|
+
""":param _db_class: example: (datetime.datetime, DbDatetime)"""
|
|
565
|
+
self._db_classes[_db_class[0]] = _db_class[1]
|
|
566
|
+
self.db_class_name_to_db_class[_db_class[1].__name__] = _db_class[1]
|
|
567
|
+
self.class_name_to_db_class[_db_class[0].__name__] = _db_class[1]
|
|
568
|
+
self.db_class_name_to_clasic_class[_db_class[1].__name__] = _db_class[0]
|
|
569
|
+
self.all_db_classes.add(_db_class[1])
|
|
570
|
+
|
|
571
|
+
def remove_db_class(self, name_clasic_class=None, name_db_class=None):
|
|
572
|
+
if name_clasic_class is None and name_db_class is None:
|
|
573
|
+
return
|
|
574
|
+
if name_db_class:
|
|
575
|
+
name_clasic_class = self.db_class_name_to_clasic_class[name_db_class].__name__
|
|
576
|
+
elif name_clasic_class:
|
|
577
|
+
name_db_class = self.class_name_to_db_class[name_clasic_class].__name__
|
|
578
|
+
db_class = self.db_class_name_to_db_class[name_db_class]
|
|
579
|
+
del self._db_classes[db_class]
|
|
580
|
+
del self.db_class_name_to_db_class[name_db_class]
|
|
581
|
+
del self.class_name_to_db_class[name_clasic_class]
|
|
582
|
+
del self.db_class_name_to_clasic_class[name_db_class]
|
|
583
|
+
self.all_db_classes.discard(db_class)
|
|
584
|
+
|
|
585
|
+
def create_any_db_classes(self, *objs, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
586
|
+
"""
|
|
587
|
+
Use for create db_class from other classes. example: from list to DbList, but from int to int.
|
|
588
|
+
:param objs: example: [123, '535', {8, 4, 6} #it's set , {1: 2} # it's dict]
|
|
589
|
+
:param _obj_dbattribute:
|
|
590
|
+
:return: example: [123, '535', {8, 4, 6} #it's DbSet , {1: 2} # it's DbDict]
|
|
591
|
+
"""
|
|
592
|
+
return [self.create_db_class(objs[i], _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container) for i in range(len(objs))]
|
|
593
|
+
|
|
594
|
+
def create_db_class(self, obj, *, attribute_type=None, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
595
|
+
if (attribute_type is None and type(obj) in self._db_classes) or (attribute_type in self._db_classes):
|
|
596
|
+
if attribute_type is None:
|
|
597
|
+
attribute_type = type(obj)
|
|
598
|
+
cls = self._db_classes[attribute_type]
|
|
599
|
+
if hasattr(cls, '__convert_to_db__'):
|
|
600
|
+
return cls.__convert_to_db__(obj, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
601
|
+
reductor = getattr(obj, "__reduce_ex__", None)
|
|
602
|
+
if reductor is not None:
|
|
603
|
+
rv = reductor(4)
|
|
604
|
+
else:
|
|
605
|
+
reductor = getattr(obj, "__reduce__", None)
|
|
606
|
+
if reductor:
|
|
607
|
+
rv = reductor()
|
|
608
|
+
else:
|
|
609
|
+
raise Exception(f"uncopyable object of type {type(obj)}")
|
|
610
|
+
if isinstance(rv, str):
|
|
611
|
+
raise Exception(f"uncopyable object of type {type(obj)}")
|
|
612
|
+
rv = list(rv)
|
|
613
|
+
if rv[0].__name__ == '__newobj__':
|
|
614
|
+
rv[0] = __newobj__
|
|
615
|
+
elif rv[0].__name__ == '__newobj_ex__':
|
|
616
|
+
rv[0] = __newobj_ex__
|
|
617
|
+
else:
|
|
618
|
+
rv[0] = __newobj__
|
|
619
|
+
rv[1] = (1,) + rv[1]
|
|
620
|
+
rv[1] = (cls,) + rv[1][1:]
|
|
621
|
+
obj = self._reconstruct(*rv, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
622
|
+
return obj
|
|
623
|
+
|
|
624
|
+
def _reconstruct(self, func, args, state=None, listiter=None, dictiter=None, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
625
|
+
y = func(*args, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
626
|
+
if _first_container is None:
|
|
627
|
+
_first_container = _FirstContainer(y)
|
|
628
|
+
if y.__dict__.get('_first_container', None) is None:
|
|
629
|
+
y.__dict__['_first_container'] = _first_container
|
|
630
|
+
if y._call_init_when_reconstruct:
|
|
631
|
+
y.__init__(*args[1:], _obj_dbattribute=None, _name_attribute=None, _first_container=None)
|
|
632
|
+
if state is not None:
|
|
633
|
+
if hasattr(y, '__setstate__'):
|
|
634
|
+
y.__setstate__(state)
|
|
635
|
+
else:
|
|
636
|
+
if isinstance(state, tuple) and len(state) == 2:
|
|
637
|
+
state, slotstate = state
|
|
638
|
+
else:
|
|
639
|
+
slotstate = None
|
|
640
|
+
if state is not None:
|
|
641
|
+
state = {key: self.create_db_class(state[key], _first_container=_first_container) for key in state}
|
|
642
|
+
y.__dict__.update(state)
|
|
643
|
+
if slotstate is not None:
|
|
644
|
+
slotstate = {key: self.create_db_class(slotstate[key], _first_container=_first_container) for key in slotstate}
|
|
645
|
+
for key, value in slotstate.items():
|
|
646
|
+
setattr(y, key, value)
|
|
647
|
+
if listiter is not None:
|
|
648
|
+
for item in listiter:
|
|
649
|
+
y.append(self.create_db_class(item, _first_container=_first_container))
|
|
650
|
+
if dictiter is not None:
|
|
651
|
+
for key, value in dictiter:
|
|
652
|
+
y[key] = self.create_db_class(value, _first_container=_first_container)
|
|
653
|
+
temp = {'_first_container': _first_container}
|
|
654
|
+
if _obj_dbattribute:
|
|
655
|
+
temp['_obj_dbattribute'] = _obj_dbattribute
|
|
656
|
+
if _name_attribute:
|
|
657
|
+
temp['_name_attribute'] = _name_attribute
|
|
658
|
+
if hasattr(y, '__dict__'):
|
|
659
|
+
y.__dict__.update(temp)
|
|
660
|
+
else:
|
|
661
|
+
for key, value in temp.items():
|
|
662
|
+
setattr(y, key, value)
|
|
663
|
+
return y
|
|
664
|
+
|
|
665
|
+
def this_support_class(self, obj, this_is_cls=False):
|
|
666
|
+
return obj in self._db_classes if this_is_cls else type(obj) in self._db_classes
|
|
667
|
+
|
|
668
|
+
def this_db_attribute_support_class(self, obj, this_is_cls=False):
|
|
669
|
+
return obj in self.all_db_classes if this_is_cls else type(obj) in self.all_db_classes
|
|
670
|
+
|
|
671
|
+
class Tlist(list): pass
|
|
672
|
+
class Tset(set): pass
|
|
673
|
+
class Tdict(dict): pass
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def __newobj_ex__(cls, args, kwargs, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
677
|
+
return cls.__new__(cls, *args, *kwargs, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
678
|
+
def __newobj__(cls, *args, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
679
|
+
return cls.__new__(cls, *args, _use_db=True, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
680
|
+
|
|
681
|
+
def convert_atr_value_to_json_value(value):
|
|
682
|
+
return value.dumps(_return_json=False) if cheaker.this_db_attribute_support_class(value) else value
|
|
683
|
+
|
|
684
|
+
def conver_json_value_to_atr_value(value, _obj_dbattribute=None, _name_attribute=None, _first_container=None):
|
|
685
|
+
if isinstance(value, dict):
|
|
686
|
+
return DbClass.loads(value, _obj_dbattribute=_obj_dbattribute, _name_attribute=_name_attribute, _first_container=_first_container)
|
|
687
|
+
return value
|
|
688
|
+
|
|
689
|
+
def convert_atr_key_to_json_key(key):
|
|
690
|
+
"""For DbDict"""
|
|
691
|
+
res = key
|
|
692
|
+
if key.__class__ == tuple:
|
|
693
|
+
res = str(key)
|
|
694
|
+
elif key.__class__ == bool:
|
|
695
|
+
res = ' True ' if key else ' False '
|
|
696
|
+
return res
|
|
697
|
+
|
|
698
|
+
def convert_json_key_to_atr_key(key, type_key):
|
|
699
|
+
"""For DbDict"""
|
|
700
|
+
if type_key == 'int':
|
|
701
|
+
return int(key)
|
|
702
|
+
if type_key == 'tuple':
|
|
703
|
+
return ast.literal_eval(str(key))
|
|
704
|
+
if type_key == 'bool':
|
|
705
|
+
return True if key == ' True ' else False
|
|
706
|
+
return key
|
|
707
|
+
|
|
708
|
+
cheaker = Cheaker({set: DbSet, list: DbList, dict: DbDict, tuple: DbTuple, datetime.datetime: DbDatetime, datetime.timedelta: DbTimedelta, datetime.date: DbDate, datetime.time: DbTime})
|
|
709
|
+
|
|
710
|
+
if __name__ == "__main__":
|
|
711
|
+
print(1)
|
|
712
|
+
A = DbDict([[0, 1], [1, 4], [2, 3], [3, 2], [4, 4]], _use_db = True)
|
|
713
|
+
B = DbList([1, 4, 3, 2, 4], _use_db = True)
|
|
714
|
+
C = DbSet([1, 4, 3, 2, 4], _use_db = True)
|
|
715
|
+
if A != {0: 1, 1: 4, 2: 3, 3: 2, 4: 4} or B != [1, 4, 3, 2, 4] or C != {1, 2, 3, 4}:
|
|
716
|
+
print(A, type(A))
|
|
717
|
+
print(B, type(B))
|
|
718
|
+
print(C, type(C))
|
|
719
|
+
|
|
720
|
+
print(2)
|
|
721
|
+
a = A | {8: 5}
|
|
722
|
+
b = B + [1]
|
|
723
|
+
c = C - {3}
|
|
724
|
+
if a != {0: 1, 1: 4, 2: 3, 3: 2, 4: 4, 8: 5} or b != [1, 4, 3, 2, 4, 1] or c != {1, 2, 4} or type(a) != dict or type(b) != list or type(c) != set:
|
|
725
|
+
print(a, type(a))
|
|
726
|
+
print(b, type(b))
|
|
727
|
+
print(c, type(c))
|
|
728
|
+
|
|
729
|
+
print(3)
|
|
730
|
+
A |= {8: 5}
|
|
731
|
+
B += [1]
|
|
732
|
+
C -= {3}
|
|
733
|
+
if A != {0: 1, 1: 4, 2: 3, 3: 2, 4: 4, 8: 5} or B != [1, 4, 3, 2, 4, 1] or C != {1, 2, 4}:
|
|
734
|
+
print(A, type(A))
|
|
735
|
+
print(B, type(B))
|
|
736
|
+
print(C, type(C))
|
|
737
|
+
|
|
738
|
+
print(4)
|
|
739
|
+
A = DbDict([[0, 1], [1, 4], [2, 3], [3, 2], [4, 4]], _use_db = True)
|
|
740
|
+
B = DbList([1, 4, 3, 2, 4], _use_db = True)
|
|
741
|
+
C = DbSet([1, 4, 3, 2, 4], _use_db = True)
|
|
742
|
+
A.update({8:5})
|
|
743
|
+
B.append(1)
|
|
744
|
+
C.remove(3)
|
|
745
|
+
if A != {0: 1, 1: 4, 2: 3, 3: 2, 4: 4, 8: 5} or B != [1, 4, 3, 2, 4, 1] or C != {1, 2, 4}:
|
|
746
|
+
print(A, type(A))
|
|
747
|
+
print(B, type(B))
|
|
748
|
+
print(C, type(C))
|
|
749
|
+
|
|
750
|
+
print(5)
|
|
751
|
+
A = DbDict([[0, 1], [1, 4], [2, 3], [3, 2], [4, 4]], _use_db = True)
|
|
752
|
+
B = DbList([1, 4, 3, 2, 4], _use_db = True)
|
|
753
|
+
C = DbSet([1, 4, 3, 2, 4], _use_db = True)
|
|
754
|
+
a = dict(A)
|
|
755
|
+
b = list(B)
|
|
756
|
+
c = set(C)
|
|
757
|
+
a |= {8: 5}
|
|
758
|
+
b += [1]
|
|
759
|
+
c -= {3}
|
|
760
|
+
if A != {0: 1, 1: 4, 2: 3, 3: 2, 4: 4} or B != [1, 4, 3, 2, 4] or C != {1, 2, 3, 4} or a != {0: 1, 1: 4, 2: 3, 3: 2, 4: 4, 8: 5} or b != [1, 4, 3, 2, 4, 1] or c != {1, 2, 4} or a == A or b == B or c == C:
|
|
761
|
+
print(a, type(a))
|
|
762
|
+
print(b, type(b))
|
|
763
|
+
print(c, type(c))
|
|
764
|
+
print(A, type(A))
|
|
765
|
+
print(B, type(B))
|
|
766
|
+
print(C, type(C))
|
|
767
|
+
|
|
768
|
+
print(6)
|
|
769
|
+
A = DbDict([[0, [1, 4, {1}]], [1, {2}], [2, {5:6}], [3, 4]], _use_db = True)
|
|
770
|
+
B = DbList([[1], [4], [3], {2:[5]}, {1, 3, 4}], _use_db = True)
|
|
771
|
+
C = DbSet([(1, 4), (3, 2), 4], _use_db = True)
|
|
772
|
+
A[0][0] = 3
|
|
773
|
+
del A[0][1]
|
|
774
|
+
A[0][1].add(2)
|
|
775
|
+
if A != {0: [3, {1, 2}], 1: {2}, 2: {5: 6}, 3: 4} or B != [[1], [4], [3], {2: [5]}, {1, 3, 4}] or C != {(3, 2), 4, (1, 4)} or type(A) != DbDict or type(B) != DbList or type(C) != DbSet:
|
|
776
|
+
print(A, type(A))
|
|
777
|
+
print(B, type(B))
|
|
778
|
+
print(C, type(C))
|
|
779
|
+
print(7)
|
|
780
|
+
A = DbDict([[0, [1, 4, {1}]], [1, {2}], [2, {5:6}], [3, 4]], _use_db = True)
|
|
781
|
+
B = DbList([[1], [4], [3], {2:[5]}, {1, 3, 4}], _use_db = True)
|
|
782
|
+
a = copy.deepcopy(A)
|
|
783
|
+
b = copy.deepcopy(B)
|
|
784
|
+
a[0][0] = 3
|
|
785
|
+
b[3][1] = 4
|
|
786
|
+
if type(a) != dict or type(b) != list or A != {0: [1, 4, {1}], 1: {2}, 2: {5: 6}, 3: 4} or B != [[1], [4], [3], {2: [5]}, {1, 3, 4}] or a != {0: [3, 4, {1}], 1: {2}, 2: {5: 6}, 3: 4} or b != [[1], [4], [3], {2: [5], 1: 4}, {1, 3, 4}]:
|
|
787
|
+
print(A, type(A))
|
|
788
|
+
print(B, type(B))
|
|
789
|
+
print(a, type(a))
|
|
790
|
+
print(b, type(b))
|
|
791
|
+
print(8)
|
|
792
|
+
A = DbDict({0: [1, 4, {1}], 1: {2}, 2: {5:6}, 3: (7, 8), 4: True, 5: False, (6, 7): [1, 2], '8': [1]}, _use_db = True)
|
|
793
|
+
B = DbList([{2:[5]}, [1], [4], [3], {1, 3, 4}, True, True, (1, 2), (1, 2)], _use_db = True)
|
|
794
|
+
C = DbSet([4, True, '/Hello\n', (1, 2)], _use_db = True)
|
|
795
|
+
#print(C.dumps())
|
|
796
|
+
a = DbClass.loads(A.dumps())
|
|
797
|
+
b = DbClass.loads(B.dumps())
|
|
798
|
+
c = DbClass.loads(C.dumps())
|
|
799
|
+
if A != a:
|
|
800
|
+
print('8.A error:')
|
|
801
|
+
print(A.dumps(), type(A.dumps()))
|
|
802
|
+
print(A, type(A))
|
|
803
|
+
print(a, type(a))
|
|
804
|
+
if B != b:
|
|
805
|
+
print('8.B error:')
|
|
806
|
+
print(B.dumps(), type(B.dumps()))
|
|
807
|
+
print(B, type(B))
|
|
808
|
+
print(b, type(b))
|
|
809
|
+
if C != c:
|
|
810
|
+
print('8.C error:')
|
|
811
|
+
print(C.dumps(), type(C.dumps()))
|
|
812
|
+
print(C, type(C))
|
|
813
|
+
print(c, type(c))
|
|
814
|
+
print(9, 'cheack _first_container')
|
|
815
|
+
temp_func = lambda inp: {id(inp._first_container.container)} | {j for i in inp if hasattr(i, '__iter__') for j in temp_func(i)}
|
|
816
|
+
temp_func_dict = lambda inp: {id(inp._first_container.container)} | {j for key in inp if hasattr(inp[key], '__iter__') for j in temp_func(inp[key])}
|
|
817
|
+
A = DbTuple(([1], 2, 3, datetime.datetime(2024, 10, 4)), _use_db = True)
|
|
818
|
+
A += ((4,),)
|
|
819
|
+
if len(temp_func(A)) > 1:
|
|
820
|
+
print('9.1 error:')
|
|
821
|
+
print(A, type(A), temp_func(A))
|
|
822
|
+
print(id(A), id(A._first_container.container), id(A[0]._first_container.container))
|
|
823
|
+
print(id(A._first_container), id(A[0]._first_container))
|
|
824
|
+
|
|
825
|
+
B = DbList([([1], 2, 3, datetime.datetime(2024, 10, 4))], _use_db=True)
|
|
826
|
+
B[0] += ((4,),)
|
|
827
|
+
if len(temp_func(B)) > 1:
|
|
828
|
+
print('9.2 error:')
|
|
829
|
+
print(B, type(B), temp_func(B))
|
|
830
|
+
print(id(B), id(B._first_container.container), id(B[0]._first_container.container), id(B[0][0]._first_container.container))
|
|
831
|
+
print(id(B._first_container), id(B[0]._first_container), id(B[0][0]._first_container))
|
|
832
|
+
|
|
833
|
+
B = cheaker.create_db_class([[1, (2,(3,),[4],datetime.datetime(2024, 10, 4)), {5, (6,(7,))}, {(8, 3), 5}], (9,(10,),[11])])
|
|
834
|
+
if B != [[1, (2,(3,),[4],datetime.datetime(2024, 10, 4)), {5, (6,(7,))}, {(8, 3), 5}], (9,(10,),[11])]:
|
|
835
|
+
print('9.3.a error:')
|
|
836
|
+
print(B, type(B))
|
|
837
|
+
B += [(12,)]
|
|
838
|
+
B[0].append(13)
|
|
839
|
+
B[-1] = [1, 2]
|
|
840
|
+
B[0][1] += (4,)
|
|
841
|
+
B[0][2] |= {(3, (1,))}
|
|
842
|
+
B[0][2] -= {(3, (1,))}
|
|
843
|
+
B[0][2] |= {(3, (2,))}
|
|
844
|
+
B[0][2] &= {(3, (2,))}
|
|
845
|
+
if len(temp_func(B)) > 1:
|
|
846
|
+
print('9.3.b error:')
|
|
847
|
+
print(B, type(B), temp_func(B))
|
|
848
|
+
|
|
849
|
+
B = cheaker.create_db_class({(1, 2): [3, 4], 5: {6, (7,)}, 8: (9, {10:11})})
|
|
850
|
+
if B != {(1, 2): [3, 4], 5: {6, (7,)}, 8: (9, {10:11})} or type(B) is not DbDict:
|
|
851
|
+
print('9.4.a error:')
|
|
852
|
+
print(B, type(B))
|
|
853
|
+
if len(temp_func_dict(B)) > 1:
|
|
854
|
+
print('9.4.b error:')
|
|
855
|
+
print(B, type(B), temp_func_dict(B))
|
|
856
|
+
B[9] = [(3, 5), {1, 0}, {3: 5}, [2]]
|
|
857
|
+
B |= {8: [1, (5, 8)]}
|
|
858
|
+
B |= {9: [3, 7, (3, 5)]}
|
|
859
|
+
if len(temp_func_dict(B)) > 1:
|
|
860
|
+
print('9.4.c error:')
|
|
861
|
+
print(B, type(B), temp_func_dict(B))
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
print(10, 'cheack datetime')
|
|
865
|
+
A = DbDatetime(2024, 11, 4, _use_db=True)
|
|
866
|
+
if A != datetime.datetime(2024, 11, 4) or type(A) is not DbDatetime:
|
|
867
|
+
print('10.1.1 error:')
|
|
868
|
+
print(A, type(A))
|
|
869
|
+
A = cheaker.create_db_class(datetime.datetime(2024, 11, 4))
|
|
870
|
+
if A != datetime.datetime(2024, 11, 4) or type(A) is not DbDatetime:
|
|
871
|
+
print('10.1.2 error:')
|
|
872
|
+
print(A, type(A))
|
|
873
|
+
A = DbClass.loads(A.dumps())
|
|
874
|
+
if A != datetime.datetime(2024, 11, 4) or type(A) is not DbDatetime:
|
|
875
|
+
print('10.1.3 error:')
|
|
876
|
+
print(A, type(A))
|
|
877
|
+
B = DbList([A], _use_db=True)
|
|
878
|
+
B = DbClass.loads(B.dumps())
|
|
879
|
+
if B[0] != datetime.datetime(2024, 11, 4) or type(B[0]) is not DbDatetime:
|
|
880
|
+
print('10.1.4 error:')
|
|
881
|
+
print(A, type(A))
|
|
882
|
+
A = DbTimedelta(microseconds=10, _use_db=True)
|
|
883
|
+
if A != datetime.timedelta(microseconds=10) or type(A) is not DbTimedelta:
|
|
884
|
+
print('10.2.1 error:')
|
|
885
|
+
print(A, type(A))
|
|
886
|
+
A = DbClass.loads(A.dumps())
|
|
887
|
+
if A != datetime.timedelta(microseconds=10) or type(A) is not DbTimedelta:
|
|
888
|
+
print('10.2.2 error:')
|
|
889
|
+
print(A, type(A))
|
|
890
|
+
A = DbTimedelta(seconds=10**6, _use_db=True)
|
|
891
|
+
if A != datetime.timedelta(seconds=10**6) or type(A) is not DbTimedelta:
|
|
892
|
+
print('10.2.3 error:')
|
|
893
|
+
print(A, type(A))
|
|
894
|
+
A = DbClass.loads(A.dumps())
|
|
895
|
+
if A != datetime.timedelta(seconds=10**6) or type(A) is not DbTimedelta:
|
|
896
|
+
print('10.2.4 error:')
|
|
897
|
+
print(A, type(A))
|
|
898
|
+
B = DbDatetime(2024, 11, 4, _use_db=True)
|
|
899
|
+
B -= A
|
|
900
|
+
if B != datetime.datetime(2024, 10, 23, 10, 13, 20) or type(B) is not DbDatetime:
|
|
901
|
+
print('10.3.1 error:')
|
|
902
|
+
print(B, type(B))
|
|
903
|
+
A = DbDate(2024, 11, 10, _use_db=True)
|
|
904
|
+
if A != datetime.date(2024, 11, 10) or type(A) is not DbDate:
|
|
905
|
+
print('10.4.1 error:')
|
|
906
|
+
print(A, type(A))
|
|
907
|
+
A = DbClass.loads(A.dumps())
|
|
908
|
+
if A != datetime.date(2024, 11, 10) or type(A) is not DbDate:
|
|
909
|
+
print('10.4.2 error:')
|
|
910
|
+
print(A, type(A))
|
|
911
|
+
A = DbTime(11, 15, 10, _use_db=True)
|
|
912
|
+
if A != datetime.time(11, 15, 10) or type(A) is not DbTime:
|
|
913
|
+
print('10.5.1 error:')
|
|
914
|
+
print(A, type(A))
|
|
915
|
+
A = DbClass.loads(A.dumps())
|
|
916
|
+
if A != datetime.time(11, 15, 10) or type(A) is not DbTime:
|
|
917
|
+
print('10.5.2 error:')
|
|
918
|
+
print(A, type(A))
|
|
919
|
+
print(11, 'time test')
|
|
920
|
+
def test(cls, args):
|
|
921
|
+
import time
|
|
922
|
+
n = 3*10**4
|
|
923
|
+
print(f'test {cls}')
|
|
924
|
+
start = time.time()
|
|
925
|
+
for i in range(n):
|
|
926
|
+
A = cls(args, _use_db = True)
|
|
927
|
+
end = time.time()
|
|
928
|
+
print(f'create: {n/(end - start)} op/sec {(end-start)} in {n} op')
|
|
929
|
+
start = time.time()
|
|
930
|
+
for i in range(n):
|
|
931
|
+
data = A.dumps()
|
|
932
|
+
end = time.time()
|
|
933
|
+
print(f'dumps: {n/(end - start)} op/sec {(end-start)} in {n} op')
|
|
934
|
+
start = time.time()
|
|
935
|
+
for i in range(n):
|
|
936
|
+
A = cls.loads(data)
|
|
937
|
+
end = time.time()
|
|
938
|
+
print(f'loads: {n/(end - start)} op/sec {(end-start)} in {n} op')
|
|
939
|
+
#test(DbDict, {0: [[1, 2], [3, 4], [5, 6]], 1: {1, ((2,), (3,))}, 2: {1: {2: (3, ), 4: (5,)}, 6: {7: (8,)}}})
|
|
940
|
+
test(DbList, [[[1, 2], [3, 4], [5, 6]], {1, ((2,), (3,))}, {1: {2: (3, ), 4: (5,)}, 6: {7: (8,)}}])
|
|
941
|
+
|
|
942
|
+
|