unisi 0.2.3__py3-none-any.whl → 0.2.5__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 CHANGED
@@ -10,6 +10,12 @@ def flatten(*arr):
10
10
  else:
11
11
  yield a
12
12
 
13
+ def index_of(lst, target):
14
+ try:
15
+ return lst.index(target)
16
+ except ValueError:
17
+ return -1
18
+
13
19
  def compose_handlers(*handlers):
14
20
  async def compose(obj, value):
15
21
  objs = set()
unisi/containers.py CHANGED
@@ -1,6 +1,167 @@
1
1
  from .units import *
2
+ from .tables import Table
2
3
  from .common import pretty4, flatten
3
4
  from numbers import Number
5
+ from collections import defaultdict
6
+ from collections.abc import Iterable
7
+
8
+ class Node:
9
+ def __init__(self, name , color = '', size = 0, image = ''):
10
+ if name:
11
+ self.name = name
12
+ if image:
13
+ self.type = 'image'
14
+ self.image = image
15
+ else:
16
+ self.type = ''
17
+ if color:
18
+ self.color = color
19
+ if size:
20
+ self.size = size
21
+
22
+ class Edge:
23
+ def __init__(self, source, target, name = '', color = '', size = 0, property = None):
24
+ self.source = source
25
+ self.target = target
26
+ if name:
27
+ self.name = name
28
+ if color:
29
+ self.color = color
30
+ if size:
31
+ self.size = size
32
+ if property is not None:
33
+ self.property = property
34
+ def __str__(self):
35
+ return f"Edge({self.source}->{self.target})"
36
+ def __repr__(self):
37
+ return f"Edge({self.source}->{self.target})"
38
+
39
+ graph_default_value = {'nodes' : [], 'edges' : []}
40
+
41
+ class Graph(Unit):
42
+ '''has to contain nodes, edges, see Readme'''
43
+ def __init__(self, name, *args, **kwargs):
44
+ super().__init__(name, *args, **kwargs)
45
+ set_defaults(self, dict(type ='graph', value = graph_default_value, nodes = [], edges = []))
46
+
47
+ Topology = lambda: defaultdict(lambda: defaultdict(lambda: {}))
48
+
49
+ def unit2image(unit):
50
+ match unit:
51
+ case Block():
52
+ return 'https://img.icons8.com/fluency/48/object.png'
53
+ case Button():
54
+ return 'https://img.icons8.com/ios-filled/50/doorbell.png'
55
+ case Edit() | Text():
56
+ return 'https://img.icons8.com/fluency-systems-filled/50/123.png' if unit.type == 'number'\
57
+ else 'https://img.icons8.com/sf-regular/48/abc.png'
58
+ case Switch():
59
+ return 'https://img.icons8.com/ios/50/toggle-on--v1.png'
60
+ case TextArea():
61
+ return 'https://img.icons8.com/color/48/align-cell-content-left.png'
62
+ case Table():
63
+ return 'https://img.icons8.com/color/48/day-view.png' if unit.type == 'table'\
64
+ else 'https://img.icons8.com/ultraviolet/40/combo-chart.png'
65
+ case Tree():
66
+ return 'https://img.icons8.com/external-flatart-icons-outline-flatarticons/64/external-tree-nature-flatart-icons-outline-flatarticons-3.png'
67
+ case Select():
68
+ return 'https://img.icons8.com/cotton/64/list--v2.png'
69
+ case Graph():
70
+ return 'https://img.icons8.com/external-vitaliy-gorbachev-blue-vitaly-gorbachev/50/external-nodes-cryptocurrency-vitaliy-gorbachev-blue-vitaly-gorbachev.png'
71
+ case Range():
72
+ return 'https://img.icons8.com/ios/50/slider-control.png'
73
+ case Unit():
74
+ return 'https://img.icons8.com/ios-filled/50/link--v1.png'
75
+ case _:
76
+ return ''
77
+
78
+ class Net(Graph):
79
+ """Graph of Units"""
80
+ def __init__(self, name, topology = Topology(), *args, **kwargs):
81
+ super().__init__(name, *args, **kwargs)
82
+ self.type = 'graph'
83
+ self.topology = topology
84
+ changed_handler = getattr(self, 'changed', None)
85
+
86
+ def changed_converter(_, value):
87
+ mark_changed = self._mark_changed
88
+ self._mark_changed = None #turn off for 'value' diff reaction
89
+ self._value = value
90
+ narray = self._narray
91
+ value = dict(nodes = [self._narray[i] for i in value['nodes']], edges =
92
+ [Edge(narray[self._edges[i].source], narray[self._edges[i].target]) for i in value['edges']])
93
+ if changed_handler:
94
+ result = changed_handler(_, value)
95
+ else:
96
+ result = None
97
+ self.value = value
98
+ self._mark_changed = mark_changed #turn on
99
+ return result
100
+ self.changed = changed_converter
101
+
102
+ def specific_changed_register(self, property = None, value = None):
103
+ """ mark serial info as invalid """
104
+ if property:
105
+ if property.startswith('_'):
106
+ return False
107
+ else:
108
+ self.delattr('_nodes')
109
+ self.delattr('_value')
110
+ return True
111
+
112
+ def elements(self, stubs=True):
113
+ if not hasattr(self, '_nodes'):
114
+ self.__getstate__()
115
+ return self.narray
116
+
117
+ def __getstate__(self):
118
+ if not hasattr(self, '_nodes'):
119
+ nodes = []
120
+ narray = []
121
+ earray = []
122
+ for sunit, links in self.topology.items():
123
+ sindex = index_of(narray,sunit)
124
+ if sindex == -1:
125
+ sindex = len(narray)
126
+ narray.append(sunit)
127
+ nodes.append(Node(sunit.name, image = unit2image(sunit),
128
+ color = 'white', size = 15))
129
+ for dunit in links:
130
+ dindex = index_of(narray,dunit)
131
+ if dindex == -1:
132
+ dindex = len(narray)
133
+ narray.append(dunit)
134
+ nodes.append(Node(dunit.name, image = unit2image(dunit),
135
+ color = 'white', size = 15))
136
+ earray.append(Edge(sindex, dindex))
137
+ self._nodes = nodes
138
+ self._edges = earray
139
+ self._narray = narray
140
+
141
+ if not hasattr(self, '_value'):
142
+ self._value = dict(nodes = [index_of(self._narray,unit) for unit in self.value['nodes']],
143
+ edges = [Edge(index_of(self._narray, e.source), index_of(self._narray, e.target)) for e in self.value['edges']])
144
+ return dict(name = self.name, type = self.type, nodes = self._nodes, edges = self._edges, value = self._value)
145
+
146
+ def make_topology(self, unit: Unit | Iterable):
147
+ topo = Topology()
148
+ def dive(unit):
149
+ match unit:
150
+ case Iterable():
151
+ node = Unit('Union', type = 'union')
152
+ for obj in unit:
153
+ if obj:
154
+ topo[node][dive(obj)] = {}
155
+ return node
156
+ case Block():
157
+ for obj in unit.value:
158
+ if obj:
159
+ topo[unit][dive(obj)] = {}
160
+ case _: ...
161
+ return unit
162
+ dive(unit)
163
+ self.topology = topo
164
+ self.specific_changed_register()
4
165
 
5
166
  class ContentScaler(Range):
6
167
  def __init__(self, *args, **kwargs):
unisi/units.py CHANGED
@@ -1,8 +1,6 @@
1
1
  from .common import *
2
2
  from .llmrag import get_property
3
3
 
4
- atomics = (int, float, complex, bool, str, bytes, type(None))
5
-
6
4
  class ChangedProxy:
7
5
  MODIFYING_METHODS = {
8
6
  'append', 'extend', 'insert', 'remove', 'pop', 'clear', 'sort', 'reverse',
@@ -47,6 +45,8 @@ class ChangedProxy:
47
45
 
48
46
  def __getstate__(self):
49
47
  return self._obj
48
+
49
+ atomics = (int, float, complex, bool, str, bytes, ChangedProxy, type(None))
50
50
 
51
51
  class Unit:
52
52
  def __init__(self, name, *args, **kwargs):
@@ -59,6 +59,10 @@ class Unit:
59
59
  self.changed = args[1]
60
60
  self.add(kwargs)
61
61
 
62
+ def specific_changed_register(self, property, value) -> bool:
63
+ """ addtional actions when changed, return False if not changed"""
64
+ return not property or not property.startswith('_')
65
+
62
66
  def set_reactivity(self, user, override = False):
63
67
  changed_call = None
64
68
  if user:
@@ -67,17 +71,13 @@ class Unit:
67
71
  if not isinstance(value, atomics) and not callable(value)})
68
72
 
69
73
  def changed_call(property = None, value = None):
70
- user.register_changed_unit(self, property, value)
74
+ if self.specific_changed_register(property, value):
75
+ user.register_changed_unit(self, property, value)
71
76
  super().__setattr__('_mark_changed', changed_call)
72
77
 
73
78
  def add(self, kwargs):
74
79
  for key, value in kwargs.items():
75
- setattr(self, key, value)
76
-
77
- def mutate(self, obj):
78
- self.__dict__ = obj.__dict__
79
- if self._mark_changed:
80
- self._mark_changed()
80
+ setattr(self, key, value)
81
81
 
82
82
  def __setattr__(self, name, value):
83
83
  #it is correct condition order
@@ -100,6 +100,10 @@ class Unit:
100
100
  else:
101
101
  self.value = value
102
102
 
103
+ def delattr(self, attr):
104
+ if hasattr(self, attr):
105
+ delattr(self, attr)
106
+
103
107
  @property
104
108
  def compact_view(self) -> str:
105
109
  """reduce for external (llm) using if required"""
@@ -122,6 +126,12 @@ class Unit:
122
126
  obj.value = value
123
127
  self.changed = compose_handlers(changed_handler, handler)
124
128
 
129
+ def __str__(self):
130
+ return f'{type(self).__name__}({self.name})'
131
+
132
+ def __repr__(self):
133
+ return f'{type(self).__name__}({self.name})'
134
+
125
135
  Line = Unit("__Line__", type = 'line')
126
136
 
127
137
  def smart_complete(lst, min_input_length = 0, max_output_length = 20):
@@ -209,39 +219,7 @@ class Video(Unit):
209
219
  def __init__(self,name, *args, **kwargs):
210
220
  super().__init__(name, *args, **kwargs)
211
221
  self.type = 'video'
212
- set_defaults(self, {'url': self.name, 'ratio' : None})
213
-
214
- class Node:
215
- def __init__(self, name = '',id = '', color = '', size = 0):
216
- if name:
217
- self.name = name
218
- if color:
219
- self.color = color
220
- if size:
221
- self.size = size
222
- if id:
223
- self.id = id
224
-
225
- class Edge:
226
- def __init__(self, source, target, name = '', id = '', color = '', size = 0):
227
- self.source = source
228
- self.target = target
229
- if name:
230
- self.name = name
231
- if color:
232
- self.color = color
233
- if size:
234
- self.size = size
235
- if id:
236
- self.id = id
237
-
238
- graph_default_value = {'nodes' : [], 'edges' : []}
239
-
240
- class Graph(Unit):
241
- '''has to contain nodes, edges, see Readme'''
242
- def __init__(self, name, *args, **kwargs):
243
- super().__init__(name, *args, **kwargs)
244
- set_defaults(self, dict(type ='graph', value = graph_default_value, nodes = [], edges = []))
222
+ set_defaults(self, {'url': self.name, 'ratio' : None})
245
223
 
246
224
  class Switch(Unit):
247
225
  def __init__(self,name, *args, **kwargs):
unisi/users.py CHANGED
@@ -6,7 +6,6 @@ from .multimon import notify_monitor, logging_lock, run_external_process
6
6
  from .kdb import Database
7
7
  from .dbunits import dbshare, dbupdates
8
8
  import sys, asyncio, logging, importlib
9
- from collections.abc import Iterable
10
9
 
11
10
  class User:
12
11
  last_user = None
@@ -124,9 +123,9 @@ class User:
124
123
  if self.screens:
125
124
  self.screens.sort(key=lambda s: s.screen.order)
126
125
  main = self.screens[0]
127
- if hasattr(main, 'prepare'):
128
- main.prepare()
129
126
  self.screen_module = main
127
+ if hasattr(main, 'prepare'):
128
+ main.prepare()
130
129
  self.update_menu()
131
130
  self.set_clean()
132
131
  return True
@@ -202,7 +201,7 @@ class User:
202
201
  if c.name == elname:
203
202
  return c
204
203
 
205
- def find_path(self, elem):
204
+ def find_path(self, elem) -> list:
206
205
  for bl in flatten(self.blocks):
207
206
  if bl == elem:
208
207
  return [bl.name]
unisi/web/index.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><base href=/ ><title>UNISI</title><meta charset=utf-8><meta name=description content="UNISI on Quasar"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src=/js/vendor.eab68489.js></script><script defer src=/js/app.cb79330d.js></script><link href=/css/vendor.9ed7638d.css rel=stylesheet><link href=/css/app.31d6cfe0.css rel=stylesheet></head><body><div id=q-app></div></body></html>
1
+ <!DOCTYPE html><html><head><base href=/ ><title>UNISI</title><meta charset=utf-8><meta name=description content="UNISI on Quasar"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src=/js/vendor.2875b6c7.js></script><script defer src=/js/app.2b81b997.js></script><link href=/css/vendor.9ed7638d.css rel=stylesheet><link href=/css/app.31d6cfe0.css rel=stylesheet></head><body><div id=q-app></div></body></html>