kongalib 1.12.0__cp310-cp310-win_amd64.whl → 2.0.0.post1__cp310-cp310-win_amd64.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.
Potentially problematic release.
This version of kongalib might be problematic. Click here for more details.
- _kongalib.cp310-win_amd64.pdb +0 -0
- _kongalib.cp310-win_amd64.pyd +0 -0
- kongalib/__init__.py +22 -36
- kongalib/async_client.py +63 -65
- kongalib/client.py +51 -20
- kongalib/constants.py +110 -1842
- kongalib/data_dictionary.py +3 -12
- kongalib/db.py +7 -8
- kongalib/expression.py +29 -24
- kongalib/json.py +1 -2
- kongalib/scripting.py +54 -31
- {kongalib-1.12.0.dist-info → kongalib-2.0.0.post1.dist-info}/METADATA +29 -26
- kongalib-2.0.0.post1.dist-info/RECORD +21 -0
- {kongalib-1.12.0.dist-info → kongalib-2.0.0.post1.dist-info}/WHEEL +1 -1
- {kongalib-1.12.0.dist-info → kongalib-2.0.0.post1.dist-info}/top_level.txt +1 -0
- kongaui.py +4 -55
- kongautil.py +17 -13
- kongalib/_kongalib.cp310-win_amd64.pdb +0 -0
- kongalib/_kongalib.cp310-win_amd64.pyd +0 -0
- kongalib/compat.py +0 -492
- kongalib/parsetab.py +0 -41
- kongalib-1.12.0.dist-info/RECORD +0 -23
- {kongalib-1.12.0.dist-info → kongalib-2.0.0.post1.dist-info/licenses}/LICENSE +0 -0
- {kongalib-1.12.0.dist-info → kongalib-2.0.0.post1.dist-info}/zip-safe +0 -0
kongalib/data_dictionary.py
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
|
|
16
16
|
from kongalib import Error, ErrorList
|
|
17
17
|
from .constants import *
|
|
18
|
-
from .compat import *
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
TYPE_TINYINT = 1 #: Tipo di campo SQL TINYINT; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``int``.
|
|
@@ -24,16 +23,7 @@ TYPE_INT = 3 #: Tipo di campo SQL INT; i valori ottenuti dalla :meth:`~ko
|
|
|
24
23
|
TYPE_BIGINT = 4 #: Tipo di campo SQL BIGINT; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``int``.
|
|
25
24
|
TYPE_FLOAT = 5 #: Tipo di campo SQL FLOAT; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``float``.
|
|
26
25
|
TYPE_DOUBLE = 6 #: Tipo di campo SQL DOUBLE; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``float``.
|
|
27
|
-
TYPE_DECIMAL = 7
|
|
28
|
-
"""Tipo di campo SQL DECIMAL; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo :class:`kongalib.Decimal`.
|
|
29
|
-
|
|
30
|
-
.. warning:: Konga Server traduce automaticamente questo tipo di dato in BIGINT sul database SQL, e salva i valori decimali come se
|
|
31
|
-
fossero interi moltiplicati per 1000000. Questo consente una precisione fino a 6 cifre decimali, e permette a Konga Server di operare anche
|
|
32
|
-
con driver SQL che non supportano nativamente il tipo dato DECIMAL (come SQLite). La traduzione è completamente trasparente per kongalib, in
|
|
33
|
-
quanto i metodi della classe :class:`kongalib.Client` ricevono e restituiscono oggetti di clase :class:`kongalib.Decimal` per gestire
|
|
34
|
-
i decimali.
|
|
35
|
-
"""
|
|
36
|
-
|
|
26
|
+
TYPE_DECIMAL = 7 #: Tipo di campo SQL DECIMAL; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo :class:`kongalib.Decimal`.
|
|
37
27
|
TYPE_DATE = 8 #: Tipo di campo SQL DATE; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``datetime.date``.
|
|
38
28
|
TYPE_TIME = 9 #: Tipo di campo SQL TIME; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``datetime.time``.
|
|
39
29
|
TYPE_TIMESTAMP = 10 #: Tipo di campo SQL TIMESTAMP; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``datetime.datetime``.
|
|
@@ -46,6 +36,7 @@ TYPE_LONGTEXT = 16 #: Tipo di campo SQL LONGTEXT; i valori ottenuti dalla :
|
|
|
46
36
|
TYPE_TINYBLOB = 17 #: Tipo di campo SQL TINYBLOB; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``bytes``.
|
|
47
37
|
TYPE_BLOB = 18 #: Tipo di campo SQL BLOB; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``bytes``.
|
|
48
38
|
TYPE_LONGBLOB = 19 #: Tipo di campo SQL LONGBLOB; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``bytes``.
|
|
39
|
+
TYPE_JSON = 20 #: Tipo di campo SQL JSON; i valori ottenuti dalla :meth:`~kongalib.Client.select_data` saranno di tipo ``unicode``.
|
|
49
40
|
|
|
50
41
|
|
|
51
42
|
TABLE_HAS_IMAGES = 0x1 #: Flag informativo di tabella del data dictionary. Se specificato, i record della tabella possono avere immagini collegate.
|
|
@@ -89,7 +80,7 @@ class DataDictionary(object):
|
|
|
89
80
|
|
|
90
81
|
def get_label(self, key):
|
|
91
82
|
"""Ottiene la descrizione della chiave *key* sotto forma di ``dict`` con le traduzioni corrispondenti a ciascuna lingua."""
|
|
92
|
-
if isinstance(key,
|
|
83
|
+
if isinstance(key, str):
|
|
93
84
|
return self.__data[key][1]
|
|
94
85
|
for value, label in self.__data.values():
|
|
95
86
|
if value == key:
|
kongalib/db.py
CHANGED
|
@@ -18,7 +18,6 @@ import datetime
|
|
|
18
18
|
|
|
19
19
|
from kongalib import Client, Decimal, Error as _Error, ErrorList
|
|
20
20
|
from .constants import *
|
|
21
|
-
from .compat import *
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
apilevel = "2.0" #: Versione delle API, come da specifica
|
|
@@ -142,11 +141,11 @@ class Cursor(object):
|
|
|
142
141
|
self.__description = []
|
|
143
142
|
row = self.__result[0]
|
|
144
143
|
for field, data in zip(fields, row):
|
|
145
|
-
if isinstance(data,
|
|
144
|
+
if isinstance(data, (int, float, Decimal)):
|
|
146
145
|
t = NUMBER
|
|
147
146
|
elif isinstance(data, (datetime.date, datetime.datetime)):
|
|
148
147
|
t = DATETIME
|
|
149
|
-
elif isinstance(data,
|
|
148
|
+
elif isinstance(data, str):
|
|
150
149
|
t = STRING
|
|
151
150
|
else:
|
|
152
151
|
t = BINARY
|
|
@@ -251,14 +250,14 @@ def TimeFromTicks(ticks):
|
|
|
251
250
|
def TimestampFromTicks(ticks):
|
|
252
251
|
return Timestamp(*time.localtime(ticks)[:6])
|
|
253
252
|
|
|
254
|
-
def connect(host, port=0, driver=None, database=None, user=None, password=None):
|
|
255
|
-
"""Esegue una connessione al server Konga identificato da *host* e *port*,
|
|
256
|
-
ed infine si autentica usando *user* e *password*. Restituisce un oggetto :class:`Connection`; da questo
|
|
257
|
-
:class:`Cursor` che permette di eseguire query SQL sul database aperto sulla connessione.
|
|
253
|
+
def connect(host, port=0, driver=None, database=None, user=None, password=None, tenant_key=None):
|
|
254
|
+
"""Esegue una connessione al server Konga identificato da *host* e *port*, usando l'eventuale chiave tenant *tenant_key*, apre *database*
|
|
255
|
+
usando il *driver* specificato, ed infine si autentica usando *user* e *password*. Restituisce un oggetto :class:`Connection`; da questo
|
|
256
|
+
è possibile ottenere un oggetto :class:`Cursor` che permette di eseguire query SQL sul database aperto sulla connessione.
|
|
258
257
|
"""
|
|
259
258
|
conn = Connection()
|
|
260
259
|
try:
|
|
261
|
-
conn.connect({ 'host': host, 'port': port })
|
|
260
|
+
conn.connect({ 'host': host, 'port': port }, options={ 'tenant_key': tenant_key })
|
|
262
261
|
conn.open_database(driver, database)
|
|
263
262
|
conn.authenticate(user, password)
|
|
264
263
|
except _Error as e:
|
kongalib/expression.py
CHANGED
|
@@ -20,8 +20,9 @@ import re
|
|
|
20
20
|
import io
|
|
21
21
|
import tempfile
|
|
22
22
|
import collections
|
|
23
|
+
from xml.etree import ElementTree as ET
|
|
23
24
|
|
|
24
|
-
from
|
|
25
|
+
from kongalib import ensure_text
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
|
|
@@ -61,7 +62,9 @@ class LRUCache(object):
|
|
|
61
62
|
|
|
62
63
|
def __setitem__(self, key, value):
|
|
63
64
|
try:
|
|
64
|
-
self.cache.pop(key)
|
|
65
|
+
old_value = self.cache.pop(key)
|
|
66
|
+
if (value is not old_value) and (self.destructor is not None):
|
|
67
|
+
self.destructor(key, old_value)
|
|
65
68
|
except KeyError:
|
|
66
69
|
if len(self.cache) >= self.capacity:
|
|
67
70
|
item = self.cache.popitem(last=False)
|
|
@@ -200,6 +203,10 @@ def parse(sql):
|
|
|
200
203
|
def p_expression_binop(p):
|
|
201
204
|
'expression : ID OPERAND VALUE'
|
|
202
205
|
p[0] = Operand(p[1], p[2], p[3])
|
|
206
|
+
|
|
207
|
+
def p_expression_valueop(p):
|
|
208
|
+
'expression : VALUE OPERAND VALUE'
|
|
209
|
+
p[0] = Operand(p[1], p[2], p[3], _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE)
|
|
203
210
|
|
|
204
211
|
def p_expression_func_fieldop(p):
|
|
205
212
|
'expression : function OPERAND ID'
|
|
@@ -242,6 +249,15 @@ def parse(sql):
|
|
|
242
249
|
node = node[1]
|
|
243
250
|
p[0] = OperandIN(p[1], values)
|
|
244
251
|
|
|
252
|
+
def p_expression_not_in(p):
|
|
253
|
+
'expression : ID NOT IN LPAREN valueslist RPAREN'
|
|
254
|
+
values = []
|
|
255
|
+
node = p[5]
|
|
256
|
+
while node is not None:
|
|
257
|
+
values.append(node[0])
|
|
258
|
+
node = node[1]
|
|
259
|
+
p[0] = OperandNotIN(p[1], values)
|
|
260
|
+
|
|
245
261
|
def p_function(p):
|
|
246
262
|
'function : ID LPAREN ID RPAREN'
|
|
247
263
|
p[0] = '%s(%s)' % (p[1], p[3])
|
|
@@ -355,7 +371,7 @@ class Operand(_HasLogic):
|
|
|
355
371
|
def __hash__(self):
|
|
356
372
|
return hash(str(self))
|
|
357
373
|
|
|
358
|
-
def
|
|
374
|
+
def __str__(self):
|
|
359
375
|
if self.value is None:
|
|
360
376
|
value = 'NULL'
|
|
361
377
|
elif re.match(r'^(\-)?[0-9]+$', self.value):
|
|
@@ -370,12 +386,6 @@ class Operand(_HasLogic):
|
|
|
370
386
|
value = "'%s'" % self.value.replace("'", "''")
|
|
371
387
|
return (u'%s %s %s' % (ensure_text(self.column), ensure_text(self.operator), ensure_text(value)))
|
|
372
388
|
|
|
373
|
-
def __str__(self):
|
|
374
|
-
if PY3:
|
|
375
|
-
return self.__unicode__()
|
|
376
|
-
else:
|
|
377
|
-
return self.__unicode__().encode('utf-8')
|
|
378
|
-
|
|
379
389
|
def __repr__(self):
|
|
380
390
|
return str(self)
|
|
381
391
|
|
|
@@ -508,7 +518,7 @@ class OperandIsNotNull(Operand):
|
|
|
508
518
|
|
|
509
519
|
class OperandIN(OperandNE):
|
|
510
520
|
def __init__(self, column, value):
|
|
511
|
-
if not isinstance(value,
|
|
521
|
+
if not isinstance(value, str):
|
|
512
522
|
value = u"('%s')" % (u"', '".join([ ensure_text(x).replace("'", "''") for x in value]))
|
|
513
523
|
Operand.__init__(self, column, 'IN', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE)
|
|
514
524
|
|
|
@@ -516,7 +526,7 @@ class OperandIN(OperandNE):
|
|
|
516
526
|
|
|
517
527
|
class OperandNotIN(OperandNE):
|
|
518
528
|
def __init__(self, column, value):
|
|
519
|
-
if not isinstance(value,
|
|
529
|
+
if not isinstance(value, str):
|
|
520
530
|
value = u"('%s')" % (u"', '".join([ ensure_text(x).replace("'", "''") for x in value]))
|
|
521
531
|
Operand.__init__(self, column, 'NOT IN', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE)
|
|
522
532
|
|
|
@@ -583,6 +593,7 @@ class Expression(_HasLogic):
|
|
|
583
593
|
e.logic_op = self.logic_op
|
|
584
594
|
for child in self.children:
|
|
585
595
|
e.children.append(child.copy())
|
|
596
|
+
child.parent = e
|
|
586
597
|
return e
|
|
587
598
|
|
|
588
599
|
def append(self, operand, logic_op):
|
|
@@ -612,8 +623,8 @@ class Expression(_HasLogic):
|
|
|
612
623
|
if self.children[index + 1].logic_op & _HasLogic.LOGIC_NOT:
|
|
613
624
|
op += ' NOT'
|
|
614
625
|
else:
|
|
615
|
-
if (len(self.children) == 1) and (self.children[-1].logic_op & _HasLogic.LOGIC_NOT):
|
|
616
|
-
|
|
626
|
+
# if (len(self.children) == 1) and (self.children[-1].logic_op & _HasLogic.LOGIC_NOT):
|
|
627
|
+
# l[-1].append(True)
|
|
617
628
|
op = None
|
|
618
629
|
l.append(op)
|
|
619
630
|
return l
|
|
@@ -634,7 +645,7 @@ class Expression(_HasLogic):
|
|
|
634
645
|
def __hash__(self):
|
|
635
646
|
return hash(str(self))
|
|
636
647
|
|
|
637
|
-
def
|
|
648
|
+
def __str__(self):
|
|
638
649
|
s = u''
|
|
639
650
|
for child in self.children:
|
|
640
651
|
if child.logic_op & _HasLogic.LOGIC_NOT:
|
|
@@ -646,12 +657,6 @@ class Expression(_HasLogic):
|
|
|
646
657
|
elif child.logic_op & _HasLogic.LOGIC_OR:
|
|
647
658
|
s += ' OR '
|
|
648
659
|
return ensure_text(s)
|
|
649
|
-
|
|
650
|
-
def __str__(self):
|
|
651
|
-
if PY3:
|
|
652
|
-
return self.__unicode__()
|
|
653
|
-
else:
|
|
654
|
-
return self.__unicode__().encode('utf-8')
|
|
655
660
|
|
|
656
661
|
def __repr__(self):
|
|
657
662
|
return str(self)
|
|
@@ -778,7 +783,7 @@ def NOT(arg):
|
|
|
778
783
|
def where(expr):
|
|
779
784
|
if expr is None:
|
|
780
785
|
return []
|
|
781
|
-
elif isinstance(expr,
|
|
786
|
+
elif isinstance(expr, str):
|
|
782
787
|
return where(parse(expr))
|
|
783
788
|
elif isinstance(expr, Operand):
|
|
784
789
|
return [ expr.as_list(), None ]
|
|
@@ -793,10 +798,10 @@ def loads(xml):
|
|
|
793
798
|
if not xml:
|
|
794
799
|
return None
|
|
795
800
|
document = ET.ElementTree()
|
|
796
|
-
if isinstance(xml,
|
|
801
|
+
if isinstance(xml, str):
|
|
797
802
|
xml = ensure_text(xml).encode('utf-8')
|
|
798
|
-
if isinstance(xml,
|
|
799
|
-
xml = io.BytesIO(
|
|
803
|
+
if isinstance(xml, bytes):
|
|
804
|
+
xml = io.BytesIO(xml)
|
|
800
805
|
if not ET.iselement(xml):
|
|
801
806
|
xml = document.parse(xml, ET.XMLTreeBuilder(parse_comments=False))
|
|
802
807
|
if xml.tag == 'operand':
|
kongalib/json.py
CHANGED
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
from __future__ import print_function
|
|
17
17
|
|
|
18
18
|
from kongalib import JSONEncoder, JSONDecoder, Decimal
|
|
19
|
-
from .compat import *
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
|
|
@@ -64,7 +63,7 @@ class Decoder(JSONDecoder):
|
|
|
64
63
|
self.stack = [ [None, None] ]
|
|
65
64
|
self.top = None
|
|
66
65
|
|
|
67
|
-
if isinstance(text,
|
|
66
|
+
if isinstance(text, (str, bytes)):
|
|
68
67
|
self.parse(text)
|
|
69
68
|
else:
|
|
70
69
|
while True:
|
kongalib/scripting.py
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
from __future__ import print_function
|
|
17
17
|
from __future__ import absolute_import
|
|
18
18
|
|
|
19
|
-
from kongalib import Error
|
|
20
|
-
from
|
|
19
|
+
from kongalib import Error
|
|
20
|
+
from _kongalib import get_application_log_path, set_interpreter_timeout, get_interpreter_timeout, get_interpreter_time_left, _set_process_foreground
|
|
21
21
|
|
|
22
22
|
import sys
|
|
23
23
|
import os
|
|
@@ -148,7 +148,7 @@ def timeout_handler():
|
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
|
|
151
|
-
def init_interpreter(
|
|
151
|
+
def init_interpreter():
|
|
152
152
|
_State.io.append((sys.stdout, sys.stderr, sys.stdin))
|
|
153
153
|
try:
|
|
154
154
|
proxy._initialize()
|
|
@@ -176,10 +176,7 @@ def init_interpreter(init_logging=True):
|
|
|
176
176
|
return True
|
|
177
177
|
tb = list(filter(do_filter, tb))
|
|
178
178
|
try:
|
|
179
|
-
|
|
180
|
-
proxy.builtin.print_exception(type, value, tb)
|
|
181
|
-
else:
|
|
182
|
-
proxy.builtin.print_exception(type.__name__, str(value), tb)
|
|
179
|
+
proxy.builtin.print_exception(type, value, tb)
|
|
183
180
|
except:
|
|
184
181
|
debug_log('proxy.builtin.print_exception exception:\n%s' % traceback.format_exc())
|
|
185
182
|
sys.excepthook = excepthook
|
|
@@ -226,7 +223,8 @@ class _Controller(threading.Thread):
|
|
|
226
223
|
name = None
|
|
227
224
|
while name != 'exit':
|
|
228
225
|
try:
|
|
229
|
-
|
|
226
|
+
ready = multiprocessing.connection.wait([ self.conn ], 0.5)
|
|
227
|
+
if not ready:
|
|
230
228
|
if self.request == _Controller.QUIT_REQUEST:
|
|
231
229
|
break
|
|
232
230
|
continue
|
|
@@ -281,16 +279,15 @@ class _Controller(threading.Thread):
|
|
|
281
279
|
|
|
282
280
|
|
|
283
281
|
|
|
284
|
-
def _trampoline(conn, sem, foreground, dll_paths, queue):
|
|
282
|
+
def _trampoline(conn, sem, foreground, env, dll_paths, queue, level):
|
|
283
|
+
logging.getLogger().setLevel(level)
|
|
285
284
|
logger = logging.getLogger('script._trampoline')
|
|
286
285
|
handler = logging.handlers.QueueHandler(queue)
|
|
287
|
-
handler.setLevel(
|
|
286
|
+
handler.setLevel(level)
|
|
288
287
|
logger.addHandler(handler)
|
|
289
|
-
logger.setLevel(logging.DEBUG)
|
|
290
288
|
logger.debug('entering interpreter process')
|
|
291
289
|
try:
|
|
292
|
-
|
|
293
|
-
_set_process_foreground()
|
|
290
|
+
_set_process_foreground(foreground)
|
|
294
291
|
for path in dll_paths:
|
|
295
292
|
try:
|
|
296
293
|
os.add_dll_directory(path)
|
|
@@ -298,6 +295,11 @@ def _trampoline(conn, sem, foreground, dll_paths, queue):
|
|
|
298
295
|
except:
|
|
299
296
|
if sys.platform == 'win32':
|
|
300
297
|
logger.error('error adding DLL directory: %s' % path)
|
|
298
|
+
for key, value in (env or {}).items():
|
|
299
|
+
key = str(key)
|
|
300
|
+
value = str(value)
|
|
301
|
+
os.environ[key] = value
|
|
302
|
+
logger.debug('added env variable %s=%s' % (key, value))
|
|
301
303
|
|
|
302
304
|
_State.controller = _Controller(conn, sem)
|
|
303
305
|
_State.controller.start()
|
|
@@ -309,8 +311,6 @@ def _trampoline(conn, sem, foreground, dll_paths, queue):
|
|
|
309
311
|
args, path, timeout, script, cwd = request
|
|
310
312
|
sys.argv = args
|
|
311
313
|
sys.path = path
|
|
312
|
-
if (not PY3) and isinstance(script, unicode):
|
|
313
|
-
script = script.encode('utf-8', 'replace')
|
|
314
314
|
filename = args[0]
|
|
315
315
|
if cwd:
|
|
316
316
|
os.chdir(cwd)
|
|
@@ -337,6 +337,8 @@ def _trampoline(conn, sem, foreground, dll_paths, queue):
|
|
|
337
337
|
except:
|
|
338
338
|
pass
|
|
339
339
|
_State.controller.join()
|
|
340
|
+
except KeyboardInterrupt:
|
|
341
|
+
logger.debug('user issued a keyboard interrupt')
|
|
340
342
|
except Exception as e:
|
|
341
343
|
import traceback
|
|
342
344
|
logger.critical('unhandled error in interpreter process: %s' % traceback.format_exc())
|
|
@@ -361,7 +363,7 @@ class _ControllerProxy(Proxy):
|
|
|
361
363
|
|
|
362
364
|
|
|
363
365
|
class Interpreter(object):
|
|
364
|
-
def __init__(self, foreground=True):
|
|
366
|
+
def __init__(self, foreground=True, env=None):
|
|
365
367
|
self.proc = None
|
|
366
368
|
self.exc_info = None
|
|
367
369
|
self.conn = None
|
|
@@ -370,15 +372,17 @@ class Interpreter(object):
|
|
|
370
372
|
self.queue = multiprocessing.Queue()
|
|
371
373
|
self.proxy = None
|
|
372
374
|
self.foreground = foreground
|
|
373
|
-
self.
|
|
375
|
+
self.env = env
|
|
376
|
+
self.logger_listener = logging.handlers.QueueListener(self.queue, *logging.getLogger().handlers, respect_handler_level=True)
|
|
374
377
|
|
|
375
378
|
def __del__(self):
|
|
376
379
|
with self.lock:
|
|
377
380
|
if self.proc is not None:
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
381
|
+
if self.proc.is_alive():
|
|
382
|
+
try:
|
|
383
|
+
self.proxy.exit()
|
|
384
|
+
except:
|
|
385
|
+
pass
|
|
382
386
|
try:
|
|
383
387
|
self.logger_listener.stop()
|
|
384
388
|
except:
|
|
@@ -390,7 +394,7 @@ class Interpreter(object):
|
|
|
390
394
|
self.conn, self.client_conn = multiprocessing.Pipe()
|
|
391
395
|
self.proxy = _ControllerProxy(self.conn).controller
|
|
392
396
|
self.logger_listener.start()
|
|
393
|
-
self.proc = multiprocessing.Process(target=_trampoline, args=(self.client_conn, self.sem, self.foreground, _DLL_PATHS, self.queue), daemon=True)
|
|
397
|
+
self.proc = multiprocessing.Process(target=_trampoline, args=(self.client_conn, self.sem, self.foreground, self.env, _DLL_PATHS, self.queue, logging.getLogger().level), daemon=True)
|
|
394
398
|
self.proc.start()
|
|
395
399
|
exitcode = self.proc.exitcode
|
|
396
400
|
if exitcode is not None:
|
|
@@ -430,7 +434,10 @@ class Interpreter(object):
|
|
|
430
434
|
self.proc = None
|
|
431
435
|
self.lock.release()
|
|
432
436
|
try:
|
|
433
|
-
|
|
437
|
+
try:
|
|
438
|
+
proc.terminate()
|
|
439
|
+
except:
|
|
440
|
+
pass
|
|
434
441
|
proc.join(3)
|
|
435
442
|
if proc.is_alive():
|
|
436
443
|
try:
|
|
@@ -441,13 +448,18 @@ class Interpreter(object):
|
|
|
441
448
|
self.lock.acquire()
|
|
442
449
|
|
|
443
450
|
def is_running(self):
|
|
444
|
-
|
|
445
|
-
|
|
451
|
+
conn = self.conn
|
|
452
|
+
proc = self.proc
|
|
453
|
+
return (conn is None) or ((proc is not None) and proc.is_alive())
|
|
446
454
|
|
|
447
455
|
def set_timeout(self, timeout=None, restore=False):
|
|
448
456
|
with self.lock:
|
|
449
457
|
if self.proxy is not None:
|
|
450
|
-
|
|
458
|
+
func = self.proxy.set_timeout
|
|
459
|
+
else:
|
|
460
|
+
func = None
|
|
461
|
+
if func is not None:
|
|
462
|
+
return func(timeout, restore)
|
|
451
463
|
|
|
452
464
|
def get_time_left(self):
|
|
453
465
|
with self.lock:
|
|
@@ -516,6 +528,8 @@ class _Method(object):
|
|
|
516
528
|
self.handler._conn.send((self.handler._name, self.name, args, kwargs))
|
|
517
529
|
if DEBUG:
|
|
518
530
|
debug_log('[Proxy] call sent in %f secs. Waiting reply: %s' % (time.time() - s, str((self.handler._name, self.name))))
|
|
531
|
+
|
|
532
|
+
multiprocessing.connection.wait([ self.handler._conn ])
|
|
519
533
|
e, result = self.handler._conn.recv()
|
|
520
534
|
if DEBUG:
|
|
521
535
|
s = time.time()
|
|
@@ -563,7 +577,8 @@ class _ServerProxy(threading.Thread):
|
|
|
563
577
|
self.conn = self.listener.accept()
|
|
564
578
|
debug_log("[ServerProxy] got proxy")
|
|
565
579
|
while True:
|
|
566
|
-
|
|
580
|
+
ready = multiprocessing.connection.wait([ self.conn ], 0.5)
|
|
581
|
+
if ready:
|
|
567
582
|
data = self.conn.recv()
|
|
568
583
|
handler, name, args, kwargs = data
|
|
569
584
|
if handler in self.handlers:
|
|
@@ -606,6 +621,7 @@ class _ServerProxy(threading.Thread):
|
|
|
606
621
|
class BuiltinHandler(object):
|
|
607
622
|
def __init__(self):
|
|
608
623
|
self.__interpreter = None
|
|
624
|
+
self.__exit_funcs = []
|
|
609
625
|
|
|
610
626
|
def _set_interpreter(self, interpreter):
|
|
611
627
|
self.__interpreter = interpreter
|
|
@@ -658,6 +674,14 @@ class BuiltinHandler(object):
|
|
|
658
674
|
def noop(self):
|
|
659
675
|
pass
|
|
660
676
|
|
|
677
|
+
def atexit(self, func, *args, **kwargs):
|
|
678
|
+
self.__exit_funcs.append((func, args, kwargs))
|
|
679
|
+
|
|
680
|
+
def _atexit(self):
|
|
681
|
+
while self.__exit_funcs:
|
|
682
|
+
func, args, kwargs = self.__exit_funcs.pop()
|
|
683
|
+
func(*args, **kwargs)
|
|
684
|
+
|
|
661
685
|
|
|
662
686
|
def set_connection_family(family):
|
|
663
687
|
global gConnFamily
|
|
@@ -715,6 +739,7 @@ def execute(script=None, filename=None, argv=None, path=None, timeout=0, handler
|
|
|
715
739
|
else:
|
|
716
740
|
debug_log("[ServerProxy] unhandled execute exception: %s" % traceback.format_exc())
|
|
717
741
|
type, value, tb = sys.exc_info()
|
|
742
|
+
tb = traceback.format_tb(tb)
|
|
718
743
|
def do_filter(entry):
|
|
719
744
|
filename = entry[0].replace('\\', '/')
|
|
720
745
|
if filename.endswith('kongalib/scripting.py') or filename.endswith('__script_host__.py'):
|
|
@@ -722,15 +747,13 @@ def execute(script=None, filename=None, argv=None, path=None, timeout=0, handler
|
|
|
722
747
|
return True
|
|
723
748
|
tb = list(filter(do_filter, tb))
|
|
724
749
|
try:
|
|
725
|
-
|
|
726
|
-
_handlers['builtin'].print_exception(type, value, tb)
|
|
727
|
-
else:
|
|
728
|
-
_handlers['builtin'].print_exception(type.__name__, str(value), tb)
|
|
750
|
+
_handlers['builtin'].print_exception(type, value, tb)
|
|
729
751
|
except:
|
|
730
752
|
debug_log('proxy.builtin.print_exception exception:\n%s' % traceback.format_exc())
|
|
731
753
|
finally:
|
|
732
754
|
_handlers['builtin']._set_interpreter(None)
|
|
733
755
|
del interpreter
|
|
756
|
+
_handlers['builtin']._atexit()
|
|
734
757
|
try:
|
|
735
758
|
debug_log("[ServerProxy] done")
|
|
736
759
|
finally:
|
|
@@ -1,36 +1,42 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: kongalib
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0.post1
|
|
4
4
|
Summary: Konga client library
|
|
5
|
-
|
|
6
|
-
Author: EasyByte Software
|
|
7
|
-
Author-email: konga@easybyte.it
|
|
5
|
+
Author-email: EasyByte Software <konga@easybyte.it>
|
|
8
6
|
License: LGPL
|
|
7
|
+
Project-URL: homepage, https://github.com/easybyte-software/kongalib
|
|
8
|
+
Project-URL: documentation, https://public.easybyte.it/docs/current/technical/kongalib/index.html
|
|
9
|
+
Project-URL: repository, https://github.com/easybyte-software/kongalib.git
|
|
9
10
|
Keywords: konga,client,erp
|
|
10
11
|
Classifier: Natural Language :: Italian
|
|
11
12
|
Classifier: Programming Language :: Python
|
|
12
|
-
Classifier: Programming Language :: Python :: 2
|
|
13
|
-
Classifier: Programming Language :: Python :: 2.7
|
|
14
13
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.8
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
22
|
Classifier: Programming Language :: C++
|
|
20
23
|
Classifier: Development Status :: 5 - Production/Stable
|
|
21
24
|
Classifier: Environment :: Console
|
|
22
25
|
Classifier: Intended Audience :: Developers
|
|
23
26
|
Classifier: Intended Audience :: Information Technology
|
|
24
27
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
25
|
-
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
26
28
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
27
29
|
Classifier: Operating System :: Microsoft :: Windows
|
|
28
30
|
Classifier: Operating System :: POSIX :: Linux
|
|
29
31
|
Classifier: Topic :: Office/Business
|
|
30
32
|
Classifier: Topic :: Office/Business :: Financial
|
|
31
33
|
Classifier: Topic :: Software Development :: Libraries
|
|
34
|
+
Requires-Python: >=3.8
|
|
35
|
+
Description-Content-Type: text/x-rst
|
|
32
36
|
License-File: LICENSE
|
|
33
37
|
Requires-Dist: colorama
|
|
38
|
+
Requires-Dist: nest_asyncio
|
|
39
|
+
Dynamic: license-file
|
|
34
40
|
|
|
35
41
|
Kongalib
|
|
36
42
|
========
|
|
@@ -44,9 +50,9 @@ Kongalib
|
|
|
44
50
|
.. image:: https://img.shields.io/badge/License-LGPLv3-blue.svg
|
|
45
51
|
:alt: LGPL v3 License
|
|
46
52
|
:target: https://www.gnu.org/licenses/lgpl-3.0.en.html
|
|
47
|
-
.. image:: https://
|
|
53
|
+
.. image:: https://github.com/easybyte-software/kongalib/actions/workflows/build_wheels.yml/badge.svg?event=workflow_dispatch
|
|
48
54
|
:alt: Build Status
|
|
49
|
-
:target: https://
|
|
55
|
+
:target: https://github.com/easybyte-software/kongalib/actions/workflows/build_wheels.yml
|
|
50
56
|
|
|
51
57
|
Libreria Python di comunicazione con i server `EasyByte Konga`_. Tramite
|
|
52
58
|
*kongalib* è possibile connettersi ad un server Konga (integrato in Konga Pro o
|
|
@@ -73,16 +79,16 @@ Se si desidera è possibile compilare i sorgenti. I prerequisiti per compilare
|
|
|
73
79
|
|
|
74
80
|
**Windows**
|
|
75
81
|
|
|
76
|
-
Sono supportate le versioni di Windows dalla
|
|
82
|
+
Sono supportate le versioni di Windows dalla 10 in su. Come prerequisiti è
|
|
77
83
|
necessario installare:
|
|
78
84
|
|
|
79
|
-
- Microsoft Visual Studio 2017
|
|
85
|
+
- Microsoft Visual Studio 2017 o successiva
|
|
80
86
|
- `SDK di Konga`_
|
|
81
87
|
|
|
82
88
|
|
|
83
89
|
**MacOS X**
|
|
84
90
|
|
|
85
|
-
Sono supportate le versioni di macOS dalla 10.
|
|
91
|
+
Sono supportate le versioni di macOS dalla 10.9 in su. Come prerequisiti è
|
|
86
92
|
necessario installare:
|
|
87
93
|
|
|
88
94
|
- XCode (assicurarsi di aver installato anche i tool da linea di comando)
|
|
@@ -92,9 +98,9 @@ necessario installare:
|
|
|
92
98
|
**Linux**
|
|
93
99
|
|
|
94
100
|
Benchè il pacchetto binario wheel per Linux supporti tutte le distribuzioni
|
|
95
|
-
Linux moderne (specifica `
|
|
101
|
+
Linux moderne (specifica `manylinux_2_28`_), al momento la compilazione da parte di
|
|
96
102
|
terzi è supportata ufficialmente solo se si usa una distribuzione Linux basata su
|
|
97
|
-
Debian, in particolare Ubuntu Linux dalla versione
|
|
103
|
+
Debian, in particolare Ubuntu Linux dalla versione 20.04 in su. Sono necessari i
|
|
98
104
|
seguenti pacchetti *deb*:
|
|
99
105
|
|
|
100
106
|
- build-essential
|
|
@@ -102,18 +108,15 @@ seguenti pacchetti *deb*:
|
|
|
102
108
|
- python-dev
|
|
103
109
|
- `easybyte-konga-dev`_
|
|
104
110
|
|
|
105
|
-
La compilazione
|
|
111
|
+
La compilazione come da standard Python è possibile sempre tramite *pip*, eseguendo
|
|
112
|
+
dalla directory dei sorgenti::
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
pip install .
|
|
108
115
|
|
|
109
116
|
|
|
110
117
|
.. note:: Sotto piattaforma Windows per la corretta compilazione è necessario
|
|
111
|
-
impostare la variabile d'ambiente `KONGASDK`
|
|
112
|
-
dell'`SDK di Konga`_.
|
|
113
|
-
Visual Studio 2017 e non è compatibile con Python 2.x (che sotto Windows
|
|
114
|
-
richiede Visual Studio 2008); se si desidera usare *kongalib* con Python 2.x
|
|
115
|
-
sotto Windows, è necessario usare la *wheel* precompilata installabile
|
|
116
|
-
tramite *pip*.
|
|
118
|
+
impostare la variabile d'ambiente `KONGASDK` alla directory d'installazione
|
|
119
|
+
dell'`SDK di Konga`_.
|
|
117
120
|
|
|
118
121
|
|
|
119
122
|
Risorse
|
|
@@ -143,5 +146,5 @@ Risorse
|
|
|
143
146
|
.. _Script di utilità comune per Konga: https://github.com/easybyte-software/konga_scripts
|
|
144
147
|
.. _SDK di Konga: http://public.easybyte.it/downloads/current
|
|
145
148
|
.. _easybyte-konga-dev: http://public.easybyte.it/downloads/current
|
|
146
|
-
..
|
|
149
|
+
.. _manylinux_2_28: https://github.com/pypa/manylinux
|
|
147
150
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
_kongalib.cp310-win_amd64.pdb,sha256=fFl5QDWTUZVSCxKUpgerW8NEcUclq72Po0EgsO0eeGQ,7335936
|
|
2
|
+
_kongalib.cp310-win_amd64.pyd,sha256=zcCsXx-gV3r2GmoCEYLuBA48Nb1lKDJTIGc57M16yh4,2533888
|
|
3
|
+
kongaui.py,sha256=0sSKUsOo5vLNH3wyUUl4icOL4z4CXqoPAR2fqYQZE7o,20598
|
|
4
|
+
kongautil.py,sha256=PSObmHX6kVf54mtIyBXtxzf4CMHUsj_ppDNSWjY3Y2c,24005
|
|
5
|
+
kongalib/__init__.py,sha256=VPFvthIAm7K668_Fxx_4Wf6rwZCAs6dwBz6DfZtwrLU,12979
|
|
6
|
+
kongalib/async_client.py,sha256=XFzkYLr0KbaNvCN3piS-AdWigcFtJqFpcDCN0fUKeMA,48017
|
|
7
|
+
kongalib/client.py,sha256=8fz5L0mvRa5q0G06gK1MEN0_PYapIgkMK_wd1_Yrexo,58834
|
|
8
|
+
kongalib/constants.py,sha256=r59fg2-CCTWRvKOusxXe9FTBrSAmFt5Esn70DsyEn8s,8793
|
|
9
|
+
kongalib/data_dictionary.py,sha256=a-_aTlZeJPGkxkxzG040A2yrfXf_Stup3CTurh_93B0,11298
|
|
10
|
+
kongalib/db.py,sha256=qnSon_7N5Po0-ww-88mL7DZlGX7_ASIM4tMY9bGGBnk,8354
|
|
11
|
+
kongalib/expression.py,sha256=A7-erKQPF4VroB3ERCTvLYyOv5_gm1a-rxToLNhd8VY,21230
|
|
12
|
+
kongalib/json.py,sha256=-8h3e92hLzsElxZhLgpcoQWfakSYyY0i7vsxB7Z7qtk,2341
|
|
13
|
+
kongalib/lex.py,sha256=tV9VGF97XHRFf0eBICVzTILzH878i_slXLsoktFnZTQ,41797
|
|
14
|
+
kongalib/scripting.py,sha256=153S5jtpLie_LztS6FH1QLs1-yrWVCdWM7hzY8FWp6g,20344
|
|
15
|
+
kongalib/yacc.py,sha256=UHnHKzBknH7qzIT7xJFIHYKBTzOIxWILtGPdSI29XcE,131768
|
|
16
|
+
kongalib-2.0.0.post1.dist-info/licenses/LICENSE,sha256=LPNKwDiu5awG-TPd0dqYJuC7k4PBPY4LCI_O0LSpW1s,7814
|
|
17
|
+
kongalib-2.0.0.post1.dist-info/METADATA,sha256=XUhKmSxS4lqMe0PuaQlZFt-qAjZenn0O7Jebn3iBsVE,5408
|
|
18
|
+
kongalib-2.0.0.post1.dist-info/WHEEL,sha256=KUuBC6lxAbHCKilKua8R9W_TM71_-9Sg5uEP3uDWcoU,101
|
|
19
|
+
kongalib-2.0.0.post1.dist-info/top_level.txt,sha256=htHdvBd1NQjLXNwXgTzCMPtyfCtorpw6jUZzu09vDYY,37
|
|
20
|
+
kongalib-2.0.0.post1.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
21
|
+
kongalib-2.0.0.post1.dist-info/RECORD,,
|