unisi 0.2.7__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
@@ -48,6 +49,12 @@ class ReceivedMessage(ArgObject):
48
49
  self.__dict__.update(kwargs)
49
50
  def __str__(self):
50
51
  return f'{self.block}/{self.element}->{self.event}({self.value})'
52
+ @property
53
+ def screen_type(self):
54
+ return self.block == 'root' and self.element is None
55
+ @property
56
+ def voice_type(self):
57
+ return self.block == 'voice' and self.element is None
51
58
 
52
59
  def toJson(obj):
53
60
  return jsonpickle.encode(obj,unpicklable = False)
@@ -58,6 +65,8 @@ def set_defaults(self, param_defaults : dict):
58
65
  setattr(self, param, value)
59
66
 
60
67
  def pretty4(name):
68
+ if name.startswith('_'):
69
+ name = name[1:]
61
70
  pretty_name = name.replace('_',' ')
62
71
  return pretty_name[0].upper() + pretty_name[1:]
63
72
 
@@ -147,6 +156,21 @@ def Answer(type, message, result):
147
156
  ms.message = message
148
157
  return ms
149
158
 
159
+ def delete_unit(units, name):
160
+ """Deletes a unit with the given name from a nested list of units.
161
+ Returns True if the unit was found and deleted, False otherwise.
162
+ """
163
+ for i in range(len(units)):
164
+ if isinstance(units[i], list | tuple):
165
+ if delete_unit(units[i], name):
166
+ if not units[i]: # if the sublist became empty after deletion
167
+ units.pop(i) # remove sublist also
168
+ return True
169
+ elif units[i].name == name:
170
+ units.pop(i)
171
+ return True
172
+ return False
173
+
150
174
 
151
175
 
152
176
 
unisi/containers.py CHANGED
@@ -1,5 +1,6 @@
1
+ # Copyright © 2024 UNISI Tech. All rights reserved.
1
2
  from .units import *
2
- from .common import pretty4, flatten
3
+ from .common import pretty4, flatten, delete_unit
3
4
  from numbers import Number
4
5
 
5
6
  class Block(Unit):
@@ -33,7 +34,7 @@ class Block(Unit):
33
34
  elif isinstance(elem.llm, dict):
34
35
  if elem.type != 'table':
35
36
  raise AttributeError(f'{elem.name} llm parameter is a dictionary only for tables, not for {elem.type}!')
36
- elem.__llm_dependencies__ = {fld: (deps if isinstance(deps, list | bool) else [deps]) for fld, deps in elem.llm.items()}
37
+ elem._llm_dependencies = {fld: (deps if isinstance(deps, list | bool) else [deps]) for fld, deps in elem.llm.items()}
37
38
  elem.llm = True
38
39
  continue
39
40
  else:
@@ -42,12 +43,18 @@ class Block(Unit):
42
43
  elem.llm = exactly
43
44
  for dependency in dependencies:
44
45
  dependency.add_changed_handler(elem.emit)
45
- elem.__llm_dependencies__ = dependencies
46
+ elem._llm_dependencies = dependencies
46
47
  else:
47
48
  elem.llm = None
48
49
  print(f'Empty dependency list for llm calculation for {elem.name} {elem.type}!')
49
-
50
- self.set_reactivity(Unishare.context_user())
50
+
51
+ user = Unishare.context_user()
52
+ if hasattr(self,'closable'):
53
+ def close(*_):
54
+ delete_unit(user.screen.blocks, self.name)
55
+ self.close = close
56
+
57
+ self.set_reactivity(user)
51
58
 
52
59
  def set_reactivity(self, user, override = False):
53
60
  if user:
@@ -88,26 +95,26 @@ class ParamBlock(Block):
88
95
 
89
96
  for param, val in params.items():
90
97
  pretty_name = pretty4(param)
91
- t = type(val)
92
- if t == str or t == int or t == float:
93
- el = Edit(pretty_name, val)
94
- elif t == bool:
95
- el = Switch(pretty_name, val)
96
- elif t == tuple or t == list:
97
- if len(val) != 2:
98
- raise ValueError('Composite value has to contain the current value and options value!')
99
- options = val[1]
100
- if not isinstance(options, list | tuple | dict):
101
- raise ValueError('Options value (the second parameter) has to be a list or tuple!')
102
- if len(options) == 3 and all(map(lambda e: isinstance(e, Number), options)):
103
- el = Range(pretty_name, val[0], options = options)
104
- elif isinstance(options, list | tuple):
105
- el = Select(pretty_name, val[0], options = options, type = 'select')
106
- else:
107
- el = Tree(pretty_name, val[0], options = options)
108
- else:
109
- raise ValueError(f'The {param} value {val} is not supported. Look at ParamBlock documentation!')
110
-
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
+
111
118
  self.name2elem[param] = el
112
119
 
113
120
  if cnt % row == 0:
@@ -129,9 +136,9 @@ class Dialog:
129
136
  self.icon = icon
130
137
  self.value = [[], *content] if content else []
131
138
 
132
- class Screen:
133
- def __init__(self, name, **kwargs):
134
- self.name = name
135
- self.__dict__.update(kwargs)
136
- 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'
137
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
@@ -77,11 +78,10 @@ def unit2image(unit):
77
78
  class Net(Graph):
78
79
  """Graph of Units"""
79
80
  replace4state = dict(nodes = '_nodes', edges = '_edges', value = '_value')
80
- def __init__(self, name, topology = Topology(), **kwargs):
81
- Unit.__init__(self, name, **kwargs)
82
- if not hasattr(self, 'value'):
83
- self.value = graph_default_value
81
+ def __init__(self, name, value = graph_default_value, topology = Topology(), **kwargs):
82
+ Unit.__init__(self, name, **kwargs)
84
83
  self.type = 'graph'
84
+ self.value = value
85
85
  self.topology = topology
86
86
  self._inside_converter = False
87
87
  changed_handler = getattr(self, 'changed', None)
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
@@ -199,7 +200,7 @@ class Table(Unit):
199
200
  tasks = []
200
201
  for index in self.selected_list:
201
202
  values = {field: value for field, value in zip(self.headers, self.rows[index]) if value}
202
- for fld, deps in self.__llm_dependencies__.items():
203
+ for fld, deps in self._llm_dependencies.items():
203
204
  if fld not in values:
204
205
  if deps is True:
205
206
  context = values
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"""
@@ -112,9 +140,9 @@ class Unit:
112
140
  async def emit(self, *_ ):
113
141
  """calcute value by system llm, can be used as a handler"""
114
142
  if Unishare.llm_model and (exactly := getattr(self, 'llm', None)) is not None:
115
- elems = [e.compact_view for e in self.__llm_dependencies__ if e.value != '' and e.value is not None]
143
+ elems = [e.compact_view for e in self._llm_dependencies if e.value != '' and e.value is not None]
116
144
  #exactly is requirment that all elements have to have valid value
117
- if not exactly or len(elems) == len(self.__llm_dependencies__):
145
+ if not exactly or len(elems) == len(self._llm_dependencies):
118
146
  context = ','.join(elems)
119
147
  self.value = await get_property(self.name, context, self.type, options = getattr(self, 'options', None))
120
148
  return self
@@ -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,9 +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 *
5
+ from .voicecom import VoiceCom
4
6
  from .containers import Dialog, Screen
5
7
  from .multimon import notify_monitor, logging_lock, run_external_process
6
- from .kdb import Database
7
8
  from .dbunits import dbshare, dbupdates
8
9
  import sys, asyncio, logging, importlib
9
10
 
@@ -17,6 +18,7 @@ class User:
17
18
  self.active_dialog = None
18
19
  self.last_message = None
19
20
  self.changed_units = set()
21
+ self.voice = None
20
22
 
21
23
  if share:
22
24
  self.screens = share.screens
@@ -53,7 +55,7 @@ class User:
53
55
  if user is not self and screen is user.screen_module])
54
56
 
55
57
  async def reflect(self, message, result):
56
- if self.reflections and not is_screen_switch(message):
58
+ if self.reflections and not message.screen_type:
57
59
  if result:
58
60
  await self.broadcast(result)
59
61
  if message:
@@ -77,7 +79,7 @@ class User:
77
79
  module.user = self
78
80
 
79
81
  spec.loader.exec_module(module)
80
- screen = Screen(getattr(module, 'name', ''))
82
+ screen = Screen(getattr(module, 'name', ''))
81
83
  #set system vars
82
84
  for var, val in screen.defaults.items():
83
85
  setattr(screen, var, getattr(module, var, val))
@@ -87,22 +89,23 @@ class User:
87
89
  screen.toolbar += User.toolbar
88
90
  else:
89
91
  screen.toolbar = User.toolbar
90
- module.screen = screen
92
+ screen.set_reactivity(self)
93
+ module.screen = screen#ChangedProxy(screen, screen)
91
94
  return module
92
95
 
93
96
  async def delete(self):
94
97
  uss = Unishare.sessions
95
98
  if uss and uss.get(self.session):
96
- del uss[self.session]
97
-
99
+ del uss[self.session]
98
100
  if self.reflections: #reflections is common array
99
101
  if len(self.reflections) == 2:
100
102
  self.reflections.clear() #1 element in user.reflections has no sense
101
103
  else:
102
104
  self.reflections.remove(self)
103
-
104
105
  if notify_monitor:
105
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')
106
109
 
107
110
  def set_clean(self):
108
111
  #remove user modules from sys
@@ -143,7 +146,7 @@ class User:
143
146
  def screen(self):
144
147
  return self.screen_module.screen
145
148
 
146
- def set_screen(self,name):
149
+ def set_screen(self,name):
147
150
  return asyncio.run(self.process(ArgObject(block = 'root', element = None, value = name)))
148
151
 
149
152
  async def result4message(self, message):
@@ -197,6 +200,8 @@ class User:
197
200
  else:
198
201
  for bl in flatten(self.blocks):
199
202
  if bl.name == blname:
203
+ if not elname:
204
+ return bl
200
205
  for c in flatten(bl.value):
201
206
  if c.name == elname:
202
207
  return c
@@ -213,9 +218,10 @@ class User:
213
218
  return ['toolbar', e.name]
214
219
 
215
220
  def prepare_result(self, raw):
216
- if raw is True or raw == Redesign:
217
- raw = self.screen
218
- raw.reload = raw == Redesign
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
219
225
  else:
220
226
  match raw:
221
227
  case None:
@@ -240,12 +246,15 @@ class User:
240
246
 
241
247
  async def process(self, message):
242
248
  screen_change_message = message.screen and self.screen.name != message.screen
243
- if screen_change_message or is_screen_switch(message):
249
+ if screen_change_message or message.screen_type:
244
250
  for s in self.screens:
245
251
  if s.name == message.value:
246
- self.screen_module = s
252
+ self.screen_module = s
247
253
  if screen_change_message:
248
254
  break
255
+ if self.voice:
256
+ self.voice.set_screen(s)
257
+ self.voice.start()
249
258
  if getattr(s.screen,'prepare', None):
250
259
  s.screen.prepare()
251
260
  return True
@@ -253,14 +262,23 @@ class User:
253
262
  error = f'Unknown screen name: {message.value}'
254
263
  self.log(error)
255
264
  return Error(error)
256
-
257
- elem = self.find_element(message)
258
- if elem:
259
- return await self.process_element(elem, message)
260
-
261
- error = f'Element {message.block}/{message.element} does not exist!'
262
- self.log(error)
263
- return Error(error)
265
+ elif message.voice_type:
266
+ if not self.voice:
267
+ self.voice = VoiceCom(self)
268
+ if message.event == 'listen':
269
+ if message.value:
270
+ self.voice.start()
271
+ else:
272
+ self.voice.stop()
273
+ else:
274
+ self.voice.process_word(message.value)
275
+ else:
276
+ elem = self.find_element(message)
277
+ if elem:
278
+ return await self.process_element(elem, message)
279
+ error = f'Element {message.block}/{message.element} does not exist!'
280
+ self.log(error)
281
+ return Error(error)
264
282
 
265
283
  async def process_element(self, elem, message):
266
284
  event = message.event
@@ -340,62 +358,3 @@ class User:
340
358
  sync_calls.append(user.send(update4user))
341
359
  dbupdates.clear()
342
360
  await asyncio.gather(*sync_calls)
343
-
344
- def context_user():
345
- return context_object(User)
346
-
347
- def context_screen():
348
- user = context_user()
349
- return user.screen if user else None
350
-
351
- def message_logger(str, type = 'error'):
352
- user = context_user()
353
- user.log(str, type)
354
-
355
- Unishare.context_user = context_user
356
- Unishare.message_logger = message_logger
357
- User.type = User
358
-
359
- if config.db_dir:
360
- Unishare.db = Database(config.db_dir, message_logger)
361
-
362
- def make_user(request):
363
- session = f'{request.remote}-{User.count}'
364
- if requested_connect := request.query_string if config.share else None:
365
- user = Unishare.sessions.get(requested_connect, None)
366
- if not user:
367
- error = f'Session id "{requested_connect}" is unknown. Connection refused!'
368
- with logging_lock:
369
- logging.error(error)
370
- return None, Error(error)
371
- user = User.type(session, user)
372
- ok = user.screens
373
- elif config.mirror and User.count:
374
- user = User.type(session, User.last_user)
375
- ok = user.screens
376
- elif not User.count:
377
- user = User.last_user
378
- user.session = session
379
- user.monitor(session)
380
- ok = True
381
- else:
382
- user = User.type(session)
383
- ok = user.load()
384
-
385
- User.count += 1
386
- Unishare.sessions[session] = user
387
- return user, ok
388
-
389
- def handle(elem, event):
390
- def h(fn):
391
- key = elem, event
392
- handler_map = User.last_user.__handlers__
393
- func = handler_map.get(key, None)
394
- if func:
395
- handler_map[key] = compose_handlers(func, fn)
396
- else:
397
- handler_map[key] = fn
398
- return fn
399
- return h
400
-
401
- 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,16 +53,14 @@ 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:
58
61
  print('froze_time in config.py can not be 0!')
59
62
  config.froze_time = None
60
63
 
61
- def is_screen_switch(message):
62
- return message and message.block == 'root' and message.element is None
63
-
64
64
  def filename2url(fn):
65
65
  if fn[0] == '/' or fn[1] == ':': #if full path
66
66
  fn = fn[len(app_dir):]