unisi 0.1.13__py3-none-any.whl → 0.1.14__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.
- unisi/common.py +123 -7
- unisi/containers.py +3 -3
- unisi/dbelements.py +155 -0
- unisi/guielements.py +8 -23
- unisi/kdb.py +336 -0
- unisi/multimon.py +7 -5
- unisi/reloader.py +2 -2
- unisi/server.py +9 -1
- unisi/tables.py +176 -56
- unisi/users.py +44 -35
- unisi/utils.py +28 -81
- unisi/web/index.html +1 -1
- unisi/web/js/346.c574f9c3.js +2 -0
- unisi/web/js/{app.cf197a5a.js → app.4b51aa78.js} +1 -1
- {unisi-0.1.13.dist-info → unisi-0.1.14.dist-info}/METADATA +31 -5
- {unisi-0.1.13.dist-info → unisi-0.1.14.dist-info}/RECORD +19 -17
- {unisi-0.1.13.dist-info → unisi-0.1.14.dist-info}/WHEEL +1 -1
- unisi/web/js/493.97ca799d.js +0 -1
- /unisi/web/css/{493.824522cf.css → 346.824522cf.css} +0 -0
- {unisi-0.1.13.dist-info → unisi-0.1.14.dist-info}/licenses/LICENSE +0 -0
unisi/common.py
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
import jsonpickle
|
1
|
+
import jsonpickle, inspect
|
2
|
+
|
3
|
+
UpdateScreen = True
|
4
|
+
Redesign = 2
|
2
5
|
|
3
6
|
def flatten(*arr):
|
4
7
|
for a in arr:
|
@@ -6,22 +9,135 @@ def flatten(*arr):
|
|
6
9
|
yield from flatten(*a)
|
7
10
|
else:
|
8
11
|
yield a
|
9
|
-
|
12
|
+
|
13
|
+
def compose_returns(*arr):
|
14
|
+
objs = set()
|
15
|
+
update_screen = False
|
16
|
+
for obj in flatten(*arr):
|
17
|
+
if obj is Redesign:
|
18
|
+
return obj
|
19
|
+
elif obj is True:
|
20
|
+
update_screen = True
|
21
|
+
elif obj is not None:
|
22
|
+
objs.add(obj)
|
23
|
+
if update_screen:
|
24
|
+
return True
|
25
|
+
if objs:
|
26
|
+
return list(objs)
|
27
|
+
|
28
|
+
def equal_dicts(dict1, dict2):
|
29
|
+
return dict1.keys() == dict2.keys() and all(dict1[key] == dict2[key] for key in dict1)
|
30
|
+
|
10
31
|
class ArgObject:
|
11
32
|
def __init__(self, **kwargs):
|
12
33
|
self.__dict__.update(kwargs)
|
34
|
+
def __getattr__(self, _):
|
35
|
+
"""return None for unknown props"""
|
36
|
+
return None
|
13
37
|
|
14
|
-
class ReceivedMessage:
|
15
|
-
def __init__(self,
|
16
|
-
|
17
|
-
self.screen = data.get('screen')
|
18
|
-
self.value = data.get('value')
|
38
|
+
class ReceivedMessage(ArgObject):
|
39
|
+
def __init__(self, kwargs):
|
40
|
+
super().__init__(**kwargs)
|
19
41
|
def __str__(self):
|
20
42
|
return f'{self.block}/{self.element}->{self.event}({self.value})'
|
21
43
|
|
22
44
|
def toJson(obj):
|
23
45
|
return jsonpickle.encode(obj,unpicklable = False)
|
24
46
|
|
47
|
+
def set_defaults(self, param_defaults : dict):
|
48
|
+
for param, value in param_defaults.items():
|
49
|
+
if not hasattr(self, param):
|
50
|
+
setattr(self, param, value)
|
51
|
+
|
52
|
+
def pretty4(name):
|
53
|
+
pretty_name = name.replace('_',' ')
|
54
|
+
return pretty_name[0].upper() + pretty_name[1:]
|
55
|
+
|
56
|
+
def is_callable(obj):
|
57
|
+
return inspect.isfunction(obj) or inspect.ismethod(obj) or inspect.iscoroutine(obj) or callable(obj)
|
58
|
+
|
59
|
+
def context_object(target_type):
|
60
|
+
"""
|
61
|
+
Finds the first argument of a specific type in the current function call stack.
|
62
|
+
"""
|
63
|
+
frame = inspect.currentframe()
|
64
|
+
while frame:
|
65
|
+
args, _, _, values = inspect.getargvalues(frame)
|
66
|
+
if args and isinstance(values[args[0]], target_type):
|
67
|
+
return values[args[0]]
|
68
|
+
# Move to the previous frame in the call stack
|
69
|
+
frame = frame.f_back
|
70
|
+
return None
|
71
|
+
|
72
|
+
def get_default_args(func):
|
73
|
+
"""
|
74
|
+
class F:
|
75
|
+
def example_function(a, b, c=10, d='hello'):
|
76
|
+
pass
|
77
|
+
f = F()
|
78
|
+
default_args = get_default_args(f.example_function)
|
79
|
+
print(default_args)
|
80
|
+
"""
|
81
|
+
# Get the signature of the function
|
82
|
+
sig = inspect.signature(func)
|
83
|
+
# Dictionary to store arguments with their default values
|
84
|
+
defaults = {}
|
85
|
+
for name, param in sig.parameters.items():
|
86
|
+
if param.default != inspect.Parameter.empty:
|
87
|
+
defaults[name] = param.default
|
88
|
+
return defaults
|
89
|
+
|
90
|
+
references = ArgObject(context_user = None)
|
91
|
+
|
92
|
+
class Message:
|
93
|
+
def __init__(self, *gui_objects, user = None, type = 'update'):
|
94
|
+
self.type = type
|
95
|
+
if gui_objects:
|
96
|
+
self.updates = [{'data': gui} for gui in gui_objects]
|
97
|
+
if user:
|
98
|
+
self.fill_paths4(user)
|
99
|
+
|
100
|
+
def fill_paths4(self, user):
|
101
|
+
if hasattr(self, 'updates'):
|
102
|
+
invalid = []
|
103
|
+
for update in self.updates:
|
104
|
+
data = update["data"]
|
105
|
+
path = user.find_path(data)
|
106
|
+
if path:
|
107
|
+
update['path'] = path
|
108
|
+
else:
|
109
|
+
invalid.append(update)
|
110
|
+
user.log(f'Invalid element update {data.name}, type {data.type}.\n\
|
111
|
+
Such element not on the screen!')
|
112
|
+
for inv in invalid:
|
113
|
+
self.updates.remove(inv)
|
114
|
+
|
115
|
+
def contains(self, guiobj):
|
116
|
+
if hasattr(self, 'updates'):
|
117
|
+
for update in self.updates:
|
118
|
+
if guiobj is update['data']:
|
119
|
+
return True
|
120
|
+
|
121
|
+
def TypeMessage(type, value, *data, user = None):
|
122
|
+
message = Message(*data, user=user, type = type)
|
123
|
+
message.value = value
|
124
|
+
return message
|
125
|
+
|
126
|
+
def Warning(text, *data):
|
127
|
+
return TypeMessage('warning', text, *data)
|
128
|
+
|
129
|
+
def Error(text, *data):
|
130
|
+
return TypeMessage('error', text, *data)
|
131
|
+
|
132
|
+
def Info(text, *data):
|
133
|
+
return TypeMessage('info', text, *data)
|
134
|
+
|
135
|
+
def Answer(type, message, result):
|
136
|
+
ms = TypeMessage(type, result)
|
137
|
+
ms.message = message
|
138
|
+
return ms
|
139
|
+
|
140
|
+
|
25
141
|
|
26
142
|
|
27
143
|
|
unisi/containers.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from .guielements import
|
1
|
+
from .guielements import *
|
2
|
+
from .common import pretty4
|
2
3
|
from numbers import Number
|
3
4
|
|
4
5
|
|
@@ -58,8 +59,7 @@ class ParamBlock(Block):
|
|
58
59
|
cnt = 0
|
59
60
|
|
60
61
|
for param, val in params.items():
|
61
|
-
pretty_name = param
|
62
|
-
pretty_name = pretty_name[0].upper() + pretty_name[1:]
|
62
|
+
pretty_name = pretty4(param)
|
63
63
|
t = type(val)
|
64
64
|
if t == str or t == int or t == float:
|
65
65
|
el = Edit(pretty_name, val)
|
unisi/dbelements.py
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
class Dblist:
|
2
|
+
def __init__(self, dbtable, init_list = None, cache = None):
|
3
|
+
self.cache = cache
|
4
|
+
self.limit = dbtable.limit
|
5
|
+
if cache is not None:
|
6
|
+
init_list = cache[:self.limit]
|
7
|
+
elif init_list is None:
|
8
|
+
raise AttributeError('init_list or cache has to be assigned!')
|
9
|
+
|
10
|
+
self.delta_list = {0 : init_list}
|
11
|
+
self.dbtable = dbtable
|
12
|
+
self.update = dict(type ='init', length = len(self),
|
13
|
+
limit = self.limit, data = init_list)
|
14
|
+
|
15
|
+
def get_delta_0(self):
|
16
|
+
return self.delta_list[0]
|
17
|
+
|
18
|
+
def __getattribute__(self, name):
|
19
|
+
if name == '__dict__':
|
20
|
+
return object.__getattribute__(self, 'update')
|
21
|
+
return object.__getattribute__(self, name)
|
22
|
+
|
23
|
+
def __getattr__(self, name):
|
24
|
+
return self.dbtable.limit if name == 'limit' else None
|
25
|
+
|
26
|
+
""" The methods causes invalid serialization!
|
27
|
+
def __iter__(self):
|
28
|
+
"Override the default iterator to provide custom behavior."
|
29
|
+
self._index = 0
|
30
|
+
return self
|
31
|
+
|
32
|
+
def __next__(self):
|
33
|
+
if self._index < len(self):
|
34
|
+
value = self[self._index]
|
35
|
+
self._index += 1
|
36
|
+
return value
|
37
|
+
else:
|
38
|
+
raise StopIteration
|
39
|
+
"""
|
40
|
+
|
41
|
+
def __str__(self):
|
42
|
+
return f'\ndeltas: {self.delta_list}\nupdate: {self.update}'
|
43
|
+
|
44
|
+
def get_delta_chunk(self, index):
|
45
|
+
if index >= len(self):
|
46
|
+
return -1, None
|
47
|
+
delta_list = index // self.limit * self.limit
|
48
|
+
|
49
|
+
if self.cache is not None:
|
50
|
+
return delta_list, self.cache[delta_list:delta_list + self.limit]
|
51
|
+
|
52
|
+
lst = self.delta_list.get(delta_list)
|
53
|
+
if lst:
|
54
|
+
return delta_list, lst
|
55
|
+
lst = self.dbtable.read_rows(skip = delta_list)
|
56
|
+
self.delta_list[delta_list] = lst
|
57
|
+
return delta_list, lst
|
58
|
+
|
59
|
+
def __getitem__(self, index):
|
60
|
+
if self.cache is not None:
|
61
|
+
return self.cache[index]
|
62
|
+
delta_list, chunk = self.get_delta_chunk(index)
|
63
|
+
if chunk:
|
64
|
+
return chunk[index - delta_list]
|
65
|
+
|
66
|
+
def __setitem__(self, index, value):
|
67
|
+
if self.cache is not None:
|
68
|
+
self.cache[index] = value
|
69
|
+
else:
|
70
|
+
delta_list, chunk = self.get_delta_chunk(index)
|
71
|
+
if chunk:
|
72
|
+
chunk[index - delta_list] = value
|
73
|
+
self.update = dict(type = 'update', index = index, data = value)
|
74
|
+
self.dbtable.assign_row(value)
|
75
|
+
|
76
|
+
def clean_cache_from(self, delta_list):
|
77
|
+
"""clear dirty delta_list cache"""
|
78
|
+
self.delta_list = {k: v for k, v in self.delta_list.items() if k < delta_list}
|
79
|
+
|
80
|
+
def __delitem__(self, index):
|
81
|
+
delta_list, chunk = self.get_delta_chunk(index)
|
82
|
+
if chunk:
|
83
|
+
self.dbtable.delete_row(index)
|
84
|
+
self.update = dict(type ='delete', index = index)
|
85
|
+
del chunk[index - delta_list]
|
86
|
+
limit = self.dbtable.limit
|
87
|
+
next_delta_list = delta_list + limit
|
88
|
+
while len(chunk) == limit - 1: #chunk was fully filled
|
89
|
+
next_list = self.delta_list.get(next_delta_list)
|
90
|
+
if next_list:
|
91
|
+
chunk.append(next_list[0])
|
92
|
+
chunk = next_list
|
93
|
+
next_delta_list += limit
|
94
|
+
del next_list[0]
|
95
|
+
else:
|
96
|
+
last = self.dbtable.read_rows(skip = next_delta_list - 1, limit = 1)[0]
|
97
|
+
chunk.append(last)
|
98
|
+
#clean dictionary from following elements
|
99
|
+
self.clean_cache_from(next_delta_list)
|
100
|
+
break
|
101
|
+
|
102
|
+
def __len__(self):
|
103
|
+
return len(self.cache) if self.cache is not None else self.dbtable.length
|
104
|
+
|
105
|
+
def append(self, value):
|
106
|
+
if self.cache is not None:
|
107
|
+
self.cache.append(value)
|
108
|
+
return value[-1]
|
109
|
+
index = len(self)
|
110
|
+
id = self.dbtable.append_row(value)
|
111
|
+
delta_list = index // self.limit * self.limit
|
112
|
+
list = self.delta_list.get(delta_list)
|
113
|
+
if list:
|
114
|
+
list.append(value)
|
115
|
+
self.update = dict(type = 'add', index = index, data = value)
|
116
|
+
return id
|
117
|
+
|
118
|
+
def extend(self, rows):
|
119
|
+
start = self.dbtable.length
|
120
|
+
rows = self.dbtable.append_rows(rows)
|
121
|
+
len_rows = len(rows)
|
122
|
+
delta_list_update = start
|
123
|
+
|
124
|
+
i_rows = 0
|
125
|
+
while len_rows > 0:
|
126
|
+
delta_list = start // self.limit * self.limit
|
127
|
+
list = self.delta_list.get(delta_list)
|
128
|
+
if list is None:
|
129
|
+
list = []
|
130
|
+
self.delta_list[delta_list] = list
|
131
|
+
can_fill = self.limit
|
132
|
+
else:
|
133
|
+
can_fill = self.limit - len(list)
|
134
|
+
if can_fill:
|
135
|
+
list.extend(rows[i_rows: i_rows + can_fill])
|
136
|
+
|
137
|
+
i_rows += can_fill
|
138
|
+
start += can_fill
|
139
|
+
len_rows -= can_fill
|
140
|
+
self.update = self.dbtable.get_init_list().update
|
141
|
+
|
142
|
+
def insert(self, index, value):
|
143
|
+
self.append(value)
|
144
|
+
|
145
|
+
def remove(self, value):
|
146
|
+
index = value[-1]
|
147
|
+
del self[index]
|
148
|
+
|
149
|
+
def pop(self, index = -1):
|
150
|
+
value = self[index]
|
151
|
+
del self[index]
|
152
|
+
return value
|
153
|
+
|
154
|
+
def clear(self):
|
155
|
+
self.dbtable.clear()
|
unisi/guielements.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
from .common import set_defaults
|
2
|
+
|
1
3
|
class Gui:
|
2
4
|
def __init__(self, name, *args, **kwargs):
|
3
5
|
self.name = name
|
@@ -20,7 +22,7 @@ class Gui:
|
|
20
22
|
else:
|
21
23
|
self.value = value
|
22
24
|
|
23
|
-
Line = Gui("
|
25
|
+
Line = Gui("__Line__", type = 'line')
|
24
26
|
|
25
27
|
def smart_complete(lst, min_input_length = 0, max_output_length = 20):
|
26
28
|
di = {it: it.lower() for it in lst}
|
@@ -105,10 +107,7 @@ class Video(Gui):
|
|
105
107
|
def __init__(self,name, *args, **kwargs):
|
106
108
|
super().__init__(name, *args, **kwargs)
|
107
109
|
self.type = 'video'
|
108
|
-
|
109
|
-
self.url = self.name
|
110
|
-
if not hasattr(self,'ratio'):
|
111
|
-
self.ratio = None
|
110
|
+
set_defaults(self, {'url': self.name, 'ratio' : None})
|
112
111
|
|
113
112
|
class Node:
|
114
113
|
def __init__(self, name = '', color = '', size = 0, id = ''):
|
@@ -141,28 +140,17 @@ class Graph(Gui):
|
|
141
140
|
def __init__(self, name, *args, **kwargs):
|
142
141
|
super().__init__(name, *args, **kwargs)
|
143
142
|
self.type='graph'
|
144
|
-
|
145
|
-
self.value = graph_default_value
|
146
|
-
if not hasattr(self, 'nodes'):
|
147
|
-
self.nodes = []
|
148
|
-
if not hasattr(self, 'edges'):
|
149
|
-
self.edges = []
|
143
|
+
set_defaults(self,{'value': graph_default_value, 'nodes': [], 'edges': []})
|
150
144
|
|
151
145
|
class Switch(Gui):
|
152
146
|
def __init__(self,name, *args, **kwargs):
|
153
147
|
super().__init__(name, *args, **kwargs)
|
154
|
-
|
155
|
-
self.value = False
|
156
|
-
if not hasattr(self,'type'):
|
157
|
-
self.type = 'switch'
|
148
|
+
set_defaults(self,{'value': False, 'type': 'switch'})
|
158
149
|
|
159
150
|
class Select(Gui):
|
160
151
|
def __init__(self,name, *args, **kwargs):
|
161
152
|
super().__init__(name, *args, **kwargs)
|
162
|
-
|
163
|
-
self.options = []
|
164
|
-
if not hasattr(self,'value'):
|
165
|
-
self.value = None
|
153
|
+
set_defaults(self,{'options': [], 'value': None})
|
166
154
|
if not hasattr(self, 'type'):
|
167
155
|
self.type = 'select' if len(self.options) > 3 else 'radio'
|
168
156
|
|
@@ -170,10 +158,7 @@ class Tree(Gui):
|
|
170
158
|
def __init__(self,name, *args, **kwargs):
|
171
159
|
super().__init__(name, *args, **kwargs)
|
172
160
|
self.type = 'tree'
|
173
|
-
|
174
|
-
self.options = {}
|
175
|
-
if not hasattr(self,'value'):
|
176
|
-
self.value = None
|
161
|
+
set_defaults(self,{'options': [], 'value': None})
|
177
162
|
|
178
163
|
class TextArea(Gui):
|
179
164
|
def __init__(self,name, *args, **kwargs):
|