iris-pex-embedded-python 2.3.25b2__py3-none-any.whl → 3.2.1b2__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.

Potentially problematic release.


This version of iris-pex-embedded-python might be problematic. Click here for more details.

Files changed (85) hide show
  1. grongier/cls/Grongier/PEX/BusinessOperation.cls +1 -28
  2. grongier/cls/Grongier/PEX/BusinessProcess.cls +1 -101
  3. grongier/cls/Grongier/PEX/BusinessService.cls +1 -28
  4. grongier/cls/Grongier/PEX/Common.cls +1 -194
  5. grongier/cls/Grongier/PEX/Director.cls +1 -48
  6. grongier/cls/Grongier/PEX/Duplex/Operation.cls +1 -26
  7. grongier/cls/Grongier/PEX/Duplex/Process.cls +1 -217
  8. grongier/cls/Grongier/PEX/Duplex/Service.cls +1 -6
  9. grongier/cls/Grongier/PEX/InboundAdapter.cls +1 -15
  10. grongier/cls/Grongier/PEX/Message.cls +1 -116
  11. grongier/cls/Grongier/PEX/OutboundAdapter.cls +1 -29
  12. grongier/cls/Grongier/PEX/PickleMessage.cls +1 -46
  13. grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +1 -253
  14. grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +1 -19
  15. grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +1 -19
  16. grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +1 -19
  17. grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +1 -35
  18. grongier/cls/Grongier/PEX/Test.cls +1 -53
  19. grongier/cls/Grongier/PEX/Utils.cls +1 -365
  20. grongier/cls/Grongier/Service/WSGI.cls +1 -307
  21. grongier/pex/__init__.py +11 -11
  22. grongier/pex/__main__.py +1 -1
  23. grongier/pex/_business_host.py +1 -481
  24. grongier/pex/_cli.py +2 -150
  25. grongier/pex/_common.py +1 -347
  26. grongier/pex/_director.py +1 -286
  27. grongier/pex/_utils.py +1 -369
  28. intersystems_iris/_ConnectionInformation.py +22 -20
  29. intersystems_iris/dbapi/_DBAPI.py +6 -1
  30. intersystems_iris/dbapi/_ResultSetRow.py +26 -15
  31. intersystems_iris/dbapi/preparser/_PreParser.py +4 -1
  32. iop/__init__.py +24 -0
  33. iop/__main__.py +4 -0
  34. iop/_business_host.py +675 -0
  35. iop/_business_operation.py +71 -0
  36. iop/_business_process.py +220 -0
  37. {grongier/pex → iop}/_business_service.py +2 -2
  38. iop/_cli.py +141 -0
  39. iop/_common.py +352 -0
  40. iop/_director.py +301 -0
  41. {grongier/pex → iop}/_inbound_adapter.py +1 -1
  42. iop/_log_manager.py +81 -0
  43. {grongier/pex → iop}/_message.py +1 -1
  44. {grongier/pex → iop}/_outbound_adapter.py +1 -1
  45. {grongier/pex → iop}/_private_session_duplex.py +4 -3
  46. {grongier/pex → iop}/_private_session_process.py +2 -2
  47. iop/_utils.py +458 -0
  48. iop/cls/IOP/BusinessOperation.cls +35 -0
  49. iop/cls/IOP/BusinessProcess.cls +124 -0
  50. iop/cls/IOP/BusinessService.cls +35 -0
  51. iop/cls/IOP/Common.cls +344 -0
  52. iop/cls/IOP/Director.cls +62 -0
  53. iop/cls/IOP/Duplex/Operation.cls +29 -0
  54. iop/cls/IOP/Duplex/Process.cls +229 -0
  55. iop/cls/IOP/Duplex/Service.cls +9 -0
  56. iop/cls/IOP/InboundAdapter.cls +22 -0
  57. iop/cls/IOP/Message/JSONSchema.cls +125 -0
  58. iop/cls/IOP/Message.cls +729 -0
  59. iop/cls/IOP/OutboundAdapter.cls +36 -0
  60. iop/cls/IOP/PickleMessage.cls +58 -0
  61. iop/cls/IOP/PrivateSession/Duplex.cls +260 -0
  62. iop/cls/IOP/PrivateSession/Message/Ack.cls +32 -0
  63. iop/cls/IOP/PrivateSession/Message/Poll.cls +32 -0
  64. iop/cls/IOP/PrivateSession/Message/Start.cls +32 -0
  65. iop/cls/IOP/PrivateSession/Message/Stop.cls +48 -0
  66. iop/cls/IOP/Service/WSGI.cls +310 -0
  67. iop/cls/IOP/Test.cls +85 -0
  68. iop/cls/IOP/Utils.cls +378 -0
  69. iop/wsgi/handlers.py +104 -0
  70. iris_pex_embedded_python-3.2.1b2.dist-info/METADATA +90 -0
  71. iris_pex_embedded_python-3.2.1b2.dist-info/RECORD +139 -0
  72. {iris_pex_embedded_python-2.3.25b2.dist-info → iris_pex_embedded_python-3.2.1b2.dist-info}/WHEEL +1 -1
  73. iris_pex_embedded_python-3.2.1b2.dist-info/entry_points.txt +2 -0
  74. {iris_pex_embedded_python-2.3.25b2.dist-info → iris_pex_embedded_python-3.2.1b2.dist-info}/top_level.txt +1 -1
  75. grongier/pex/_business_operation.py +0 -70
  76. grongier/pex/_business_process.py +0 -215
  77. iris/__init__.py +0 -60
  78. iris/__init__.pyi +0 -236
  79. iris/iris_ipm.py +0 -40
  80. iris/iris_ipm.pyi +0 -17
  81. iris_pex_embedded_python-2.3.25b2.dist-info/METADATA +0 -1384
  82. iris_pex_embedded_python-2.3.25b2.dist-info/RECORD +0 -113
  83. iris_pex_embedded_python-2.3.25b2.dist-info/entry_points.txt +0 -2
  84. {grongier/pex → iop}/_pickle_message.py +0 -0
  85. {iris_pex_embedded_python-2.3.25b2.dist-info → iris_pex_embedded_python-3.2.1b2.dist-info}/LICENSE +0 -0
grongier/pex/_utils.py CHANGED
@@ -1,369 +1 @@
1
- import os
2
- import ast
3
- import iris
4
- import inspect
5
- import xmltodict
6
- import pkg_resources
7
-
8
- class _Utils():
9
- @staticmethod
10
- def raise_on_error(sc):
11
- """
12
- If the status code is an error, raise an exception
13
-
14
- :param sc: The status code returned by the Iris API
15
- """
16
- if iris.system.Status.IsError(sc):
17
- raise RuntimeError(iris.system.Status.GetOneStatusText(sc))
18
-
19
- @staticmethod
20
- def setup(path:str = None):
21
-
22
- if path is None:
23
- # get the path of the data folder with pkg_resources
24
- path = pkg_resources.resource_filename('grongier', 'cls')
25
-
26
- _Utils.raise_on_error(iris.cls('%SYSTEM.OBJ').LoadDir(path,'cubk',"*.cls",1))
27
-
28
- @staticmethod
29
- def register_component(module:str,classname:str,path:str,overwrite:int=1,iris_classname:str='Python'):
30
- """
31
- It registers a component in the Iris database.
32
-
33
- :param module: The name of the module that contains the class
34
- :type module: str
35
- :param classname: The name of the class you want to register
36
- :type classname: str
37
- :param path: The path to the component
38
- :type path: str
39
- :param overwrite: 0 = no, 1 = yes
40
- :type overwrite: int
41
- :param iris_classname: The name of the class in the Iris class hierarchy
42
- :type iris_classname: str
43
- :return: The return value is a string.
44
- """
45
- path = os.path.normpath(path)
46
- # get the absolute path of the folder
47
- path = os.path.abspath(path)
48
- return iris.cls('Grongier.PEX.Utils').dispatchRegisterComponent(module,classname,path,overwrite,iris_classname)
49
-
50
- @staticmethod
51
- def register_folder(path:str,overwrite:int=1,iris_package_name:str='Python'):
52
- """
53
- > This function takes a path to a folder, and registers all the Python files in that folder as IRIS
54
- classes
55
-
56
- :param path: the path to the folder containing the files you want to register
57
- :type path: str
58
- :param overwrite:
59
- :type overwrite: int
60
- :param iris_package_name: The name of the iris package you want to register the file to
61
- :type iris_package_name: str
62
- """
63
- path = os.path.normpath(path)
64
- # get the absolute path of the folder
65
- path = os.path.abspath(path)
66
- for filename in os.listdir(path):
67
- if filename.endswith(".py"):
68
- _Utils._register_file(filename, path, overwrite, iris_package_name)
69
- else:
70
- continue
71
-
72
- @staticmethod
73
- def register_file(file:str,overwrite:int=1,iris_package_name:str='Python'):
74
- """
75
- It takes a file name, a boolean to overwrite existing components, and the name of the Iris
76
- package that the file is in. It then opens the file, parses it, and looks for classes that extend
77
- BusinessOperation, BusinessProcess, or BusinessService. If it finds one, it calls register_component
78
- with the module name, class name, path, overwrite boolean, and the full Iris package name
79
-
80
- :param file: the name of the file containing the component
81
- :type file: str
82
- :param overwrite: if the component already exists, overwrite it
83
- :type overwrite: int
84
- :param iris_package_name: the name of the iris package that you want to register the components to
85
- :type iris_package_name: str
86
- """
87
- head_tail = os.path.split(file)
88
- return _Utils._register_file(head_tail[1],head_tail[0],overwrite,iris_package_name)
89
-
90
- @staticmethod
91
- def _register_file(filename:str,path:str,overwrite:int=1,iris_package_name:str='Python'):
92
- """
93
- It takes a file name, a path, a boolean to overwrite existing components, and the name of the Iris
94
- package that the file is in. It then opens the file, parses it, and looks for classes that extend
95
- BusinessOperation, BusinessProcess, or BusinessService. If it finds one, it calls register_component
96
- with the module name, class name, path, overwrite boolean, and the full Iris package name
97
-
98
- :param filename: the name of the file containing the component
99
- :type filename: str
100
- :param path: the path to the directory containing the files to be registered
101
- :type path: str
102
- :param overwrite: if the component already exists, overwrite it
103
- :type overwrite: int
104
- :param iris_package_name: the name of the iris package that you want to register the components to
105
- :type iris_package_name: str
106
- """
107
- #pour chaque classe dans le module, appeler register_component
108
- f = os.path.join(path,filename)
109
- with open(f) as file:
110
- node = ast.parse(file.read())
111
- #list of class in the file
112
- classes = [n for n in node.body if isinstance(n, ast.ClassDef)]
113
- for klass in classes:
114
- extend = ''
115
- if len(klass.bases) == 1:
116
- if hasattr(klass.bases[0],'id'):
117
- extend = klass.bases[0].id
118
- else:
119
- extend = klass.bases[0].attr
120
- if extend in ('BusinessOperation','BusinessProcess','BusinessService','DuplexService','DuplexProcess','DuplexOperation','InboundAdapter','OutboundAdapter'):
121
- module = _Utils.filename_to_module(filename)
122
- iris_class_name = f"{iris_package_name}.{module}.{klass.name}"
123
- # strip "_" for iris class name
124
- iris_class_name = iris_class_name.replace('_','')
125
- _Utils.register_component(module, klass.name, path, overwrite, iris_class_name)
126
- @staticmethod
127
- def register_package(package:str,path:str,overwrite:int=1,iris_package_name:str='Python'):
128
- """
129
- It takes a package name, a path to the package, a flag to overwrite existing files, and the name of
130
- the iris package to register the files to. It then loops through all the files in the package and
131
- registers them to the iris package
132
-
133
- :param package: the name of the package you want to register
134
- :type package: str
135
- :param path: the path to the directory containing the package
136
- :type path: str
137
- :param overwrite: 0 = don't overwrite, 1 = overwrite
138
- :type overwrite: int
139
- :param iris_package_name: The name of the package in the Iris package manager
140
- :type iris_package_name: str
141
- """
142
- for filename in os.listdir(os.path.join(path,package)):
143
- if filename.endswith(".py"):
144
- _Utils._register_file(filename, os.path.join(path,package), overwrite, iris_package_name)
145
- else:
146
- continue
147
-
148
- @staticmethod
149
- def filename_to_module(filename) -> str:
150
- """
151
- It takes a filename and returns the module name
152
-
153
- :param filename: The name of the file to be imported
154
- :return: The module name
155
- """
156
- module = ''
157
-
158
- path,file = os.path.split(filename)
159
- mod = file.split('.')[0]
160
- packages = path.replace(os.sep, ('.'))
161
- if len(packages) >1:
162
- module = packages+'.'+mod
163
- else:
164
- module = mod
165
-
166
- return module
167
-
168
- @staticmethod
169
- def migrate(filename=None,root_path=None):
170
- """
171
- Read the settings.py file and register all the components
172
- settings.py file has two dictionaries:
173
- * CLASSES
174
- * key: the name of the class
175
- * value: an instance of the class
176
- * PRODUCTIONS
177
- list of dictionaries:
178
- * key: the name of the production
179
- * value: a dictionary containing the settings for the production
180
- """
181
- # try to load the settings file
182
- if filename:
183
- import sys
184
- path = None
185
- # check if the filename is absolute or relative
186
- if os.path.isabs(filename):
187
- path = os.path.dirname(filename)
188
- else:
189
- raise ValueError("The filename must be absolute")
190
- # add the path to the system path
191
- sys.path.append(path)
192
- import settings
193
- # get the path of the settings file
194
- path = os.path.dirname(inspect.getfile(settings))
195
- try:
196
- # set the classes settings
197
- _Utils.set_classes_settings(settings.CLASSES,path)
198
- except AttributeError:
199
- print("No classes to register")
200
- try:
201
- # set the productions settings
202
- _Utils.set_productions_settings(settings.PRODUCTIONS,path)
203
- except AttributeError:
204
- print("No productions to register")
205
-
206
-
207
-
208
- @staticmethod
209
- def set_classes_settings(class_items,root_path=None):
210
- """
211
- It takes a dictionary of classes and returns a dictionary of settings for each class
212
-
213
- :param class_items: a dictionary of classes
214
- :return: a dictionary of settings for each class
215
- """
216
- for key, value in class_items.items():
217
- if inspect.isclass(value):
218
- path = None
219
- if root_path:
220
- path = root_path
221
- else:
222
- path = os.path.dirname(inspect.getfile(value))
223
- _Utils.register_component(value.__module__,value.__name__,path,1,key)
224
- elif inspect.ismodule(value):
225
- path = None
226
- if root_path:
227
- path = root_path
228
- else:
229
- path = os.path.dirname(inspect.getfile(value))
230
- _Utils._register_file(value.__name__+'.py',path,1,key)
231
- # if the value is a dict
232
- elif isinstance(value,dict):
233
- # if the dict has a key 'path' and a key 'module' and a key 'class'
234
- if 'path' in value and 'module' in value and 'class' in value:
235
- # register the component
236
- _Utils.register_component(value['module'],value['class'],value['path'],1,key)
237
- # if the dict has a key 'path' and a key 'package'
238
- elif 'path' in value and 'package' in value:
239
- # register the package
240
- _Utils.register_package(value['package'],value['path'],1,key)
241
- # if the dict has a key 'path' and a key 'file'
242
- elif 'path' in value and 'file' in value:
243
- # register the file
244
- _Utils._register_file(value['file'],value['path'],1,key)
245
- # if the dict has a key 'path'
246
- elif 'path' in value:
247
- # register folder
248
- _Utils.register_folder(value['path'],1,key)
249
- else:
250
- raise ValueError(f"Invalid value for {key}.")
251
-
252
- @staticmethod
253
- def set_productions_settings(production_list,root_path=None):
254
- """
255
- It takes a list of dictionaries and registers the productions
256
- """
257
- # for each production in the list
258
- for production in production_list:
259
- # get the production name (first key in the dictionary)
260
- production_name = list(production.keys())[0]
261
- # set the first key to 'production'
262
- production['Production'] = production.pop(production_name)
263
- # handle Items
264
- production = _Utils.handle_items(production,root_path)
265
- # transform the json as an xml
266
- xml = _Utils.dict_to_xml(production)
267
- # register the production
268
- _Utils.register_production(production_name,xml)
269
-
270
- @staticmethod
271
- def handle_items(production,root_path=None):
272
- # if an item is a class, register it and replace it with the name of the class
273
- if 'Item' in production['Production']:
274
- # for each item in the list
275
- for i,item in enumerate(production['Production']['Item']):
276
- # if the attribute "@ClassName" is a class, register it and replace it with the name of the class
277
- if '@ClassName' in item:
278
- if inspect.isclass(item['@ClassName']):
279
- path = None
280
- if root_path:
281
- path = root_path
282
- else:
283
- path = os.path.dirname(inspect.getfile(item['@ClassName']))
284
- _Utils.register_component(item['@ClassName'].__module__,item['@ClassName'].__name__,path,1,item['@Name'])
285
- # replace the class with the name of the class
286
- production['Production']['Item'][i]['@ClassName'] = item['@Name']
287
- # if the attribute "@ClassName" is a dict
288
- elif isinstance(item['@ClassName'],dict):
289
- # create a new dict where the key is the name of the class and the value is the dict
290
- class_dict = {item['@Name']:item['@ClassName']}
291
- # pass the new dict to set_classes_settings
292
- _Utils.set_classes_settings(class_dict)
293
- # replace the class with the name of the class
294
- production['Production']['Item'][i]['@ClassName'] = item['@Name']
295
- else:
296
- raise ValueError(f"Invalid value for {item['@Name']}.")
297
-
298
- return production
299
-
300
- @staticmethod
301
- def dict_to_xml(json):
302
- """
303
- It takes a json and returns an xml
304
-
305
- :param json: a json
306
- :return: an xml
307
- """
308
- xml = xmltodict.unparse(json,pretty=True)
309
- # remove the xml version tag
310
- xml = xml.replace('<?xml version="1.0" encoding="utf-8"?>','')
311
- # remove the new line at the beginning of the xml
312
- xml = xml[1:]
313
- return xml
314
-
315
- @staticmethod
316
- def register_production(production_name,xml):
317
- """
318
- It takes a production name and an xml and registers the production
319
-
320
- :param production_name: the name of the production
321
- :type production_name: str
322
- :param xml: the xml of the production
323
- :type xml: str
324
- """
325
- # split the production name in the package name and the production name
326
- # the production name is the last part of the string
327
- package = '.'.join(production_name.split('.')[:-1])
328
- production_name = production_name.split('.')[-1]
329
- stream = _Utils.string_to_stream(xml)
330
- # register the production
331
- _Utils.raise_on_error(iris.cls('Grongier.PEX.Utils').CreateProduction(package,production_name,stream))
332
-
333
- @staticmethod
334
- def export_production(production_name):
335
- """
336
- It takes a production name and exports the production
337
-
338
- :param production_name: the name of the production
339
- :type production_name: str
340
- """
341
- def postprocessor(path, key, value):
342
- if value is None:
343
- return key, ''
344
- return key, value
345
- # export the production
346
- xdata = iris.cls('Grongier.PEX.Utils').ExportProduction(production_name)
347
- # for each chunk of 1024 characters
348
- string = _Utils.stream_to_string(xdata)
349
- # convert the xml to a dictionary
350
- data = xmltodict.parse(string,postprocessor=postprocessor)
351
- # return the dictionary
352
- return data
353
-
354
- @staticmethod
355
- def stream_to_string(stream)-> str:
356
- string = ""
357
- stream.Rewind()
358
- while not stream.AtEnd:
359
- string += stream.Read(4092)
360
- return string
361
-
362
- @staticmethod
363
- def string_to_stream(string:str):
364
- stream = iris.cls('%Stream.GlobalCharacter')._New()
365
- n = 4092
366
- chunks = [string[i:i+n] for i in range(0, len(string), n)]
367
- for chunk in chunks:
368
- stream.Write(chunk)
369
- return stream
1
+ from iop._utils import _Utils
@@ -1,7 +1,7 @@
1
1
  import intersystems_iris._Constant
2
2
 
3
- class _ConnectionInformation(object):
4
3
 
4
+ class _ConnectionInformation(object):
5
5
  def __init__(self):
6
6
  self.protocol_version = intersystems_iris._Constant._Constant.PROTOCOL_VERSION
7
7
  self._is_unicode = True
@@ -20,9 +20,10 @@ class _ConnectionInformation(object):
20
20
  def _parse_server_version(self, server_version):
21
21
  split_1 = server_version.split("|")
22
22
  self._server_version = split_1[0]
23
- if len(split_1)>1: self._iris_install_dir = split_1[1]
23
+ if len(split_1) > 1:
24
+ self._iris_install_dir = split_1[1]
24
25
  if self._server_version.find("Version") > 0:
25
- version = server_version[server_version.find("Version")+8:]
26
+ version = server_version[server_version.find("Version") + 8 :]
26
27
  self._server_version_major = version.split(".")[0]
27
28
  self._server_version_minor = version.split(".")[1]
28
29
  return
@@ -31,24 +32,25 @@ class _ConnectionInformation(object):
31
32
  def _map_server_locale(locale):
32
33
  # we need to map IRIS locale literals to Python locale literals
33
34
  _locales = {
34
- "LATIN1": "latin_1",
35
- "LATIN2": "iso8859_2",
36
- "LATINC": "iso8859_5",
37
- "LATINA": "iso8859_6",
38
- "LATING": "iso8859_7",
39
- "LATINH": "iso8859_8",
40
- "LATINT": "iso8859_11",
41
- "LATIN9": "iso8859_15",
42
- "CP1250": "cp1250",
43
- "CP1251": "cp1251",
44
- "CP1252": "cp1252",
45
- "CP1253": "cp1253",
46
- "CP1255": "cp1255",
47
- "CP1256": "cp1256",
48
- "CP1257": "cp1257",
49
- "CP874": "cp874",
35
+ "LATIN1": "latin_1",
36
+ "LATIN2": "iso8859_2",
37
+ "LATINC": "iso8859_5",
38
+ "LATINA": "iso8859_6",
39
+ "LATING": "iso8859_7",
40
+ "LATINH": "iso8859_8",
41
+ "LATINT": "iso8859_11",
42
+ "LATIN9": "iso8859_15",
43
+ "CP1250": "cp1250",
44
+ "CP1251": "cp1251",
45
+ "CP1252": "cp1252",
46
+ "CP1253": "cp1253",
47
+ "CP1255": "cp1255",
48
+ "CP1256": "cp1256",
49
+ "CP1257": "cp1257",
50
+ "CP874": "cp874",
50
51
  "UNICODE": "utf-8",
51
52
  }
52
53
  return _locales[locale.upper()] if locale.upper() in _locales else locale
53
54
 
54
-
55
+ def __repr__(self) -> str:
56
+ return f"<{self._server_version}>"
@@ -1,3 +1,4 @@
1
+ from typing import Union
1
2
  import struct
2
3
  import copy
3
4
  import enum
@@ -25,6 +26,7 @@ from ._SQLType import SQLType
25
26
 
26
27
  from .._IRISNative import connect as native_connect
27
28
  from .._IRISEmbedded import _IRISEmbedded
29
+ from intersystems_iris._IRISConnection import _IRISConnection
28
30
 
29
31
 
30
32
  def NotImplementedErrorDBAPI(msg=None):
@@ -42,7 +44,7 @@ def embedded_connect(*args, hostname=None, port=None, namespace=None, username=N
42
44
  return connection
43
45
 
44
46
 
45
- def connect(*args, embedded=False, hostname=None, port=None, namespace=None, username=None, password=None, **kw):
47
+ def connect(*args, embedded=False, hostname=None, port=None, namespace=None, username=None, password=None, **kw) -> Union[_IRISConnection, _IRISEmbedded]:
46
48
  try:
47
49
  if not embedded:
48
50
  return native_connect(
@@ -1180,6 +1182,8 @@ class Cursor(_BaseCursor):
1180
1182
  sets = self._parameter_sets or 1
1181
1183
  self.params = list(self.params).copy()
1182
1184
  param_types = [param.type for param in self._params._params_list]
1185
+ if not self.params:
1186
+ return
1183
1187
 
1184
1188
  for i in range(sets):
1185
1189
  params = self._params.collect(i)
@@ -2149,6 +2153,7 @@ class Cursor(_BaseCursor):
2149
2153
 
2150
2154
  if retval is None:
2151
2155
  return retval
2156
+ # print('retval', retval[:])
2152
2157
  return retval.as_tuple()
2153
2158
  # return tuple(retval[:])
2154
2159
 
@@ -1,5 +1,5 @@
1
1
  import uuid
2
- from datetime import datetime, date, time
2
+ from datetime import datetime, date, time, timezone
3
3
  from collections import namedtuple
4
4
  from ._SQLType import SQLType
5
5
  from .._DBList import _DBList
@@ -11,20 +11,26 @@ from ._Column import _Column
11
11
  def from_timestamp_posix(posix):
12
12
  time = int(posix)
13
13
  if time > 0:
14
- time ^= 0x1000000000000000
14
+ time ^= 0x1000000000000000
15
15
  else:
16
- time |= 0xF000000000000000
16
+ time |= 0xF000000000000000
17
17
 
18
18
  time /= 1000000
19
19
 
20
- value = datetime.utcfromtimestamp(time).replace(tzinfo=None)
20
+ value = datetime.fromtimestamp(time, timezone.utc).replace(tzinfo=None)
21
21
  return value
22
22
 
23
+
23
24
  class _ResultSetRow:
24
25
  _locale = "latin-1"
25
26
  _connection = None
26
27
 
27
- def __init__(self, connection, columns=None, rowcount=0, ):
28
+ def __init__(
29
+ self,
30
+ connection,
31
+ columns=None,
32
+ rowcount=0,
33
+ ):
28
34
  self._connection = connection
29
35
  # index from user-inputted columns to columns received from server
30
36
  self.col_index = []
@@ -55,7 +61,7 @@ class _ResultSetRow:
55
61
  self.colCount = len(columns) if columns != None else 0
56
62
 
57
63
  # number of columns received from server, aka number of items per row
58
- #self.colCount = rowcount
64
+ # self.colCount = rowcount
59
65
 
60
66
  # list of _ListItems corresponding to the various entries in the row, plus the offset of next row's first _ListItem
61
67
  self.rowItems = None
@@ -126,9 +132,9 @@ class _ResultSetRow:
126
132
 
127
133
  def get(self):
128
134
  return self[:]
129
-
135
+
130
136
  def as_tuple(self):
131
- row = namedtuple('Row', [col.name for col in self._columns], rename=True)
137
+ row = namedtuple("Row", [col.name for col in self._columns], rename=True)
132
138
  values = self[:]
133
139
  return row(*values)
134
140
 
@@ -164,15 +170,18 @@ class _ResultSetRow:
164
170
  HOROLOG_ORDINAL = date(1840, 12, 31).toordinal()
165
171
  if item:
166
172
  item = date.fromordinal(HOROLOG_ORDINAL + item)
173
+ if ctype == SQLType.TIMESTAMP and item:
174
+ item = item + '.000' if '.' not in item else item
175
+ item = datetime.strptime(item, '%Y-%m-%d %H:%M:%S.%f')
167
176
  if ctype == SQLType.TIME_HOROLOG:
168
177
  if item:
169
178
  item = time(item // 3600, item % 3600 // 60, item % 3600 % 60)
170
179
  if ctype == SQLType.GUID:
171
180
  item = uuid.UUID(item)
172
- if ctype == SQLType.TIMESTAMP_POSIX:
181
+ if ctype == SQLType.TIMESTAMP_POSIX and item:
173
182
  item = from_timestamp_posix(item)
174
183
 
175
- if _column.tableName == 'None' and _column.schema == 'None':
184
+ if _column.tableName == "None" and _column.schema == "None":
176
185
  # Ignore for anonymous tables
177
186
  pass
178
187
  elif item is None:
@@ -285,8 +294,9 @@ class _ResultSetRow:
285
294
  rowItems[i] = curr_offset
286
295
  prev_offset = curr_offset
287
296
  except IndexError:
288
- raise IndexError("Row incomplete: " + str(self.colCount) +
289
- " items expected, but " + str(i) + " were found")
297
+ raise IndexError(
298
+ "Row incomplete: " + str(self.colCount) + " items expected, but " + str(i) + " were found"
299
+ )
290
300
  self.update(rowItems)
291
301
  return True
292
302
 
@@ -319,8 +329,9 @@ class _ResultSetRow:
319
329
  rowItems[i] = curr_offset
320
330
  prev_offset = curr_offset
321
331
  except IndexError:
322
- raise IndexError("Row incomplete: " + str(self.colCount) +
323
- " items expected, but " + str(i) + " were found")
332
+ raise IndexError(
333
+ "Row incomplete: " + str(self.colCount) + " items expected, but " + str(i) + " were found"
334
+ )
324
335
  return self.update(rowItems)
325
336
 
326
337
  def update(self, rowItems):
@@ -330,7 +341,7 @@ class _ResultSetRow:
330
341
  colIndexOffsets[idx] = rowItems[i]
331
342
  colIndexOffsets[-1] = self._last_list_item.next_offset
332
343
  self.rowItems = colIndexOffsets
333
- return self.rowItems[:self.colCount]
344
+ return self.rowItems[: self.colCount]
334
345
  self.rowItems = rowItems
335
346
  self._offsets = self.DataRow(self)
336
347
  self._new_buffer = False
@@ -580,7 +580,10 @@ class _PreParser(object):
580
580
  break
581
581
  if token.TokenType is TOKEN.CONSTANT:
582
582
  values += '?'
583
- params += [token.Lexeme]
583
+ param = token.Lexeme
584
+ if param.__len__ and param[0] == "'" and param[0] == param[-1]:
585
+ param = param[1: -1]
586
+ params += [param]
584
587
  else:
585
588
  values += token.Lexeme
586
589
  values += ' '
iop/__init__.py ADDED
@@ -0,0 +1,24 @@
1
+ from iop._business_operation import _BusinessOperation
2
+ from iop._business_process import _BusinessProcess
3
+ from iop._business_service import _BusinessService
4
+ from iop._director import _Director
5
+ from iop._inbound_adapter import _InboundAdapter
6
+ from iop._message import _Message
7
+ from iop._outbound_adapter import _OutboundAdapter
8
+ from iop._pickle_message import _PickleMessage
9
+ from iop._private_session_duplex import _PrivateSessionDuplex
10
+ from iop._private_session_process import _PrivateSessionProcess
11
+ from iop._utils import _Utils
12
+
13
+ class Utils(_Utils): pass
14
+ class InboundAdapter(_InboundAdapter): pass
15
+ class OutboundAdapter(_OutboundAdapter): pass
16
+ class BusinessService(_BusinessService): pass
17
+ class BusinessOperation(_BusinessOperation): pass
18
+ class BusinessProcess(_BusinessProcess): pass
19
+ class DuplexService(_PrivateSessionDuplex): pass
20
+ class DuplexOperation(_PrivateSessionDuplex): pass
21
+ class DuplexProcess(_PrivateSessionProcess): pass
22
+ class Message(_Message): pass
23
+ class PickleMessage(_PickleMessage): pass
24
+ class Director(_Director): pass
iop/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ # main entry is _cli.main()
2
+ if __name__ == '__main__':
3
+ import iop._cli as _cli
4
+ _cli.main()