kisa-utils 0.39.1__py3-none-any.whl → 0.40.0__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.
- kisa_utils/__init__.py +1 -0
- kisa_utils/dataStructures.py +89 -0
- kisa_utils/db.py +16 -6
- kisa_utils/response.py +16 -5
- kisa_utils/storage.py +39 -112
- kisa_utils/structures/validator.py +5 -2
- {kisa_utils-0.39.1.dist-info → kisa_utils-0.40.0.dist-info}/METADATA +1 -1
- {kisa_utils-0.39.1.dist-info → kisa_utils-0.40.0.dist-info}/RECORD +10 -9
- {kisa_utils-0.39.1.dist-info → kisa_utils-0.40.0.dist-info}/WHEEL +0 -0
- {kisa_utils-0.39.1.dist-info → kisa_utils-0.40.0.dist-info}/top_level.txt +0 -0
kisa_utils/__init__.py
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import pprint
|
|
3
|
+
|
|
4
|
+
class KDict(dict):
|
|
5
|
+
'''
|
|
6
|
+
A dict subclass that allows attribute access (obj.key)
|
|
7
|
+
and recursively converts nested dicts, lists, tuples, and sets.
|
|
8
|
+
'''
|
|
9
|
+
|
|
10
|
+
def __init__(self, *args, **kwargs):
|
|
11
|
+
super().__init__(*args, **kwargs)
|
|
12
|
+
self._convert_nested()
|
|
13
|
+
|
|
14
|
+
def __getattr__(self, name):
|
|
15
|
+
try:
|
|
16
|
+
return self[name]
|
|
17
|
+
except KeyError:
|
|
18
|
+
raise AttributeError(f"`KDict` object has no attribute '{name}'")
|
|
19
|
+
|
|
20
|
+
def __setattr__(self, name, value):
|
|
21
|
+
self[name] = value
|
|
22
|
+
|
|
23
|
+
def __delattr__(self, name):
|
|
24
|
+
try:
|
|
25
|
+
del self[name]
|
|
26
|
+
except KeyError:
|
|
27
|
+
raise AttributeError(f"`KDict` object has no attribute '{name}'")
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def _wrap(value):
|
|
31
|
+
'''Recursively wrap any dicts inside nested structures.'''
|
|
32
|
+
if isinstance(value, dict) and not isinstance(value, KDict):
|
|
33
|
+
return KDict(value)
|
|
34
|
+
elif isinstance(value, list):
|
|
35
|
+
return [KDict._wrap(v) for v in value]
|
|
36
|
+
elif isinstance(value, tuple):
|
|
37
|
+
return tuple(KDict._wrap(v) for v in value)
|
|
38
|
+
elif isinstance(value, set):
|
|
39
|
+
return {KDict._wrap(v) for v in value}
|
|
40
|
+
else:
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
def _convert_nested(self):
|
|
44
|
+
'''Convert all nested dicts/lists/tuples/sets in self.'''
|
|
45
|
+
for k, v in list(self.items()):
|
|
46
|
+
super().__setitem__(k, self._wrap(v))
|
|
47
|
+
|
|
48
|
+
def copy(self):
|
|
49
|
+
return KDict(copy.deepcopy(self))
|
|
50
|
+
|
|
51
|
+
def update(self, *args, **kwargs):
|
|
52
|
+
result = super().update(*args, **kwargs)
|
|
53
|
+
self._convert_nested()
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def fromkeys(cls, seq, value=None):
|
|
58
|
+
return cls({k: value for k in seq})
|
|
59
|
+
|
|
60
|
+
def __getitem__(self, key):
|
|
61
|
+
value = super().__getitem__(key)
|
|
62
|
+
wrapped = self._wrap(value)
|
|
63
|
+
if wrapped is not value:
|
|
64
|
+
super().__setitem__(key, wrapped)
|
|
65
|
+
return wrapped
|
|
66
|
+
|
|
67
|
+
def toDict(self):
|
|
68
|
+
'''
|
|
69
|
+
convert KDict to dict
|
|
70
|
+
'''
|
|
71
|
+
def unwrap(v):
|
|
72
|
+
if isinstance(v, KDict):
|
|
73
|
+
return {k: unwrap(x) for k, x in v.items()}
|
|
74
|
+
if isinstance(v, list):
|
|
75
|
+
return [unwrap(x) for x in v]
|
|
76
|
+
if isinstance(v, tuple):
|
|
77
|
+
return tuple(unwrap(x) for x in v)
|
|
78
|
+
if isinstance(v, set):
|
|
79
|
+
return {unwrap(x) for x in v}
|
|
80
|
+
return v
|
|
81
|
+
return unwrap(self)
|
|
82
|
+
|
|
83
|
+
def __repr__(self):
|
|
84
|
+
return repr(dict(self))
|
|
85
|
+
|
|
86
|
+
# map the KDict type to pprint's dict pretty-printer
|
|
87
|
+
try:
|
|
88
|
+
pprint.PrettyPrinter._dispatch[KDict.__repr__] = pprint.PrettyPrinter._pprint_dict
|
|
89
|
+
except Exception: pass
|
kisa_utils/db.py
CHANGED
|
@@ -14,6 +14,7 @@ from .response import Error, Ok, Response
|
|
|
14
14
|
from .functionUtils import enforceRequirements, Definition
|
|
15
15
|
from .structures.utils import Value
|
|
16
16
|
from . import structures
|
|
17
|
+
from .dataStructures import KDict
|
|
17
18
|
|
|
18
19
|
if sqlite3.sqlite_version_info[1]<38:
|
|
19
20
|
sys.exit(f'we need sqlite3 v3.38.0+ to run this program. current version::{sqlite3.sqlite_version}')
|
|
@@ -395,7 +396,7 @@ class Api:
|
|
|
395
396
|
|
|
396
397
|
return _data
|
|
397
398
|
|
|
398
|
-
def __decodeOutgoingData(self, data:list[tuple]) -> list[tuple]:
|
|
399
|
+
def __decodeOutgoingData(self, data:list[tuple], dictType:dict|KDict = dict) -> list[tuple]:
|
|
399
400
|
'''
|
|
400
401
|
attempt to decode json objects to python list/dict where applicable.
|
|
401
402
|
Args:
|
|
@@ -408,6 +409,8 @@ class Api:
|
|
|
408
409
|
if value and isinstance(value,str) and (value[0] in '[{'):
|
|
409
410
|
try:
|
|
410
411
|
value = storage.decodeJSON(value)
|
|
412
|
+
if dictType==KDict:
|
|
413
|
+
value = KDict._wrap(value)
|
|
411
414
|
except:
|
|
412
415
|
pass
|
|
413
416
|
|
|
@@ -613,7 +616,8 @@ class Api:
|
|
|
613
616
|
table:str, columns:list, condition:str, conditionData:list,
|
|
614
617
|
limit:int=MAX_FETCH_ITEMS, returnDicts:bool=False,
|
|
615
618
|
returnNamespaces:bool=False, parseJson:bool=False,
|
|
616
|
-
returnGenerator:bool=False
|
|
619
|
+
returnGenerator:bool=False,
|
|
620
|
+
useKDicts:bool=True,
|
|
617
621
|
) -> list|Response:
|
|
618
622
|
'''
|
|
619
623
|
attempt to fetch from the database
|
|
@@ -624,11 +628,12 @@ class Api:
|
|
|
624
628
|
condition(str): a string indicating the SQL condition for the fetch eg `userId=? and dateCreated<?`. all values a represented with the `?` placeholder
|
|
625
629
|
conditionData(list): a list containing the values for each `?` placeholder in the condition
|
|
626
630
|
limit(int): number indicating the maximum number of results to fetch
|
|
627
|
-
returnDicts(bool): if `True`, we shall return a list of dictionaries as opposed to a list of tuples
|
|
631
|
+
returnDicts(bool): if `True`, we shall return a list of dictionaries(KDict if `useKDicts`=`True`) as opposed to a list of tuples
|
|
628
632
|
returnNamespaces(bool): if `True`, we shall return a list of named-tuples as opposed to a list of tuples
|
|
629
633
|
** if both `returnDicts` and `returnNamespaces` are set, `returnDicts` is effected
|
|
630
634
|
parseJson(bool):if `True`, we shall parse json objects to python lists and dictionaries where possible
|
|
631
635
|
returnGenerator(bool): if True, a generator will be returned instead of the list of tuple|dict|SimpleNamespace. this is especially recommended for large data
|
|
636
|
+
useKDicts(bool): if True, all dicts returned are `KDicts` ie dicts that support the dot notation, just like JS objects
|
|
632
637
|
'''
|
|
633
638
|
if not (limit>0 and limit<=MAX_FETCH_ITEMS):
|
|
634
639
|
err = f'please set a limit on the returned rows. maximum should be {MAX_FETCH_ITEMS}'
|
|
@@ -666,18 +671,23 @@ class Api:
|
|
|
666
671
|
except Exception as e:
|
|
667
672
|
return Error(str(e))
|
|
668
673
|
|
|
674
|
+
dictType = KDict if useKDicts else dict
|
|
675
|
+
|
|
669
676
|
fetchedData = self.cursor
|
|
670
677
|
if parseJson and not returnGenerator:
|
|
671
|
-
fetchedData = self.__decodeOutgoingData(fetchedData)
|
|
678
|
+
fetchedData = self.__decodeOutgoingData(fetchedData, dictType=dictType)
|
|
672
679
|
|
|
673
680
|
cols = [_[0] for _ in self.cursor.description]
|
|
674
681
|
|
|
675
682
|
if not (returnDicts or returnNamespaces):
|
|
676
|
-
|
|
683
|
+
if fetchedData == self.cursor:
|
|
684
|
+
fetchedData = [_ for _ in fetchedData]
|
|
685
|
+
|
|
686
|
+
returnData = fetchedData if not returnGenerator else self.__createFetchResultsGenerator(fetchedData, cols, parseJson, 'plain')
|
|
677
687
|
return returnData if not self.__returnKISAResponse else Ok(returnData)
|
|
678
688
|
|
|
679
689
|
if returnDicts:
|
|
680
|
-
returnData = [
|
|
690
|
+
returnData = [dictType(zip(cols,_)) for _ in fetchedData] if not returnGenerator else self.__createFetchResultsGenerator(fetchedData, cols, parseJson, 'dicts')
|
|
681
691
|
return returnData if not self.__returnKISAResponse else Ok(returnData)
|
|
682
692
|
|
|
683
693
|
# namepsaces...
|
kisa_utils/response.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import json as _j; encodeJSON = _j.JSONEncoder().encode
|
|
2
2
|
from typing import Any
|
|
3
3
|
import inspect
|
|
4
4
|
|
|
@@ -57,10 +57,16 @@ class Response(tuple):
|
|
|
57
57
|
'status': self.__status,
|
|
58
58
|
'log': self.__log,
|
|
59
59
|
'data': self.__data,
|
|
60
|
-
}.get(index, self))
|
|
61
|
-
|
|
60
|
+
}.get(index, self)) != self:
|
|
61
|
+
return value
|
|
62
|
+
|
|
63
|
+
if not isinstance(self.__data, dict) or (index not in self.__data):
|
|
64
|
+
return self.__data
|
|
65
|
+
|
|
66
|
+
return self.__data[index]
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
def __getattr__(self, attr):
|
|
69
|
+
return self[attr]
|
|
64
70
|
|
|
65
71
|
def __iter__(self):
|
|
66
72
|
return iter([self[0], self[1]])
|
|
@@ -137,4 +143,9 @@ def Error(log:str) -> Response:
|
|
|
137
143
|
Args:
|
|
138
144
|
log(str): the log to pass to the Response object
|
|
139
145
|
'''
|
|
140
|
-
return Response(False, log=log)
|
|
146
|
+
return Response(False, log=log)
|
|
147
|
+
|
|
148
|
+
if __name__=='__main__':
|
|
149
|
+
r = Ok(74); print(r['xx'], r.xx, r['xy'], r.data, r)
|
|
150
|
+
r = Ok({'xx':50}); print(r['xx'], r.xx, r['xy'], r['data'], r)
|
|
151
|
+
r = Ok({'xx':{'a':13}}); print(r['xx']['a'], r.xx['a'], r['data'], r)
|
kisa_utils/storage.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os, glob, json
|
|
2
2
|
import inspect
|
|
3
|
+
from kisa_utils.response import Response, Error, Ok
|
|
3
4
|
|
|
4
5
|
encodeJSON = json.JSONEncoder().encode
|
|
5
6
|
decodeJSON = json.JSONDecoder().decode
|
|
@@ -22,7 +23,7 @@ class Path:
|
|
|
22
23
|
return os.path.isfile(path)
|
|
23
24
|
|
|
24
25
|
@staticmethod
|
|
25
|
-
def createDirectory(path:str) ->
|
|
26
|
+
def createDirectory(path:str) -> Response:
|
|
26
27
|
'''
|
|
27
28
|
attempt to create a directory provided in `path`.
|
|
28
29
|
Args:
|
|
@@ -31,159 +32,91 @@ class Path:
|
|
|
31
32
|
Note:
|
|
32
33
|
if any intermediate directories dont exist, they will be created as well
|
|
33
34
|
|
|
34
|
-
Returns:
|
|
35
|
-
the standard dict in the form
|
|
36
|
-
```
|
|
37
|
-
{
|
|
38
|
-
'status': bool,
|
|
39
|
-
'log': str
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
35
|
'''
|
|
43
|
-
reply = {'status':False, 'log':''}
|
|
44
36
|
if os.system(f"mkdir -p '{path}' 2> /dev/null"):
|
|
45
|
-
|
|
46
|
-
return reply
|
|
37
|
+
return Error('failed to create directory. please review your permissions')
|
|
47
38
|
|
|
48
|
-
|
|
49
|
-
return reply
|
|
39
|
+
return Ok()
|
|
50
40
|
|
|
51
41
|
@staticmethod
|
|
52
|
-
def createShortcut(source:str, destination:str) ->
|
|
42
|
+
def createShortcut(source:str, destination:str) -> Response:
|
|
53
43
|
'''
|
|
54
44
|
attempt to create a shortcut.
|
|
55
45
|
Args:
|
|
56
46
|
source(str): the path we want to create a shortcut to
|
|
57
47
|
destination(str): the path to the shortcut
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
the standard dict in the form of
|
|
61
|
-
```
|
|
62
|
-
{
|
|
63
|
-
'status': bool,
|
|
64
|
-
'log': str
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
48
|
'''
|
|
68
|
-
reply = {'status':False, 'log':''}
|
|
69
49
|
|
|
70
50
|
if not Path.exists(source):
|
|
71
|
-
|
|
72
|
-
return reply
|
|
51
|
+
return Error('the source path does not exist')
|
|
73
52
|
|
|
74
53
|
if Path.exists(destination):
|
|
75
|
-
|
|
76
|
-
return reply
|
|
54
|
+
return Error('the destination path already exists')
|
|
77
55
|
|
|
78
56
|
if os.system(f"ln -s -T '{source}' '{destination}' 2> /dev/null"):
|
|
79
|
-
|
|
80
|
-
return reply
|
|
57
|
+
return Error('failed to create the shortcut. please confirm that all necessary paths are valid and exist')
|
|
81
58
|
|
|
82
|
-
|
|
83
|
-
return reply
|
|
59
|
+
return Ok()
|
|
84
60
|
|
|
85
61
|
@staticmethod
|
|
86
|
-
def delete(path:str) ->
|
|
62
|
+
def delete(path:str) -> Response:
|
|
87
63
|
'''
|
|
88
64
|
attempt to delete `path`.
|
|
89
65
|
|
|
90
66
|
Note:
|
|
91
67
|
if the path is a directory, it will NOT be deleted if its empty
|
|
92
|
-
|
|
93
|
-
Returns:
|
|
94
|
-
the standard dict in the form
|
|
95
|
-
```
|
|
96
|
-
{
|
|
97
|
-
'status': bool,
|
|
98
|
-
'log': str
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
68
|
'''
|
|
102
|
-
reply = {'status':False, 'log':''}
|
|
103
69
|
|
|
104
70
|
if not Path.exists(path):
|
|
105
|
-
|
|
106
|
-
return reply
|
|
71
|
+
return Error('path does not exist')
|
|
107
72
|
|
|
108
73
|
if Path.isDirectory(path) and os.listdir(path):
|
|
109
|
-
|
|
110
|
-
return reply
|
|
74
|
+
return Error('can not delete a non-empty directory')
|
|
111
75
|
|
|
112
76
|
if Path.isFile(path):
|
|
113
77
|
if os.system(f"rm '{path}' 2> /dev/null"):
|
|
114
|
-
|
|
115
|
-
return reply
|
|
78
|
+
return Error('failed to delete the file. please ensure you have the right permissions')
|
|
116
79
|
else:
|
|
117
80
|
if os.system(f"rmdir '{path}' 2> /dev/null"):
|
|
118
|
-
|
|
119
|
-
return reply
|
|
81
|
+
return Error('failed to delete the directory. please ensure you have the right permissions')
|
|
120
82
|
|
|
121
|
-
|
|
122
|
-
return reply
|
|
83
|
+
return Ok()
|
|
123
84
|
|
|
124
85
|
@staticmethod
|
|
125
|
-
def copy(source:str, destination:str) ->
|
|
86
|
+
def copy(source:str, destination:str) -> Response:
|
|
126
87
|
'''
|
|
127
88
|
attempt to copy a file/directory
|
|
128
89
|
Args:
|
|
129
90
|
source(str): the path we want to copy
|
|
130
91
|
destination(str): the path to the new copy of the file/directory
|
|
131
|
-
|
|
132
|
-
Returns:
|
|
133
|
-
the standard dict in the form
|
|
134
|
-
```
|
|
135
|
-
{
|
|
136
|
-
'status': bool,
|
|
137
|
-
'log': str
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
92
|
'''
|
|
141
|
-
reply = {'status':False, 'log':''}
|
|
142
93
|
|
|
143
94
|
if not Path.exists(source):
|
|
144
|
-
|
|
145
|
-
return reply
|
|
95
|
+
return Error('the source path does not exist')
|
|
146
96
|
|
|
147
97
|
if Path.exists(destination):
|
|
148
|
-
|
|
149
|
-
return reply
|
|
98
|
+
return Error('the destination path already exists')
|
|
150
99
|
|
|
151
100
|
if os.system(f"cp -rfHpu '{source}' '{destination}' 2> /dev/null"):
|
|
152
|
-
|
|
153
|
-
return reply
|
|
101
|
+
return Error('failed to copy the source. please confirm that all necessary paths are valid and exist')
|
|
154
102
|
|
|
155
|
-
|
|
156
|
-
return reply
|
|
103
|
+
return Ok()
|
|
157
104
|
|
|
158
105
|
@staticmethod
|
|
159
|
-
def listDirectory(path:str) ->
|
|
106
|
+
def listDirectory(path:str) -> Response:
|
|
160
107
|
'''
|
|
161
108
|
attempt to list the contents of a directory
|
|
162
109
|
Args:
|
|
163
110
|
path(str): the path to the directory we want to list
|
|
164
|
-
|
|
165
|
-
Returns:
|
|
166
|
-
the standard dict in the form
|
|
167
|
-
```
|
|
168
|
-
{
|
|
169
|
-
'status': bool,
|
|
170
|
-
'log': str,
|
|
171
|
-
'contents': list[str] # list of ABSOLUTE paths
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
111
|
'''
|
|
175
|
-
reply = {'status':False, 'log':'', 'contents':[]}
|
|
176
112
|
|
|
177
113
|
if not Path.isDirectory(path):
|
|
178
|
-
|
|
179
|
-
return reply
|
|
114
|
+
return Error('the path given is not a directory')
|
|
180
115
|
|
|
181
116
|
path += '/*'
|
|
182
117
|
contents = [os.path.abspath(f) for f in glob.glob(path)]
|
|
183
118
|
|
|
184
|
-
|
|
185
|
-
reply['status'] = True
|
|
186
|
-
return reply
|
|
119
|
+
return Ok(contents)
|
|
187
120
|
|
|
188
121
|
@staticmethod
|
|
189
122
|
def getMyAbsolutePath() -> str:
|
|
@@ -206,7 +139,7 @@ class Path:
|
|
|
206
139
|
return os.path.abspath(caller_file)
|
|
207
140
|
|
|
208
141
|
@staticmethod
|
|
209
|
-
def directoryBackAt(path:str, howFarBack:int=0) ->
|
|
142
|
+
def directoryBackAt(path:str, howFarBack:int=0) -> Response:
|
|
210
143
|
'''
|
|
211
144
|
get directory thats `howFarBack` steps from `path`
|
|
212
145
|
Args:
|
|
@@ -223,36 +156,30 @@ class Path:
|
|
|
223
156
|
|
|
224
157
|
if `howFarBack` = 4, then final directory = '/a/b'
|
|
225
158
|
```
|
|
226
|
-
|
|
227
|
-
Returns:
|
|
228
|
-
dict in form
|
|
229
|
-
```
|
|
230
|
-
{
|
|
231
|
-
'status': bool,
|
|
232
|
-
'log': str,
|
|
233
|
-
'directory': str
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
159
|
'''
|
|
237
|
-
reply = {'status':False, 'log':'', 'directory':''}
|
|
238
160
|
|
|
239
161
|
if not Path.exists(path):
|
|
240
|
-
|
|
241
|
-
return reply
|
|
162
|
+
return Error('could not find the given path')
|
|
242
163
|
|
|
243
164
|
if howFarBack<0:
|
|
244
|
-
|
|
245
|
-
return reply
|
|
165
|
+
return Error('invalid value given for `howFarBack`')
|
|
246
166
|
|
|
247
167
|
parent = os.path.dirname(path)
|
|
248
168
|
|
|
249
169
|
if howFarBack >= parent.count('/'):
|
|
250
|
-
|
|
251
|
-
|
|
170
|
+
return Error('value of `howFarBack` goes beyond the root directory `/`')
|
|
171
|
+
|
|
172
|
+
return Ok('/'.join(parent.split('/')[:-howFarBack]) if howFarBack else parent)
|
|
173
|
+
|
|
174
|
+
@staticmethod
|
|
175
|
+
def getAbsolutePath(path:str) -> str:
|
|
176
|
+
'''
|
|
177
|
+
get absolute path to file
|
|
178
|
+
Args:
|
|
179
|
+
path(str): path, relative or otherwise whose absolute path we need
|
|
180
|
+
'''
|
|
181
|
+
return os.path.abspath(path)
|
|
252
182
|
|
|
253
|
-
reply['directory'] = '/'.join(parent.split('/')[:-howFarBack]) if howFarBack else parent
|
|
254
|
-
reply['status'] = True
|
|
255
|
-
return reply
|
|
256
183
|
|
|
257
184
|
if __name__=='__main__':
|
|
258
|
-
|
|
185
|
+
print(Path.getAbsolutePath('.'))
|
|
@@ -7,6 +7,7 @@ from typing import Any, get_args, get_origin
|
|
|
7
7
|
from types import UnionType
|
|
8
8
|
from kisa_utils.structures.utils import Value
|
|
9
9
|
from kisa_utils.response import Response, Ok, Error
|
|
10
|
+
from kisa_utils.dataStructures import KDict
|
|
10
11
|
|
|
11
12
|
def validate(instance:Any, structure:Any, path:str='$') -> dict:
|
|
12
13
|
'''
|
|
@@ -53,11 +54,13 @@ def validate(instance:Any, structure:Any, path:str='$') -> dict:
|
|
|
53
54
|
result['status'] = True
|
|
54
55
|
return result
|
|
55
56
|
else:
|
|
56
|
-
|
|
57
|
+
# checking in both directions as dict and KDict can fail when you check
|
|
58
|
+
# `isinstance(dict, KDict)` but will pass when the arguments switch positions
|
|
59
|
+
if (not isinstance(instance,type(structure))) and (not isinstance(structure, type(instance))):
|
|
57
60
|
result['log'] = f'E02: types not similar:: {path}, expected {str(type(structure))[7:-1]} but got {str(type(instance))[7:-1]}'
|
|
58
61
|
return result
|
|
59
62
|
|
|
60
|
-
if isinstance(structure,dict):
|
|
63
|
+
if isinstance(structure,(dict, KDict)):
|
|
61
64
|
_path = path
|
|
62
65
|
for key in structure:
|
|
63
66
|
path = f'{_path}->{key}'
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
kisa_utils/__init__.py,sha256=
|
|
1
|
+
kisa_utils/__init__.py,sha256=z2vCa2O3W1vOFhW4K0_hkpyEuy_H05WUTzdCPHldCyI,659
|
|
2
2
|
kisa_utils/cache.py,sha256=4Ue5G3QhHSQAmIfQKYgWKWjNL4rA4wLLd_RdBLb2ABY,7345
|
|
3
3
|
kisa_utils/codes.py,sha256=PV_S53Skggf4XetOdYoIKtEmM8cpN5wZwUlxje70WZY,904
|
|
4
4
|
kisa_utils/config.py,sha256=NfluzGKTh66qfNtC-Ae0zNb1XzMTgU2Me9Vi82R9c1E,2285
|
|
5
|
+
kisa_utils/dataStructures.py,sha256=ZgLpttJ66jfpU1NWzLDD1Czqxzj6sWereffgTQWhlV8,2679
|
|
5
6
|
kisa_utils/dates.py,sha256=zxe4n0PdKReZjK5ZkvnCZtJ55lk5oqu9oS8VX_nLozw,13966
|
|
6
|
-
kisa_utils/db.py,sha256=
|
|
7
|
+
kisa_utils/db.py,sha256=oUpqpew3a1a69Ow1xSydfB1S_QhiUrCtba_7dbK0XBs,49715
|
|
7
8
|
kisa_utils/encryption.py,sha256=nFzNpzWV_D9uSEq4FsgCnlS7FQtqWP9fvM_81rsfcLo,4218
|
|
8
9
|
kisa_utils/enqueue.py,sha256=VIliaMvw4MUdOqts0dXdZCYNxs-QrOVjIRAR3scGrRM,11786
|
|
9
10
|
kisa_utils/figures.py,sha256=pYIpQzu1OXRSsY1d98GhgPifnIRmgl-r7S32ai-Ms0c,3731
|
|
@@ -11,9 +12,9 @@ kisa_utils/functionUtils.py,sha256=PlXjnmU1uJWNdISlJJ3SCgavTsgNBoebaa9dtWSFhRA,6
|
|
|
11
12
|
kisa_utils/log.py,sha256=0TYdxcIBts026RCSuVIQBcZ-CW1ES7n3M1nEIjmeLTM,2295
|
|
12
13
|
kisa_utils/queues.py,sha256=9QqPtDujw6tbWk7uUiXrsd0rVBTIkzeQw9b45l5Fo3k,6502
|
|
13
14
|
kisa_utils/remote.py,sha256=0RDrfC4RUW4m6JLziC0_EXJYqzWp38Rw8NDroJ0MuqI,2149
|
|
14
|
-
kisa_utils/response.py,sha256=
|
|
15
|
+
kisa_utils/response.py,sha256=asETUBkeF5OlSTwa-coa7lZDCKmQlHCmHf6eaZFl8CU,4560
|
|
15
16
|
kisa_utils/standardize.py,sha256=nt-uzHQFoKxGscD_MpDYXw65Teg3724whAqa6Kh_zhE,2231
|
|
16
|
-
kisa_utils/storage.py,sha256=
|
|
17
|
+
kisa_utils/storage.py,sha256=waHLmrf19QxvEQZlWlC2qQvEYFFhDeJHc7MMNbcmj7c,5823
|
|
17
18
|
kisa_utils/threads.py,sha256=qQqsf64YHMyLpboq5AEXKxYqf3iXUhxiJe6Ymg-vlxI,12840
|
|
18
19
|
kisa_utils/token.py,sha256=Y2qglWYWpmHxoXBh-TH0r1as0uPV5LLqMNcunLvM4vM,7850
|
|
19
20
|
kisa_utils/permissions/__config__.py,sha256=i3ELkOydDnjKx2ozQTxLZdZ8DXSeUncnl2kRxANjFmM,613
|
|
@@ -22,8 +23,8 @@ kisa_utils/servers/__init__.py,sha256=lPqDyGTrFo0qwPZ2WA9Xtcpc5D8AIU4huqgFx1iZf6
|
|
|
22
23
|
kisa_utils/servers/flask.py,sha256=XZYY1pWnP1mSvaS5Uv8G3EFJV5BJBQtU2gDbO8suvLc,40422
|
|
23
24
|
kisa_utils/structures/__init__.py,sha256=JBU1j3A42jQ62ALKnsS1Hav9YXcYwjDw1wQJtohXPbU,83
|
|
24
25
|
kisa_utils/structures/utils.py,sha256=665rXIapGwFqejizeJwy3DryeskCQOdgP25BCdLkGvk,2898
|
|
25
|
-
kisa_utils/structures/validator.py,sha256=
|
|
26
|
-
kisa_utils-0.
|
|
27
|
-
kisa_utils-0.
|
|
28
|
-
kisa_utils-0.
|
|
29
|
-
kisa_utils-0.
|
|
26
|
+
kisa_utils/structures/validator.py,sha256=JhD9jcfbjTwBr_7OfuNaJd_cYr7wR2emFhsCEo5MCHQ,4323
|
|
27
|
+
kisa_utils-0.40.0.dist-info/METADATA,sha256=OxeJF4Wb_Yk5x5spw-v8bdERToTAICfPzHPs9ntEyhg,477
|
|
28
|
+
kisa_utils-0.40.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
29
|
+
kisa_utils-0.40.0.dist-info/top_level.txt,sha256=URxY4sRuqmirOxWtztpVmPoGQdksEMYO6hmYsEDGz2Y,75
|
|
30
|
+
kisa_utils-0.40.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|