sqlalchemy-iris 0.5.0b3__py3-none-any.whl → 0.6.0b1__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.
Files changed (77) hide show
  1. intersystems_iris/_BufferReader.py +10 -0
  2. intersystems_iris/_BufferWriter.py +32 -0
  3. intersystems_iris/_ConnectionInformation.py +54 -0
  4. intersystems_iris/_ConnectionParameters.py +18 -0
  5. intersystems_iris/_Constant.py +38 -0
  6. intersystems_iris/_DBList.py +499 -0
  7. intersystems_iris/_Device.py +69 -0
  8. intersystems_iris/_GatewayContext.py +25 -0
  9. intersystems_iris/_GatewayException.py +4 -0
  10. intersystems_iris/_GatewayUtility.py +74 -0
  11. intersystems_iris/_IRIS.py +1294 -0
  12. intersystems_iris/_IRISConnection.py +516 -0
  13. intersystems_iris/_IRISEmbedded.py +85 -0
  14. intersystems_iris/_IRISGlobalNode.py +273 -0
  15. intersystems_iris/_IRISGlobalNodeView.py +25 -0
  16. intersystems_iris/_IRISIterator.py +143 -0
  17. intersystems_iris/_IRISList.py +360 -0
  18. intersystems_iris/_IRISNative.py +208 -0
  19. intersystems_iris/_IRISOREF.py +4 -0
  20. intersystems_iris/_IRISObject.py +424 -0
  21. intersystems_iris/_IRISReference.py +133 -0
  22. intersystems_iris/_InStream.py +149 -0
  23. intersystems_iris/_LegacyIterator.py +135 -0
  24. intersystems_iris/_ListItem.py +15 -0
  25. intersystems_iris/_ListReader.py +84 -0
  26. intersystems_iris/_ListWriter.py +157 -0
  27. intersystems_iris/_LogFileStream.py +115 -0
  28. intersystems_iris/_MessageHeader.py +51 -0
  29. intersystems_iris/_OutStream.py +25 -0
  30. intersystems_iris/_PrintStream.py +65 -0
  31. intersystems_iris/_PythonGateway.py +850 -0
  32. intersystems_iris/_SharedMemorySocket.py +87 -0
  33. intersystems_iris/__init__.py +79 -0
  34. intersystems_iris/__main__.py +7 -0
  35. intersystems_iris/dbapi/_Column.py +56 -0
  36. intersystems_iris/dbapi/_DBAPI.py +2295 -0
  37. intersystems_iris/dbapi/_Descriptor.py +46 -0
  38. intersystems_iris/dbapi/_IRISStream.py +63 -0
  39. intersystems_iris/dbapi/_Message.py +158 -0
  40. intersystems_iris/dbapi/_Parameter.py +138 -0
  41. intersystems_iris/dbapi/_ParameterCollection.py +133 -0
  42. intersystems_iris/dbapi/_ResultSetRow.py +314 -0
  43. intersystems_iris/dbapi/_SQLType.py +32 -0
  44. intersystems_iris/dbapi/__init__.py +0 -0
  45. intersystems_iris/dbapi/preparser/_PreParser.py +1658 -0
  46. intersystems_iris/dbapi/preparser/_Scanner.py +391 -0
  47. intersystems_iris/dbapi/preparser/_Token.py +81 -0
  48. intersystems_iris/dbapi/preparser/_TokenList.py +251 -0
  49. intersystems_iris/dbapi/preparser/__init__.py +0 -0
  50. intersystems_iris/pex/_BusinessHost.py +101 -0
  51. intersystems_iris/pex/_BusinessOperation.py +105 -0
  52. intersystems_iris/pex/_BusinessProcess.py +214 -0
  53. intersystems_iris/pex/_BusinessService.py +95 -0
  54. intersystems_iris/pex/_Common.py +228 -0
  55. intersystems_iris/pex/_Director.py +24 -0
  56. intersystems_iris/pex/_IRISBusinessOperation.py +5 -0
  57. intersystems_iris/pex/_IRISBusinessService.py +18 -0
  58. intersystems_iris/pex/_IRISInboundAdapter.py +5 -0
  59. intersystems_iris/pex/_IRISOutboundAdapter.py +17 -0
  60. intersystems_iris/pex/_InboundAdapter.py +57 -0
  61. intersystems_iris/pex/_Message.py +6 -0
  62. intersystems_iris/pex/_OutboundAdapter.py +46 -0
  63. intersystems_iris/pex/__init__.py +25 -0
  64. iris/__init__.py +25 -0
  65. iris/iris_site.py +13 -0
  66. iris/irisbuiltins.py +97 -0
  67. iris/irisloader.py +199 -0
  68. irisnative/_IRISNative.py +9 -0
  69. irisnative/__init__.py +10 -0
  70. {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/METADATA +1 -1
  71. sqlalchemy_iris-0.6.0b1.dist-info/RECORD +83 -0
  72. sqlalchemy_iris-0.6.0b1.dist-info/top_level.txt +4 -0
  73. sqlalchemy_iris-0.5.0b3.dist-info/RECORD +0 -14
  74. sqlalchemy_iris-0.5.0b3.dist-info/top_level.txt +0 -1
  75. {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/LICENSE +0 -0
  76. {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/WHEEL +0 -0
  77. {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,850 @@
1
+ import functools
2
+ import hashlib
3
+ import importlib
4
+ import os
5
+ import platform
6
+ import signal
7
+ import socket
8
+ import ssl
9
+ import xml.etree.ElementTree as ET
10
+ import base64
11
+ import sys
12
+ import threading
13
+ import traceback
14
+ import inspect
15
+ import decimal
16
+ import zipfile
17
+ import intersystems_iris._Constant
18
+ import intersystems_iris._GatewayException
19
+ import intersystems_iris._GatewayUtility
20
+ import intersystems_iris._InStream
21
+ import intersystems_iris._IRISOREF
22
+ import intersystems_iris._LogFileStream
23
+ import intersystems_iris._OutStream
24
+ import intersystems_iris._PrintStream
25
+ import intersystems_iris._GatewayContext
26
+ import intersystems_iris._IRIS
27
+ import intersystems_iris._IRISConnection
28
+ import intersystems_iris._IRISList
29
+
30
+ def synchronized(func):
31
+ @functools.wraps(func)
32
+ def wrapper(self, *args, **kwargs):
33
+ with self.lock:
34
+ return func(self, *args, **kwargs)
35
+ return wrapper
36
+
37
+ class _PythonGateway(threading.Thread):
38
+
39
+ _output_redirect = None
40
+ _error_redirect = None
41
+ _server_name = None
42
+
43
+ @classmethod
44
+ def _main(cls, args):
45
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
46
+ port = cls.__get_port_number(args)
47
+ log_stream = cls.__get_log_stream(args)
48
+ cls._server_name = cls.__get_server_name(args)
49
+ host = cls.__get_host(args)
50
+ # secret_hash = cls.__get_secret(args)
51
+ # sslcontext = cls.__get_sslcontext(args)
52
+ (secret_hash, sslcontext) = cls.__get_secret_or_sslcontext(args, log_stream)
53
+ try:
54
+ cls.__initialize_output_redirection()
55
+ server_socket = cls.__setup_server_socket(host, port, sslcontext)
56
+ while True:
57
+ try:
58
+ sock, addr = server_socket.accept()
59
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
60
+ try:
61
+ thread = cls(None, sock, log_stream, secret_hash)
62
+ thread.daemon = True
63
+ thread.start()
64
+ except Exception as e:
65
+ traceback.print_exc()
66
+ except ssl.SSLError:
67
+ traceback.print_exc()
68
+ except Exception as e:
69
+ traceback.print_exc()
70
+ raise intersystems_iris._GatewayException._GatewayException("[Python Gateway] Communication link failure: " + str(e))
71
+
72
+ @staticmethod
73
+ def __get_port_number(args):
74
+ if len(args) == 0:
75
+ raise intersystems_iris._GatewayException._GatewayException("Port number must be supplied as the first command line argument")
76
+ else:
77
+ return int(args[0])
78
+
79
+ @staticmethod
80
+ def __get_log_stream(args):
81
+ if len(args) > 1 and len(args[1]) > 0:
82
+ return intersystems_iris._LogFileStream._LogFileStream(args[1])
83
+ return None
84
+
85
+ @staticmethod
86
+ def __get_server_name(args):
87
+ if len(args) > 2:
88
+ return args[2]
89
+ return None
90
+
91
+ @staticmethod
92
+ def __get_host(args):
93
+ if len(args) > 3 and len(args[3]) > 0:
94
+ return args[3]
95
+ # Using 0.0.0.0 causes the gateway to listen on all IP addresses
96
+ return "127.0.0.1"
97
+
98
+ @staticmethod
99
+ def __hex_to_bin(ch):
100
+ if ord('0') <= ord(ch) and ord(ch) <= ord('9'):
101
+ return ord(ch) - ord('0')
102
+ if ord('A') <= ord(ch) and ord(ch) <= ord('F'):
103
+ return ord(ch) - ord('A') + 10
104
+ if ord('a') <= ord(ch) and ord(ch) <= ord('f'):
105
+ return ord(ch) - ord('a') + 10
106
+ return -1
107
+
108
+ @classmethod
109
+ def __get_secret_or_sslcontext(cls, args, log_stream):
110
+ if len(args) > 4:
111
+ security_string = args[4]
112
+ if security_string[:4] == "ssl:":
113
+ try:
114
+ return (None, cls.__get_sslcontext(security_string[4:], log_stream))
115
+ except Exception as e:
116
+ raise intersystems_iris._GatewayException._GatewayException("Error loading SSL Configuration: " + str(e))
117
+ else:
118
+ return (cls.__get_secret(security_string), None)
119
+ return (None, None)
120
+
121
+ @classmethod
122
+ def __get_secret(cls, secure_str):
123
+ number_chars = len(secure_str)
124
+ if number_chars > 0:
125
+ if number_chars > 16:
126
+ number_chars = 16
127
+ secure_str = secure_str[0:number_chars]
128
+ # parse hex binary
129
+ if number_chars % 2 != 0:
130
+ raise ValueError("hexBinary needs to be even-length: " + secure_str)
131
+ parsed_bytes = [b''] * int(number_chars / 2)
132
+ for i in range(0, number_chars, 2):
133
+ h = cls.__hex_to_bin(secure_str[i])
134
+ l = cls.__hex_to_bin(secure_str[i + 1])
135
+ if h == -1 or l == -1:
136
+ raise ValueError("contains illegal character for hexBinary: " + secure_str)
137
+ parsed_bytes[int(i / 2)] = bytes([h * 16 + l])
138
+ eight_bytes = b''
139
+ for i in range(int(number_chars / 2)):
140
+ eight_bytes += parsed_bytes[i]
141
+ hashvalue = hashlib.sha256(eight_bytes).hexdigest()
142
+ return hashvalue
143
+ return None
144
+
145
+ @classmethod
146
+ def __get_sslcontext(cls, config_args, log_stream):
147
+ config_split = config_args.split("?")
148
+ config_file = config_split[0]
149
+ key_pwd = cls.__decode_pwd(config_split[1]) if len(config_split) > 1 else ""
150
+
151
+ # parse XML output from IRIS ssl config
152
+ tree = ET.parse(config_file)
153
+ root = tree.getroot()
154
+ config = root[0]
155
+ config_dict = {}
156
+ for config_item in config:
157
+ config_dict[config_item.tag] = config_item.text
158
+ # print XML file to log, then delete it
159
+ if log_stream:
160
+ with open(log_stream.path, 'a') as f:
161
+ end_line = intersystems_iris._LogFileStream._LogFileStream.LINE_SEPARATOR
162
+ f.write(end_line + "SSL Configuration File:" + end_line)
163
+ with open(config_file) as xml:
164
+ f.write(xml.read() + end_line)
165
+ os.remove(config_file)
166
+ # as a sanity check, verify the parsed XML has various required fields
167
+ required_tags = ["Name", "Type", "Enabled", "VerifyPeer", "TLSMaxVersion", "TLSMinVersion", "CipherList", "Ciphersuites"]
168
+ for tag in required_tags:
169
+ if tag not in config_dict:
170
+ raise ValueError("SSL config file did not contain the field '" + tag + "'")
171
+ # verify provided configuration was for a server
172
+ if config_dict["Type"] != "true":
173
+ raise ValueError("Chosen SSL configuration must be a server configuration")
174
+ # configure SSLContext object
175
+ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
176
+ # set verify_mode
177
+ verify_dict = {"0": ssl.CERT_NONE, "1": ssl.CERT_OPTIONAL, "3": ssl.CERT_REQUIRED}
178
+ context.verify_mode = verify_dict[config_dict["VerifyPeer"]]
179
+ # load CA certificate, if one was provided
180
+ if "CAFile" in config_dict:
181
+ context.load_verify_locations(cafile = config_dict["CAFile"])
182
+ # load certificate/key pair, if one was provided
183
+ if "CertificateFile" in config_dict and "PrivateKeyFile" in config_dict:
184
+ context.load_cert_chain(config_dict["CertificateFile"], config_dict["PrivateKeyFile"], key_pwd)
185
+ # set cipher options
186
+ context.set_ciphers(config_dict["CipherList"] + ":" + config_dict["Ciphersuites"])
187
+ # set min and max TLS version
188
+ tls_dict = {"4": ssl.TLSVersion.TLSv1, "8": ssl.TLSVersion.TLSv1_1, "16": ssl.TLSVersion.TLSv1_2, "32": ssl.TLSVersion.TLSv1_3}
189
+ context.minimum_version = tls_dict[config_dict["TLSMinVersion"]]
190
+ context.maximum_version = tls_dict[config_dict["TLSMaxVersion"]]
191
+ return context
192
+
193
+ @staticmethod
194
+ def __decode_pwd(pwd):
195
+ pwd_bytes = bytearray()
196
+ pwd_bytes.extend(map(ord, pwd))
197
+ pwd_decoded = base64.b64decode(pwd_bytes)
198
+ return pwd_decoded.decode()
199
+
200
+ @staticmethod
201
+ def __setup_server_socket(host, port, sslcontext = None):
202
+ server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
203
+ if platform.system().startswith("Windows"):
204
+ server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 0)
205
+ else:
206
+ server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
207
+ server_socket.bind((host, port))
208
+ server_socket.listen(50)
209
+ if sslcontext is None:
210
+ return server_socket
211
+ else:
212
+ return sslcontext.wrap_socket(server_socket, True)
213
+
214
+ @classmethod
215
+ def __initialize_output_redirection(cls):
216
+ cls._output_redirect = intersystems_iris._PrintStream._PrintStream(0)
217
+ sys.stdout = cls._output_redirect
218
+ cls._error_redirect = intersystems_iris._PrintStream._PrintStream(1)
219
+ sys.stderr = cls._error_redirect
220
+
221
+ def __set_redirect(self):
222
+ if not self._connection._disable_output_redirect:
223
+ self._output_redirect._register()
224
+ self._error_redirect._register()
225
+
226
+ def __init__(self, conn, sock, log_stream, hash):
227
+ threading.Thread.__init__(self)
228
+ self.lock = threading.RLock()
229
+ if conn != None:
230
+ self._connection = conn
231
+ self._device = conn._device
232
+ self._log_stream = conn._log_stream
233
+ else:
234
+ self._connection = intersystems_iris.IRISConnection()
235
+ self._device = intersystems_iris._Device._Device(self._connection, sock)
236
+ self._connection._log_stream = self._log_stream = log_stream
237
+ self._connection._in_message = intersystems_iris._InStream._InStream(self._connection)
238
+ self._connection._out_message = intersystems_iris._OutStream._OutStream(self._connection)
239
+ self.__rundown = False
240
+ self.in_message = intersystems_iris._InStream._InStream(self._connection)
241
+ self.out_message = intersystems_iris._OutStream._OutStream(self._connection)
242
+ self.in_message_secondary = intersystems_iris._InStream._InStream(self._connection)
243
+ self.out_message_secondary = intersystems_iris._OutStream._OutStream(self._connection)
244
+ self.out_message_sequence_number = 0
245
+ self._thread_modules = {}
246
+ self._sys_modules_lock = threading.RLock()
247
+ if hash is not None:
248
+ try:
249
+ if not self.in_message._check_sheader(hash, sock):
250
+ self.__rundown = True
251
+ except Exception as e:
252
+ message = str(e)
253
+ if (message == "Server closed communication device" or
254
+ message == "Communication error: Server closed communication device" or
255
+ message == "Connection reset"):
256
+ self.__rundown = True
257
+ return
258
+ raise intersystems_iris._GatewayException._GatewayException(message)
259
+
260
+ def __cleanup(self):
261
+ if self._output_redirect != None:
262
+ self._output_redirect._unregister()
263
+ if self._error_redirect != None:
264
+ self._error_redirect._unregister()
265
+ self._connection.close()
266
+
267
+ def _dispatch_reentrancy(self, other_in_message):
268
+ code = other_in_message.wire.header._get_function_code()
269
+ code = ((0xFF00 & code) >> 8) - 48
270
+ previous_connection = intersystems_iris.GatewayContext._get_connection()
271
+ intersystems_iris.GatewayContext._set_connection(self._connection)
272
+ self.in_message.wire = other_in_message.wire
273
+ is_disconnect = self.__process_message(code)
274
+ self.out_message._send(self.out_message_sequence_number)
275
+ if is_disconnect:
276
+ if self._connection._log_stream != None:
277
+ self._connection._log_stream._logApi(" << GatewayException: Connection closed inside reentrancy")
278
+ self.__cleanup()
279
+ raise Exception("Connection closed")
280
+ intersystems_iris.GatewayContext._set_connection(previous_connection);
281
+
282
+ @synchronized
283
+ def run(self):
284
+ try:
285
+ self._connection._set_gateway(self)
286
+ to_send_response = False;
287
+ is_disconnect = False;
288
+ while True:
289
+ try:
290
+ with self._connection._lock:
291
+ if self.__rundown:
292
+ self.__cleanup()
293
+ return
294
+ if to_send_response:
295
+ self.out_message._send(self.out_message_sequence_number)
296
+ if is_disconnect:
297
+ self.__cleanup()
298
+ return
299
+ code = self.in_message._read_message_gateway()
300
+ except Exception as e:
301
+ message = str(e)
302
+ if (message == "Server closed communication device" or message == "Connection reset"):
303
+ self._device.close()
304
+ return
305
+ raise intersystems_iris._GatewayException._GatewayException(message)
306
+ is_disconnect = self.__process_message(code)
307
+ to_send_response = (code != intersystems_iris._Constant._Constant.ENUM_MESSAGE_CONNECT)
308
+ except BaseException as e:
309
+ traceback.print_exc()
310
+ try:
311
+ self._device.close()
312
+ except BaseException as e:
313
+ traceback.print_exc()
314
+
315
+ def __process_message(self, code):
316
+ switcher = {
317
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_CONNECT: self.__connect,
318
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_DISCONNECT: self.__disconnect,
319
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_SHUTDOWN: self.__shutdown,
320
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_PING: self.__ping,
321
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_BENCHMARK_ECHO: self.__benchmark_echo,
322
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_LOAD_MODULES: self.__load_modules,
323
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_DYNAMIC_EXECUTE_CONSTRUCTOR: self.__dynamic_execute_constructor,
324
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_DYNAMIC_EXECUTE_METHOD: self.__dynamic_execute_method,
325
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_DYNAMIC_EXECUTE_GET: self.__dynamic_execute_get,
326
+ intersystems_iris._Constant._Constant.ENUM_MESSAGE_DYNAMIC_EXECUTE_SET: self.__dynamic_execute_set
327
+ }
328
+ func = switcher.get(code, "passphrase" if code == intersystems_iris._Constant._Constant.ENUM_MESSAGE_PASSPHRASE else "default")
329
+ if func == "passphrase":
330
+ pass
331
+ elif func == "default":
332
+ raise intersystems_iris._GatewayException._GatewayException("Unknown Message:", code)
333
+ else:
334
+ func()
335
+ if code == intersystems_iris._Constant._Constant.ENUM_MESSAGE_DISCONNECT:
336
+ return True
337
+ else:
338
+ return False
339
+
340
+ def __connect(self):
341
+ sequence_number = self.in_message.wire._get_header_count();
342
+ unused = self.in_message.wire._get()
343
+ self._connection._connection_info._is_unicode = bool(self.in_message.wire._get())
344
+ self._connection._connection_info._set_server_locale(self.in_message.wire._get())
345
+ self._connection._connection_info._server_job_number = self.in_message.wire._get()
346
+ self._connection._connection_params.namespace = self.in_message.wire._get()
347
+ module_count = int(self.in_message.wire._get())
348
+ for i in range(module_count):
349
+ try:
350
+ self.__load_one_module(self.in_message.wire._get(), False)
351
+ except BaseException as e:
352
+ pass
353
+ self._connection._disable_output_redirect = bool(self.in_message.wire._get())
354
+ self.__set_redirect()
355
+ usused = self.in_message.wire._get()
356
+ dbsrv_protocol_version = int(self.in_message.wire._get())
357
+ negotiated_protocol_version = min(intersystems_iris._Constant._Constant.PROTOCOL_VERSION, dbsrv_protocol_version)
358
+ self._connection._connection_info._iris_install_dir = None if self.in_message.wire._is_end() else self.in_message.wire._get()
359
+ self._connection._connection_params.hostname = None if self.in_message.wire._is_end() else self.in_message.wire._get()
360
+ # temporarily disable shared-memory
361
+ # self._connection._connection_params._set_sharedmemory(self._connection._connection_info._iris_install_dir != None)
362
+ self._connection._connection_params._set_sharedmemory(False)
363
+ compact_double = False if self.in_message.wire._is_end() else bool(self.in_message.wire._get())
364
+ self._connection._connection_info.protocol_version = negotiated_protocol_version;
365
+ self._connection._connection_info._compact_double = compact_double if negotiated_protocol_version >= 65 else False
366
+ self.out_message.wire._set_connection_info(self._connection._connection_info)
367
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_CONNECT)
368
+ self.out_message.wire._set(self._connection._connection_info.protocol_version)
369
+ self.out_message.wire._set(self._connection._connection_info.protocol_version)
370
+ self.out_message.wire._set(self._connection._connection_params._get_sharedmemory())
371
+ self.out_message.wire._set(self._server_name, True)
372
+ self.out_message._send(sequence_number)
373
+ if self._connection._connection_params._get_sharedmemory():
374
+ self._connection._device.establishSHMSocket()
375
+ if self._connection._is_using_sharedmemory():
376
+ self.in_message = intersystems_iris._InStream._InStream(self._connection)
377
+ self.out_message = intersystems_iris._OutStream._OutStream(self._connection)
378
+ self.in_message_secondary = intersystems_iris._InStream._InStream(self._connection)
379
+ self.out_message_secondary = intersystems_iris._OutStream._OutStream(self._connection)
380
+ self._connection._in_message = intersystems_iris._InStream._InStream(self._connection)
381
+ self._connection._out_message = intersystems_iris._OutStream._OutStream(self._connection)
382
+ intersystems_iris.GatewayContext._set_connection(self._connection)
383
+ return
384
+
385
+ def __load_one_module(self, filename_full, process_wide):
386
+ if filename_full is None: return
387
+ if os.path.isdir(filename_full):
388
+ if filename_full[-1] == os.sep:
389
+ filename_full = os.path.join(filename_full,"__init__.py")
390
+ else:
391
+ filename_full = filename_full + ".__init__.py"
392
+ if filename_full.endswith(".py"):
393
+ filename_path = os.path.dirname(filename_full)
394
+ filename_name = os.path.basename(filename_full)
395
+ filename_short = filename_name.rsplit('.', 1)[0]
396
+ filename_ext = filename_name.rsplit('.', 1)[1]
397
+ with self._sys_modules_lock:
398
+ self.__save_sys_module(process_wide)
399
+ sys.path.insert(0,filename_path)
400
+ importlib.import_module(filename_short)
401
+ del sys.path[0]
402
+ self.__restore_sys_module(process_wide)
403
+ return
404
+ elif filename_full.endswith(".whl"):
405
+ ziplist = zipfile.ZipFile(filename_full).namelist()
406
+ with self._sys_modules_lock:
407
+ self.__save_sys_module(process_wide)
408
+ sys.path.insert(0,filename_full)
409
+ for file in ziplist:
410
+ if file.endswith(".py"):
411
+ package_name = file[0:-3].replace("/",".")
412
+ importlib.import_module(package_name)
413
+ del sys.path[0]
414
+ self.__restore_sys_module(process_wide)
415
+ return
416
+ else:
417
+ # import built-in modules
418
+ package_name = filename_full
419
+ self.__save_sys_module(process_wide)
420
+ importlib.import_module(package_name)
421
+ self.__restore_sys_module(process_wide)
422
+ return
423
+
424
+ def __save_sys_module(self, process_wide):
425
+ if process_wide: return
426
+ self._saved_modules = sys.modules.copy()
427
+ return
428
+
429
+ def __restore_sys_module(self, process_wide):
430
+ if process_wide: return
431
+ new_modules = [key for key in sys.modules if key not in self._saved_modules]
432
+ for key in new_modules:
433
+ self._thread_modules[key] = sys.modules[key]
434
+ del sys.modules[key]
435
+ return
436
+
437
+ def _load_class(self, class_name):
438
+ if "." in class_name:
439
+ module_name = class_name.rsplit(".", 1)[0]
440
+ class_name_short = class_name.rsplit(".", 1)[1]
441
+ else:
442
+ module_name = None
443
+ class_name_short = class_name
444
+ if class_name_short == "":
445
+ try:
446
+ return self._thread_modules[module_name]
447
+ except Exception as ex:
448
+ pass
449
+ try:
450
+ with self._sys_modules_lock:
451
+ return sys.modules[module_name]
452
+ except Exception as ex:
453
+ pass
454
+ raise intersystems_iris._GatewayException._GatewayException("Module not found: " + module_name)
455
+ else:
456
+ for module in self._thread_modules:
457
+ try:
458
+ class_object = getattr(self._thread_modules[module], class_name_short)
459
+ if module_name == None:
460
+ return class_object
461
+ if class_object.__module__ == module_name:
462
+ return class_object
463
+ except Exception as ex:
464
+ pass
465
+ with self._sys_modules_lock:
466
+ for module in sys.modules:
467
+ try:
468
+ class_object = getattr(sys.modules[module], class_name_short)
469
+ if module_name == None:
470
+ return class_object
471
+ if class_object.__module__ == module_name:
472
+ return class_object
473
+ except Exception as ex:
474
+ pass
475
+ raise intersystems_iris._GatewayException._GatewayException("Class not found: " + class_name)
476
+ return
477
+
478
+ def __find_method(self, class_object, method_name):
479
+ try:
480
+ return getattr(class_object, method_name)
481
+ except BaseException as e:
482
+ raise intersystems_iris._GatewayException._GatewayException("Method not found: " + method_name)
483
+
484
+ def __get_method_hints(self, method_object, cardinality):
485
+ hints = [object]*cardinality
486
+ try:
487
+ pointer = 0
488
+ params = inspect.signature(method_object).parameters
489
+ for key in params:
490
+ if pointer >= cardinality:
491
+ break
492
+ if key == "self":
493
+ continue
494
+ if params[key].kind == inspect.Parameter.POSITIONAL_ONLY or params[key].kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
495
+ hints[pointer] = params[key].annotation
496
+ pointer += 1
497
+ continue
498
+ if params[key].kind == inspect.Parameter.VAR_POSITIONAL:
499
+ while (pointer<cardinality):
500
+ hints[pointer] = params[key].annotation
501
+ pointer += 1
502
+ break
503
+ except Exception as ex:
504
+ pass
505
+ for i in range(len(hints)):
506
+ if not self._is_datatype(hints[i]) and hints[i] != intersystems_iris.IRISList:
507
+ hints[i] = object
508
+ return hints
509
+
510
+ def __disconnect(self):
511
+ sequence_number = self.in_message.wire._get_header_count();
512
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_DISCONNECT)
513
+ self.out_message_sequence_number = sequence_number
514
+
515
+ def __shutdown(self):
516
+ self._device.close()
517
+ os._exit(0)
518
+
519
+ def __ping(self):
520
+ sequence_number = self.in_message.wire._get_header_count();
521
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_PING)
522
+ self.out_message.wire._set(self._server_name)
523
+ self.out_message_sequence_number = sequence_number
524
+
525
+ def __benchmark_echo(self):
526
+ sequence_number = self.in_message.wire._get_header_count();
527
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_BENCHMARK_ECHO)
528
+ self.out_message_sequence_number = sequence_number
529
+
530
+ def __load_modules(self):
531
+ sequence_number = self.in_message.wire._get_header_count();
532
+ try:
533
+ module_count = self.in_message.wire._get()
534
+ process_wide = False
535
+ if type(module_count)==str and module_count.endswith(":system"):
536
+ module_count = int(module_count[0:-7])
537
+ process_wide = True
538
+ for i in range(module_count):
539
+ self.__load_one_module(self.in_message.wire._get(), process_wide)
540
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_LOAD_MODULES)
541
+ self.out_message_sequence_number = sequence_number
542
+ return
543
+ except Exception as ex:
544
+ self.__process_exception(ex, sequence_number)
545
+ return
546
+
547
+ def __dynamic_execute_constructor(self):
548
+ sequence_number = self.in_message.wire._get_header_count();
549
+ try:
550
+ closed_proxy_count = int(self.in_message.wire._get())
551
+ for i in range(closed_proxy_count):
552
+ closed_oref = self.in_message.wire._get()
553
+ del self._connection._oref_registry[closed_oref]
554
+ oref = self.in_message.wire._get()
555
+ class_name = self.in_message.wire._get()
556
+ cardinality = self.in_message.wire._get()
557
+ if class_name == "[]":
558
+ args = self.__unmarshal_parameters(cardinality, [object]*cardinality)
559
+ instance = args
560
+ elif class_name == "()":
561
+ args = self.__unmarshal_parameters(cardinality, [object]*cardinality)
562
+ instance = tuple(args)
563
+ elif class_name == "{}":
564
+ args = self.__unmarshal_parameters(cardinality, [object]*cardinality)
565
+ instance = set(args)
566
+ else:
567
+ class_object = self._load_class(class_name)
568
+ constructor_object = self.__find_method(class_object, "__init__")
569
+ hints = self.__get_method_hints(constructor_object, cardinality)
570
+ args = self.__unmarshal_parameters(cardinality, hints)
571
+ instance = class_object(*args)
572
+ self._connection._oref_registry[oref] = instance
573
+ self._connection._oref_to_class_map[oref] = class_name
574
+ self.__release_closed_iris_object()
575
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_DYNAMIC_EXECUTE_CONSTRUCTOR)
576
+ self.out_message.wire._set("end")
577
+ self.__redirect_output()
578
+ self.out_message_sequence_number = sequence_number
579
+ return
580
+ except Exception as ex:
581
+ self.__process_exception(ex, sequence_number)
582
+ return
583
+
584
+ def __dynamic_execute_method(self):
585
+ sequence_number = self.in_message.wire._get_header_count();
586
+ map_listream = False
587
+ try:
588
+ closed_proxy_count = int(self.in_message.wire._get())
589
+ for i in range(closed_proxy_count):
590
+ closed_oref = self.in_message.wire._get()
591
+ del self._connection._oref_registry[closed_oref]
592
+ oref_or_class_name = self.in_message.wire._get()
593
+ method_name = self.in_message.wire._get()
594
+ cardinality = int(self.in_message.wire._get())
595
+ if oref_or_class_name == "**Utility**":
596
+ oref_or_class_name = "iris._GatewayUtility._GatewayUtility"
597
+ if oref_or_class_name == None:
598
+ # built-in function when oref_or_class_name is None
599
+ function_object = getattr(sys.modules["builtins"],method_name)
600
+ hints = self.__get_method_hints(function_object, cardinality)
601
+ args = self.__unmarshal_parameters(cardinality, hints)
602
+ return_value = function_object(*args)
603
+ elif "@" in oref_or_class_name:
604
+ # instance method
605
+ instance = self._connection._oref_registry[oref_or_class_name]
606
+ if method_name.startswith("%"):
607
+ # special methods: %get, %set, %getall, %setall
608
+ if method_name == "%get":
609
+ if cardinality != 1:
610
+ raise intersystems_iris._GatewayException._GatewayException("Method not found: %get(" + str(cardinality) + ")")
611
+ key = self.in_message.wire._get()
612
+ if type(instance) == bytes or type(instance) == bytearray:
613
+ return_value = instance[key:key+1].decode()
614
+ else:
615
+ return_value = instance[key]
616
+ elif method_name == "%set":
617
+ if cardinality != 2:
618
+ raise intersystems_iris._GatewayException._GatewayException("Method not found: %set(" + str(cardinality) + ")")
619
+ args = self.__unmarshal_parameters(cardinality, [object]*cardinality)
620
+ try:
621
+ if type(instance) == bytes or type(instance) == bytearray:
622
+ return_value = instance[args[0]:args[0]+1].decode()
623
+ else:
624
+ return_value = instance[args[0]]
625
+ except (IndexError, KeyError):
626
+ return_value = None
627
+ if type(instance) == bytes or type(instance) == bytearray:
628
+ instance[args[0]] = ord(args[1][0])
629
+ else:
630
+ instance[args[0]] = args[1]
631
+ elif method_name == "%getall":
632
+ if cardinality != 0:
633
+ raise intersystems_iris._GatewayException._GatewayException("Method not found: %getall(" + str(cardinality) + ")")
634
+ if type(instance) != bytes and type(instance) != bytearray and type(instance) != list and type(instance) != tuple:
635
+ raise intersystems_iris._GatewayException._GatewayException("Object is not a list or byte array")
636
+ return_value = instance
637
+ map_listream = True
638
+ elif method_name == "%setall":
639
+ if cardinality != 1:
640
+ raise intersystems_iris._GatewayException._GatewayException("Method not found: %setall(" + str(cardinality) + ")")
641
+ value = self.in_message.wire._get()
642
+ if not isinstance(value, intersystems_iris._IRISOREF._IRISOREF):
643
+ raise intersystems_iris._GatewayException._GatewayException("Argument for %setall(" + str(cardinality) + ") is invalid")
644
+ self._connection._close_unused_oref(value._oref)
645
+ new_listream = self._connection._get_parameter_listream(self.in_message_secondary, self.out_message_secondary, value._oref, instance)
646
+ return_value = None
647
+ elif method_name == "%len":
648
+ return_value = len(instance)
649
+ else:
650
+ raise intersystems_iris._GatewayException._GatewayException("Method not found: " + method_name)
651
+ else:
652
+ # process non-special instance method
653
+ method_object = getattr(instance, method_name)
654
+ hints = self.__get_method_hints(method_object, cardinality)
655
+ args = self.__unmarshal_parameters(cardinality, hints)
656
+ return_value = method_object(*args)
657
+ else:
658
+ # static method
659
+ class_object = self._load_class(oref_or_class_name)
660
+ method_object = self.__find_method(class_object, method_name)
661
+ hints = self.__get_method_hints(method_object, cardinality)
662
+ args = self.__unmarshal_parameters(cardinality, hints)
663
+ return_value = method_object(*args)
664
+ self.__release_closed_iris_object()
665
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_DYNAMIC_EXECUTE_METHOD)
666
+ self.__marshal_return_value(return_value, map_listream)
667
+ self.out_message.wire._set("end")
668
+ self.__redirect_output()
669
+ self.out_message_sequence_number = sequence_number
670
+ return
671
+ except Exception as ex:
672
+ self.__process_exception(ex, sequence_number)
673
+ return
674
+
675
+ def __dynamic_execute_get(self):
676
+ sequence_number = self.in_message.wire._get_header_count();
677
+ try:
678
+ closed_proxy_count = int(self.in_message.wire._get())
679
+ for x in range(closed_proxy_count):
680
+ closed_oref = self.in_message.wire._get()
681
+ del self._connection._oref_registry[closed_oref]
682
+ oref_or_class_name = self.in_message.wire._get()
683
+ property_name = self.in_message.wire._get()
684
+ if "@" in oref_or_class_name:
685
+ instance = self._connection._oref_registry[oref_or_class_name]
686
+ return_value = getattr(instance, property_name)
687
+ else:
688
+ class_object = self._load_class(oref_or_class_name)
689
+ return_value = getattr(class_object, property_name)
690
+ self.__release_closed_iris_object()
691
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_DYNAMIC_EXECUTE_GET)
692
+ self.__marshal_return_value(return_value, False)
693
+ self.__redirect_output()
694
+ self.out_message_sequence_number = sequence_number
695
+ return
696
+ except Exception as ex:
697
+ self.__process_exception(ex, sequence_number)
698
+ return
699
+
700
+ def __dynamic_execute_set(self):
701
+ sequence_number = self.in_message.wire._get_header_count();
702
+ try:
703
+ closed_proxy_count = int(self.in_message.wire._get())
704
+ for x in range(closed_proxy_count):
705
+ closed_oref = self.in_message.wire._get()
706
+ del self._connection._oref_registry[closed_oref]
707
+ oref_or_class_name = self.in_message.wire._get()
708
+ property_name = self.in_message.wire._get()
709
+ args = self.__unmarshal_parameters(1,[object])
710
+ property_value = args[0]
711
+ if "@" in oref_or_class_name:
712
+ instance = self._connection._oref_registry[oref_or_class_name]
713
+ setattr(instance, property_name, property_value)
714
+ else:
715
+ class_object = self._load_class(oref_or_class_name)
716
+ setattr(class_object, property_name, property_value)
717
+ self.__release_closed_iris_object()
718
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_DYNAMIC_EXECUTE_SET)
719
+ self.__redirect_output()
720
+ self.out_message_sequence_number = sequence_number
721
+ return
722
+ except Exception as ex:
723
+ self.__process_exception(ex, sequence_number)
724
+ return
725
+
726
+ def __redirect_output(self):
727
+ if not self._connection._disable_output_redirect and self._output_redirect._was_written_to():
728
+ self.out_message.wire._set(self._output_redirect._get_buffer_contents())
729
+ else:
730
+ self.out_message.wire._set_undefined()
731
+ if not self._connection._disable_output_redirect and self._error_redirect._was_written_to():
732
+ self.out_message.wire._set(self._error_redirect._get_buffer_contents())
733
+ else:
734
+ self.out_message.wire._set_undefined()
735
+ return
736
+
737
+ def __process_exception(self, ex, sequence_number):
738
+ self.out_message.wire._write_header(intersystems_iris._Constant._Constant.MESSAGE_EXCEPTION_RAISED)
739
+ stack_string = traceback.format_exc()
740
+ stack_list = stack_string.split("\n")
741
+ stack_list.pop(0) # remove first line whic is always 'Traceback (most recent call last):'
742
+ stack_list.pop(-1) # remove last line which is always blank
743
+ # reverse the stack list, add module name before the exception name
744
+ error_text = ex.__class__.__module__ + "." + "\n".join(reversed(stack_list))
745
+ self.out_message.wire._set(error_text)
746
+ self.out_message_sequence_number = sequence_number
747
+ return
748
+
749
+ def __unmarshal_parameters(self, cardinality, hints):
750
+ args = [None]*cardinality
751
+ for i in range(cardinality):
752
+ args[i] = self.__unmarshal_one_parameter(hints[i])
753
+ return args
754
+
755
+ def __unmarshal_one_parameter(self, hint):
756
+ asBytes = hint != str and hint != object
757
+ value = self.in_message.wire._get(asBytes, True)
758
+ if type(value) == intersystems_iris._IRISOREF._IRISOREF:
759
+ if hint == object:
760
+ return self._connection._map_local_object_from_oref(value._oref)
761
+ else:
762
+ self._connection._close_unused_oref(value._oref)
763
+ value = value._oref
764
+ mode = intersystems_iris.IRIS.MODE_RUNTIME
765
+ locale = self._connection._connection_info._locale
766
+ is_unicode = self._connection._connection_info._is_unicode
767
+ if hint == bool:
768
+ return intersystems_iris.IRIS._convertToBoolean(value, mode, locale)
769
+ pass
770
+ if hint == bytes:
771
+ return intersystems_iris.IRIS._convertToBytes(value, mode, locale, is_unicode)
772
+ if hint == float:
773
+ return intersystems_iris.IRIS._convertToFloat(value, mode, locale)
774
+ if hint == int:
775
+ return intersystems_iris.IRIS._convertToInteger(value, mode, locale)
776
+ if hint == str:
777
+ return intersystems_iris.IRIS._convertToString(value, mode, locale)
778
+ if hint == decimal.Decimal:
779
+ return intersystems_iris.IRIS._convertToDecimal(value, mode, locale)
780
+ if hint == intersystems_iris.IRISList:
781
+ value = intersystems_iris.IRIS._convertToBytes(value, mode, locale, is_unicode)
782
+ return None if value is None else intersystems_iris.IRISList(value, locale, self._connection._connection_info._is_unicode, self._connection._connection_info._compact_double)
783
+ if hint == object:
784
+ return value
785
+ else:
786
+ raise TypeError("unrecognized argument hint type")
787
+
788
+ def __marshal_return_value(self, return_value, map_listream):
789
+ if map_listream:
790
+ self.__marshal_listream_return_value(return_value)
791
+ return
792
+ if self._is_datatype(type(return_value)):
793
+ self.out_message.wire._set("value")
794
+ self.out_message.wire._set(return_value, True)
795
+ elif type(return_value) == intersystems_iris.IRISList:
796
+ self.out_message.wire._set("value")
797
+ self.out_message.wire._set(return_value.getBuffer())
798
+ else:
799
+ oref = self._connection._oref_registry_lookup(return_value);
800
+ if oref is None:
801
+ oref = self._connection._map_local_object_to_oref(self.in_message_secondary, self.out_message_secondary, return_value);
802
+ self.out_message.wire._set("object");
803
+ self.out_message.wire._set(oref);
804
+ return
805
+
806
+ def __marshal_listream_return_value(self, return_value):
807
+ if type(return_value) == bytes or type(return_value) == bytearray:
808
+ self.out_message.wire._set("bstream")
809
+ self.out_message.wire._set(len(return_value))
810
+ stream_size = len(return_value)
811
+ pointer = 0
812
+ chunk_size = 3000000
813
+ while (pointer < stream_size):
814
+ this_length = stream_size - pointer
815
+ if this_length>chunk_size:
816
+ this_length = chunk_size
817
+ self.out_message.wire._set(return_value[pointer:pointer+this_length])
818
+ pointer = pointer + this_length
819
+ else:
820
+ self.out_message.wire._set("mlist")
821
+ self.out_message.wire._set(len(return_value))
822
+ for v in return_value:
823
+ if self._is_datatype(type(v)):
824
+ self.out_message.wire._set_null()
825
+ self.out_message.wire._set(v)
826
+ else:
827
+ oref = self._connection._oref_registry_lookup(v);
828
+ if oref is None:
829
+ oref = self._connection._map_local_object_to_oref(self.in_message_secondary, self.out_message_secondary, v);
830
+ self.out_message.wire._set("obj");
831
+ self.out_message.wire._set(oref);
832
+ return
833
+
834
+ def __release_closed_iris_object(self):
835
+ if len(self._connection._iris_object_proxy_closed) > intersystems_iris.IRISConnection.CLOSED_PROXY_UPDATE_THRESHOLD:
836
+ native = intersystems_iris.GatewayContext.getIRIS()
837
+ native._release_closed_iris_object
838
+
839
+ @staticmethod
840
+ def _is_datatype(value_type):
841
+ switcher = {
842
+ type(None): True,
843
+ bool: True,
844
+ bytes: True,
845
+ int: True,
846
+ float: True,
847
+ str: True,
848
+ decimal.Decimal: True
849
+ }
850
+ return switcher.get(value_type, False)