unisi 0.2.8__py3-none-any.whl → 0.2.9__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/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from .utils import *
2
2
  from .units import *
3
- from .users import User, handle, context_user, context_screen
4
- from .server import start
3
+ from .users import User
4
+ from .server import start, handle, context_user, context_screen
5
5
  from .tables import *
6
6
  from .containers import *
7
7
  from .proxy import *
unisi/autotest.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  import config, os, json, asyncio
2
3
  from .utils import *
3
4
  from .units import *
unisi/common.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  import jsonpickle, inspect, asyncio
2
3
 
3
4
  UpdateScreen = True
@@ -64,6 +65,8 @@ def set_defaults(self, param_defaults : dict):
64
65
  setattr(self, param, value)
65
66
 
66
67
  def pretty4(name):
68
+ if name.startswith('_'):
69
+ name = name[1:]
67
70
  pretty_name = name.replace('_',' ')
68
71
  return pretty_name[0].upper() + pretty_name[1:]
69
72
 
unisi/containers.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .units import *
2
3
  from .common import pretty4, flatten, delete_unit
3
4
  from numbers import Number
@@ -50,8 +51,7 @@ class Block(Unit):
50
51
  user = Unishare.context_user()
51
52
  if hasattr(self,'closable'):
52
53
  def close(*_):
53
- delete_unit(user.screen.blocks, self.name)
54
- return Redesign
54
+ delete_unit(user.screen.blocks, self.name)
55
55
  self.close = close
56
56
 
57
57
  self.set_reactivity(user)
@@ -95,26 +95,26 @@ class ParamBlock(Block):
95
95
 
96
96
  for param, val in params.items():
97
97
  pretty_name = pretty4(param)
98
- t = type(val)
99
- if t == str or t == int or t == float:
100
- el = Edit(pretty_name, val)
101
- elif t == bool:
102
- el = Switch(pretty_name, val)
103
- elif t == tuple or t == list:
104
- if len(val) != 2:
105
- raise ValueError('Composite value has to contain the current value and options value!')
106
- options = val[1]
107
- if not isinstance(options, list | tuple | dict):
108
- raise ValueError('Options value (the second parameter) has to be a list or tuple!')
109
- if len(options) == 3 and all(map(lambda e: isinstance(e, Number), options)):
110
- el = Range(pretty_name, val[0], options = options)
111
- elif isinstance(options, list | tuple):
112
- el = Select(pretty_name, val[0], options = options, type = 'select')
113
- else:
114
- el = Tree(pretty_name, val[0], options = options)
115
- else:
116
- raise ValueError(f'The {param} value {val} is not supported. Look at ParamBlock documentation!')
117
-
98
+ match val:
99
+ case True | False:
100
+ el = Switch(pretty_name, val)
101
+ case str() | int() | float():
102
+ el = Edit(pretty_name, val)
103
+ case tuple() | list():
104
+ if len(val) != 2:
105
+ raise ValueError('Composite value has to contain the current value and options value!')
106
+ options = val[1]
107
+ if not isinstance(options, list | tuple | dict):
108
+ raise ValueError('Options value (the second parameter) has to be a list or tuple!')
109
+ if len(options) == 3 and all(map(lambda e: isinstance(e, Number), options)):
110
+ el = Range(pretty_name, val[0], options = options)
111
+ elif isinstance(options, list | tuple):
112
+ el = Select(pretty_name, val[0], options = options, type = 'select')
113
+ else:
114
+ el = Tree(pretty_name, val[0], options = options)
115
+ case _:
116
+ raise ValueError(f'The {param} value {val} is not supported. Look at ParamBlock documentation!')
117
+
118
118
  self.name2elem[param] = el
119
119
 
120
120
  if cnt % row == 0:
@@ -136,9 +136,9 @@ class Dialog:
136
136
  self.icon = icon
137
137
  self.value = [[], *content] if content else []
138
138
 
139
- class Screen:
140
- def __init__(self, name, **kwargs):
141
- self.name = name
142
- self.__dict__.update(kwargs)
143
- self.type = 'screen'
139
+ class Screen(Unit):
140
+ def __init__(self, name):
141
+ self._mark_changed = None
142
+ self.name = name
143
+ self.type = 'screen'
144
144
 
unisi/dbunits.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .common import Unishare
2
3
  from collections import defaultdict
3
4
 
unisi/graphs.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .units import *
2
3
  from .tables import Table
3
4
  from .containers import Block
unisi/kdb.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  import kuzu, shutil, os, re
2
3
  from datetime import date, datetime
3
4
  from cymple import QueryBuilder as qb
unisi/llmrag.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .common import Unishare
2
3
  from langchain_groq import ChatGroq
3
4
  from langchain_openai import ChatOpenAI
unisi/multimon.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  import multiprocessing, time, asyncio, logging, inspect
2
3
  from .utils import start_logging
3
4
  from config import froze_time, monitor_tick, profile, pool
unisi/proxy.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from websocket import create_connection
2
3
  from enum import IntFlag
3
4
  import json, requests, os
unisi/reloader.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .autotest import config
2
3
 
3
4
  empty_app = {
unisi/server.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from aiohttp import web, WSMsgType
2
3
  from .users import *
3
4
  from pathlib import Path
@@ -6,9 +7,69 @@ from .autotest import recorder, run_tests
6
7
  from .common import *
7
8
  from.llmrag import setup_llmrag
8
9
  from .dbunits import dbupdates
10
+ from .kdb import Database
9
11
  from config import port, upload_dir
10
12
  import traceback, json
11
13
 
14
+ def context_user():
15
+ return context_object(User)
16
+
17
+ def context_screen():
18
+ user = context_user()
19
+ return user.screen if user else None
20
+
21
+ def message_logger(str, type = 'error'):
22
+ user = context_user()
23
+ user.log(str, type)
24
+
25
+ Unishare.context_user = context_user
26
+ Unishare.message_logger = message_logger
27
+ User.type = User
28
+
29
+ if config.db_dir:
30
+ Unishare.db = Database(config.db_dir, message_logger)
31
+
32
+ def make_user(request):
33
+ session = f'{request.remote}-{User.count}'
34
+ if requested_connect := request.query_string if config.share else None:
35
+ user = Unishare.sessions.get(requested_connect, None)
36
+ if not user:
37
+ error = f'Session id "{requested_connect}" is unknown. Connection refused!'
38
+ with logging_lock:
39
+ logging.error(error)
40
+ return None, Error(error)
41
+ user = User.type(session, user)
42
+ ok = user.screens
43
+ elif config.mirror and User.count:
44
+ user = User.type(session, User.last_user)
45
+ ok = user.screens
46
+ elif not User.count:
47
+ user = User.last_user
48
+ user.session = session
49
+ user.monitor(session)
50
+ ok = True
51
+ else:
52
+ user = User.type(session)
53
+ ok = user.load()
54
+
55
+ User.count += 1
56
+ Unishare.sessions[session] = user
57
+ return user, ok
58
+
59
+ def handle(elem, event):
60
+ def h(fn):
61
+ key = elem, event
62
+ handler_map = User.last_user.__handlers__
63
+ func = handler_map.get(key, None)
64
+ if func:
65
+ handler_map[key] = compose_handlers(func, fn)
66
+ else:
67
+ handler_map[key] = fn
68
+ return fn
69
+ return h
70
+
71
+ Unishare.handle = handle
72
+
12
73
  async def post_handler(request):
13
74
  reader = await request.multipart()
14
75
  field = await reader.next()
unisi/tables.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .units import Unit
2
3
  from .common import *
3
4
  from .dbunits import Dblist, dbupdates
unisi/units.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .common import *
2
3
  from .llmrag import get_property
3
4
 
@@ -22,13 +23,26 @@ class ChangedProxy:
22
23
  elif not callable(value) and not isinstance(value, atomics):
23
24
  return ChangedProxy(value, self)
24
25
  return value
26
+
27
+ def __setattr__(self, name, value):
28
+ if name in ('_obj', '_unit'):
29
+ super().__setattr__(name, value)
30
+ else:
31
+ self._obj.__setattr__(name, value)
32
+ self._unit._mark_changed()
25
33
 
26
34
  def __setitem__(self, key, value):
27
35
  self._obj[key] = value
28
36
  self._unit._mark_changed ()
29
37
 
30
38
  def __getitem__(self, key):
31
- return self._obj[key]
39
+ value = self._obj[key]
40
+ if not callable(value) and not isinstance(value, atomics):
41
+ value = ChangedProxy(value, self._unit)
42
+ return value
43
+
44
+ def __eq__(self, other):
45
+ return self._obj.__eq__(other._obj) if isinstance(other, ChangedProxy) else self._obj.__eq__(other)
32
46
 
33
47
  def __delitem__(self, key):
34
48
  del self._obj[key]
@@ -42,6 +56,16 @@ class ChangedProxy:
42
56
  return len(self._obj)
43
57
  except TypeError:
44
58
  return 0
59
+
60
+ def __hash__(self):
61
+ return hash(self._obj)
62
+
63
+ def __iadd__(self, other):
64
+ if isinstance(self._obj, list):
65
+ self.extend(other)
66
+ return self # Important: __iadd__ must return self
67
+
68
+ raise TypeError(f"Unsupported operand type for += with '{type(self._obj).__name__}'")
45
69
 
46
70
  def __getstate__(self):
47
71
  return self._obj
@@ -81,9 +105,7 @@ class Unit:
81
105
 
82
106
  def __setattr__(self, name, value):
83
107
  #it is correct condition order
84
- if name != "_mark_changed" and self._mark_changed:
85
- if name != "__dict__" and not isinstance(value, atomics) and not callable(value):
86
- value = ChangedProxy(value, self)
108
+ if name[0] != "_" and self._mark_changed:
87
109
  self._mark_changed(name, value)
88
110
  super().__setattr__(name, value)
89
111
 
@@ -103,7 +125,13 @@ class Unit:
103
125
  def delattr(self, attr):
104
126
  if hasattr(self, attr):
105
127
  delattr(self, attr)
106
-
128
+
129
+ def __eq__(self, other):
130
+ return super().__eq__(other._obj) if isinstance(other, ChangedProxy) else super().__eq__(other)
131
+
132
+ def __hash__(self):
133
+ return super().__hash__()
134
+
107
135
  @property
108
136
  def compact_view(self) -> str:
109
137
  """reduce for external (llm) using if required"""
@@ -153,6 +181,7 @@ def smart_complete(lst, min_input_length = 0, max_output_length = 20):
153
181
  class Edit(Unit):
154
182
  def __init__(self, name, *args, **kwargs):
155
183
  super().__init__(name, *args, **kwargs)
184
+ self.x = -1
156
185
  has_value = hasattr(self,'value')
157
186
  if 'type' not in kwargs:
158
187
  if has_value:
@@ -263,6 +292,7 @@ class Tree(Unit):
263
292
  class TextArea(Unit):
264
293
  def __init__(self,name, *args, **kwargs):
265
294
  super().__init__(name, *args, **kwargs)
295
+ self.x = -1
266
296
  self.type = 'text'
267
297
 
268
298
 
unisi/users.py CHANGED
@@ -1,10 +1,10 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .utils import *
2
3
  from .units import *
3
4
  from .common import *
4
5
  from .voicecom import VoiceCom
5
6
  from .containers import Dialog, Screen
6
7
  from .multimon import notify_monitor, logging_lock, run_external_process
7
- from .kdb import Database
8
8
  from .dbunits import dbshare, dbupdates
9
9
  import sys, asyncio, logging, importlib
10
10
 
@@ -79,7 +79,7 @@ class User:
79
79
  module.user = self
80
80
 
81
81
  spec.loader.exec_module(module)
82
- screen = Screen(getattr(module, 'name', ''))
82
+ screen = Screen(getattr(module, 'name', ''))
83
83
  #set system vars
84
84
  for var, val in screen.defaults.items():
85
85
  setattr(screen, var, getattr(module, var, val))
@@ -89,22 +89,23 @@ class User:
89
89
  screen.toolbar += User.toolbar
90
90
  else:
91
91
  screen.toolbar = User.toolbar
92
- module.screen = screen
92
+ screen.set_reactivity(self)
93
+ module.screen = screen#ChangedProxy(screen, screen)
93
94
  return module
94
95
 
95
96
  async def delete(self):
96
97
  uss = Unishare.sessions
97
98
  if uss and uss.get(self.session):
98
- del uss[self.session]
99
-
99
+ del uss[self.session]
100
100
  if self.reflections: #reflections is common array
101
101
  if len(self.reflections) == 2:
102
102
  self.reflections.clear() #1 element in user.reflections has no sense
103
103
  else:
104
104
  self.reflections.remove(self)
105
-
106
105
  if notify_monitor:
107
106
  await notify_monitor('-', self.session, self.last_message)
107
+ if config.share:
108
+ self.log(f'User is disconnected, session: {self.session}', type = 'info')
108
109
 
109
110
  def set_clean(self):
110
111
  #remove user modules from sys
@@ -145,7 +146,7 @@ class User:
145
146
  def screen(self):
146
147
  return self.screen_module.screen
147
148
 
148
- def set_screen(self,name):
149
+ def set_screen(self,name):
149
150
  return asyncio.run(self.process(ArgObject(block = 'root', element = None, value = name)))
150
151
 
151
152
  async def result4message(self, message):
@@ -217,10 +218,10 @@ class User:
217
218
  return ['toolbar', e.name]
218
219
 
219
220
  def prepare_result(self, raw):
220
- if raw is True or raw == Redesign:
221
- out = self.screen
222
- out.reload = raw == Redesign
223
- raw = out
221
+ reload_screen = self.screen in self.changed_units
222
+ if reload_screen or raw is True or raw == Redesign:
223
+ self.screen.reload = reload_screen or raw == Redesign
224
+ raw = self.screen
224
225
  else:
225
226
  match raw:
226
227
  case None:
@@ -261,17 +262,16 @@ class User:
261
262
  error = f'Unknown screen name: {message.value}'
262
263
  self.log(error)
263
264
  return Error(error)
264
- elif message.voice_type:
265
- created = False
265
+ elif message.voice_type:
266
266
  if not self.voice:
267
- self.voice = VoiceCom(self)
268
- created = True
267
+ self.voice = VoiceCom(self)
269
268
  if message.event == 'listen':
270
- return self.voice.start() if message.value else self.voice.stop()
269
+ if message.value:
270
+ self.voice.start()
271
+ else:
272
+ self.voice.stop()
271
273
  else:
272
- self.voice.input_word(message.value)
273
- if created:
274
- return Redesign
274
+ self.voice.process_word(message.value)
275
275
  else:
276
276
  elem = self.find_element(message)
277
277
  if elem:
@@ -358,62 +358,3 @@ class User:
358
358
  sync_calls.append(user.send(update4user))
359
359
  dbupdates.clear()
360
360
  await asyncio.gather(*sync_calls)
361
-
362
- def context_user():
363
- return context_object(User)
364
-
365
- def context_screen():
366
- user = context_user()
367
- return user.screen if user else None
368
-
369
- def message_logger(str, type = 'error'):
370
- user = context_user()
371
- user.log(str, type)
372
-
373
- Unishare.context_user = context_user
374
- Unishare.message_logger = message_logger
375
- User.type = User
376
-
377
- if config.db_dir:
378
- Unishare.db = Database(config.db_dir, message_logger)
379
-
380
- def make_user(request):
381
- session = f'{request.remote}-{User.count}'
382
- if requested_connect := request.query_string if config.share else None:
383
- user = Unishare.sessions.get(requested_connect, None)
384
- if not user:
385
- error = f'Session id "{requested_connect}" is unknown. Connection refused!'
386
- with logging_lock:
387
- logging.error(error)
388
- return None, Error(error)
389
- user = User.type(session, user)
390
- ok = user.screens
391
- elif config.mirror and User.count:
392
- user = User.type(session, User.last_user)
393
- ok = user.screens
394
- elif not User.count:
395
- user = User.last_user
396
- user.session = session
397
- user.monitor(session)
398
- ok = True
399
- else:
400
- user = User.type(session)
401
- ok = user.load()
402
-
403
- User.count += 1
404
- Unishare.sessions[session] = user
405
- return user, ok
406
-
407
- def handle(elem, event):
408
- def h(fn):
409
- key = elem, event
410
- handler_map = User.last_user.__handlers__
411
- func = handler_map.get(key, None)
412
- if func:
413
- handler_map[key] = compose_handlers(func, fn)
414
- else:
415
- handler_map[key] = fn
416
- return fn
417
- return h
418
-
419
- Unishare.handle = handle
unisi/utils.py CHANGED
@@ -1,3 +1,4 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  import os, platform, requests, logging
2
3
  from .common import set_defaults
3
4
  from .containers import Screen
@@ -41,7 +42,8 @@ set_defaults(config, dict(
41
42
  froze_time= None,
42
43
  monitor_tick = 0.005,
43
44
  pool = None,
44
- db_dir = None
45
+ db_dir = None,
46
+ lang = 'en-US'
45
47
  ))
46
48
 
47
49
  Screen.defaults = dict(
@@ -51,7 +53,8 @@ Screen.defaults = dict(
51
53
  header = config.appname,
52
54
  toolbar = [],
53
55
  order = 0,
54
- reload = config.hot_reload
56
+ reload = config.hot_reload,
57
+ lang = config.lang
55
58
  )
56
59
 
57
60
  if config.froze_time == 0: