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
@@ -1,481 +1 @@
1
- import datetime
2
- import pickle
3
- import codecs
4
- import uuid
5
- import decimal
6
- import base64
7
- import json
8
- import importlib
9
- import iris
10
-
11
- from inspect import signature, getsource
12
-
13
- from dacite import from_dict, Config
14
-
15
- from grongier.pex._common import _Common
16
- from grongier.pex._utils import _Utils
17
-
18
- class _BusinessHost(_Common):
19
- """ This is a superclass for BusinessService, BusinesProcess, and BusinessOperation that
20
- defines common methods. It is a subclass of Common.
21
- """
22
-
23
- buffer:int = 64000
24
- DISPATCH = []
25
-
26
- def input_serialzer(fonction):
27
- """
28
- It takes a function as an argument, and returns a function that takes the same arguments as the
29
- original function, but serializes the arguments before passing them to the original function
30
-
31
- :param fonction: the function that will be decorated
32
- :return: The function dispatch_serializer is being returned.
33
- """
34
- def dispatch_serializer(self,*params, **param2):
35
- # Handle positional arguments
36
- serialized=[]
37
- for param in params:
38
- serialized.append(self._dispatch_serializer(param))
39
- # Handle keyword arguments
40
- for key, value in param2.items():
41
- param2[key] = self._dispatch_serializer(value)
42
- return fonction(self,*serialized, **param2)
43
- return dispatch_serializer
44
-
45
- def output_deserialzer(fonction):
46
- """
47
- It takes a function as an argument, and returns a function that takes the same arguments as the
48
- original function, but returns the result of the original function passed to the
49
- `_dispatch_deserializer` function
50
-
51
- :param fonction: the function that will be decorated
52
- :return: The function dispatch_deserializer is being returned.
53
- """
54
- def dispatch_deserializer(self,*params, **param2):
55
- return self._dispatch_deserializer(fonction(self,*params, **param2))
56
-
57
- return dispatch_deserializer
58
-
59
- def input_deserialzer(fonction):
60
- """
61
- It takes a function as input, and returns a function that takes the same arguments as the input
62
- function, but deserializes the arguments before passing them to the input function
63
-
64
- :param fonction: the function that will be decorated
65
- :return: The function dispatch_deserializer is being returned.
66
- """
67
- def dispatch_deserializer(self,*params, **param2):
68
- # Handle positional arguments
69
- serialized=[]
70
- for param in params:
71
- serialized.append(self._dispatch_deserializer(param))
72
- # Handle keyword arguments
73
- for key, value in param2.items():
74
- param2[key] = self._dispatch_deserializer(value)
75
- return fonction(self,*serialized, **param2)
76
- return dispatch_deserializer
77
-
78
- def output_serialzer(fonction):
79
- """
80
- It takes a function as an argument, and returns a function that takes the same arguments as the
81
- original function, and returns the result of the original function, after passing it through the
82
- _dispatch_serializer function
83
-
84
- :param fonction: The function that is being decorated
85
- :return: The function dispatch_serializer is being returned.
86
- """
87
- def dispatch_serializer(self,*params, **param2):
88
- return self._dispatch_serializer(fonction(self,*params, **param2))
89
- return dispatch_serializer
90
-
91
- @input_serialzer
92
- @output_deserialzer
93
- def send_request_sync(self, target, request, timeout=-1, description=None):
94
- """ Send the specified message to the target business process or business operation synchronously.
95
-
96
- Parameters:
97
- target: a string that specifies the name of the business process or operation to receive the request.
98
- The target is the name of the component as specified in the Item Name property in the production definition, not the class name of the component.
99
- request: specifies the message to send to the target. The request is either an instance of a class that is a subclass of Message class or of IRISObject class.
100
- If the target is a build-in ObjectScript component, you should use the IRISObject class. The IRISObject class enables the PEX framework to convert the message to a class supported by the target.
101
- timeout: an optional integer that specifies the number of seconds to wait before treating the send request as a failure. The default value is -1, which means wait forever.
102
- description: an optional string parameter that sets a description property in the message header. The default is None.
103
- Returns:
104
- the response object from target.
105
- Raises:
106
- TypeError: if request is not of type Message or IRISObject.
107
- """
108
-
109
- return self.iris_handle.dispatchSendRequestSync(target,request,timeout,description)
110
-
111
- @input_serialzer
112
- def send_request_async(self, target, request, description=None):
113
- """ Send the specified message to the target business process or business operation asynchronously.
114
- Parameters:
115
- target: a string that specifies the name of the business process or operation to receive the request.
116
- The target is the name of the component as specified in the Item Name property in the production definition, not the class name of the component.
117
- request: specifies the message to send to the target. The request is an instance of IRISObject or of a subclass of Message.
118
- If the target is a built-in ObjectScript component, you should use the IRISObject class. The IRISObject class enables the PEX framework to convert the message to a class supported by the target.
119
- description: an optional string parameter that sets a description property in the message header. The default is None.
120
-
121
- Raises:
122
- TypeError: if request is not of type Message or IRISObject.
123
- """
124
-
125
- return self.iris_handle.dispatchSendRequestAsync(target,request,description)
126
-
127
- def _serialize_pickle_message(self,message):
128
- """ Converts a python dataclass message into an iris grongier.pex.message.
129
-
130
- Parameters:
131
- message: The message to serialize, an instance of a class that is a subclass of Message.
132
-
133
- Returns:
134
- string: The message in json format.
135
- """
136
-
137
- pickle_string = codecs.encode(pickle.dumps(message), "base64").decode()
138
- module = message.__class__.__module__
139
- classname = message.__class__.__name__
140
-
141
- msg = iris.cls('Grongier.PEX.PickleMessage')._New()
142
- msg.classname = module + "." + classname
143
-
144
- stream = _Utils.string_to_stream(pickle_string)
145
- msg.jstr = stream
146
-
147
- return msg
148
-
149
-
150
- def _dispatch_serializer(self,message):
151
- """
152
- If the message is a message instance, serialize it as a message, otherwise, if it's a pickle message
153
- instance, serialize it as a pickle message, otherwise, return the message
154
-
155
- :param message: The message to be serialized
156
- :return: The serialized message
157
- """
158
- if (message is not None and self._is_message_instance(message)):
159
- return self._serialize_message(message)
160
- elif (message is not None and self._is_pickle_message_instance(message)):
161
- return self._serialize_pickle_message(message)
162
- elif (message is not None and self._is_iris_object_instance(message)):
163
- return message
164
- else:
165
- # todo : decorator takes care of all the parameters, so this should never happen
166
- return message
167
- #raise TypeError("The message must be an instance of a class that is a subclass of Message or IRISObject %Persistent class.")
168
-
169
- def _serialize_message(self,message):
170
- """ Converts a python dataclass message into an iris grongier.pex.message.
171
-
172
- Parameters:
173
- message: The message to serialize, an instance of a class that is a subclass of Message.
174
-
175
- Returns:
176
- string: The message in json format.
177
- """
178
- json_string = json.dumps(message, cls=IrisJSONEncoder, ensure_ascii=False)
179
- module = message.__class__.__module__
180
- classname = message.__class__.__name__
181
-
182
- msg = iris.cls('Grongier.PEX.Message')._New()
183
- msg.classname = module + "." + classname
184
-
185
- stream = _Utils.string_to_stream(json_string)
186
- msg.jstr = stream
187
-
188
- return msg
189
-
190
- def _deserialize_pickle_message(self,serial):
191
- """
192
- Converts an iris grongier.pex.message into an python dataclass message.
193
-
194
- """
195
- string = _Utils.stream_to_string(serial.jstr)
196
-
197
- msg = pickle.loads(codecs.decode(string.encode(), "base64"))
198
- return msg
199
-
200
- def _dispatch_deserializer(self,serial):
201
- """
202
- If the serialized object is a Message, deserialize it as a Message, otherwise deserialize it as a
203
- PickleMessage
204
-
205
- :param serial: The serialized object
206
- :return: The return value is a tuple of the form (serial, serial_type)
207
- """
208
- if (serial is not None and type(serial).__module__.find('iris') == 0) and serial._IsA("Grongier.PEX.Message"):
209
- return self._deserialize_message(serial)
210
- elif (serial is not None and type(serial).__module__.find('iris') == 0) and serial._IsA("Grongier.PEX.PickleMessage"):
211
- return self._deserialize_pickle_message(serial)
212
- else:
213
- return serial
214
-
215
- def _deserialize_message(self,serial):
216
- """
217
- Converts an iris grongier.pex.message into an python dataclass message.
218
- """
219
-
220
- if (serial.classname is None):
221
- raise ValueError("JSON message malformed, must include classname")
222
- classname = serial.classname
223
-
224
- j = classname.rindex(".")
225
- if (j <=0):
226
- raise ValueError("Classname must include a module: " + classname)
227
- try:
228
- module = importlib.import_module(classname[:j])
229
- msg = getattr(module, classname[j+1:])
230
- except Exception:
231
- raise ImportError("Class not found: " + classname)
232
-
233
- string = _Utils.stream_to_string(serial.jstr)
234
-
235
- jdict = json.loads(string, cls=IrisJSONDecoder)
236
- msg = self._dataclass_from_dict(msg,jdict)
237
- return msg
238
-
239
- def _dataclass_from_dict(self,klass, dikt):
240
- """
241
- > If the field is not in the dataclass, then add it as an attribute
242
-
243
- :param klass: The dataclass to convert to
244
- :param dikt: the dictionary to convert to a dataclass
245
- :return: A dataclass object with the fields of the dataclass and the fields of the dictionary.
246
- """
247
- ret = from_dict(klass, dikt, Config(check_types=False))
248
-
249
- try:
250
- fieldtypes = klass.__annotations__
251
- except Exception as e:
252
- fieldtypes = []
253
-
254
- for key,val in dikt.items():
255
- if key not in fieldtypes:
256
- setattr(ret, key, val)
257
- return ret
258
-
259
- def _dispach_message(self, request):
260
- """
261
- It takes a request object, and returns a response object
262
-
263
- :param request: The request object
264
- :return: The return value is the result of the method call.
265
- """
266
-
267
- call = 'on_message'
268
-
269
- module = request.__class__.__module__
270
- classname = request.__class__.__name__
271
-
272
- for msg,method in self.DISPATCH:
273
- if msg == module+"."+classname:
274
- call = method
275
-
276
- return getattr(self,call)(request)
277
-
278
-
279
- def _create_dispatch(self):
280
- """
281
- It creates a list of tuples, where each tuple contains the name of a class and the name of a method
282
- that takes an instance of that class as its only argument
283
- :return: A list of tuples.
284
- """
285
- if len(self.DISPATCH) == 0:
286
- #get all function in current BO
287
- method_list = [func for func in dir(self) if callable(getattr(self, func)) and not func.startswith("_")]
288
- for method in method_list:
289
- #get signature of current function
290
- try:
291
- param = signature(getattr(self, method)).parameters
292
- # Handle staticmethod
293
- except ValueError as e:
294
- param=''
295
- #one parameter
296
- if (len(param)==1):
297
- #get parameter type
298
- annotation = str(param[list(param)[0]].annotation)
299
- #trim annotation format <class 'toto'>
300
- i = annotation.find("'")
301
- j = annotation.rfind("'")
302
- #if end is not found
303
- if j == -1:
304
- j = None
305
- classname = annotation[i+1:j]
306
- self.DISPATCH.append((classname,method))
307
- return
308
-
309
- @staticmethod
310
- def OnGetConnections():
311
- """ The OnGetConnections() method returns all of the targets of any SendRequestSync or SendRequestAsync
312
- calls for the class. Implement this method to allow connections between components to show up in
313
- the interoperability UI.
314
-
315
- Returns:
316
- An IRISList containing all targets for this class. Default is None.
317
- """
318
- return None
319
-
320
- def SendRequestSync(self, target, request, timeout=-1, description=None):
321
- """ DEPRECATED : use send_request_sync
322
- `SendRequestSync` is a function that sends a request to a target and waits for a response
323
-
324
- :param target: The target of the request
325
- :param request: The request to send
326
- :param timeout: The timeout in seconds. If the timeout is negative, the default timeout will be used
327
- :param description: A string that describes the request. This is used for logging purposes
328
- :return: The return value is a tuple of (response, status).
329
- """
330
- return self.send_request_sync(target,request,timeout,description)
331
-
332
- def SendRequestAsync(self, target, request, description=None):
333
- """ DEPRECATED : use send_request_async
334
- It takes a target, a request, and a description, and returns a send_request_async function
335
-
336
- :param target: The target of the request. This is the name of the function you want to call
337
- :param request: The request to send
338
- :param description: A string that describes the request
339
- :return: The return value is a Future object.
340
- """
341
- return self.send_request_async(target,request,description)
342
-
343
- @staticmethod
344
- def getAdapterType():
345
- """ DEPRECATED : use get_adapter_type
346
- Name of the registred Adapter
347
- """
348
- return
349
-
350
- @staticmethod
351
- def get_adapter_type():
352
- """
353
- Name of the registred Adapter
354
- """
355
- return
356
-
357
- def on_get_connections(self) -> list:
358
- """
359
- The OnGetConnections() method returns all of the targets of any SendRequestSync or SendRequestAsync
360
- calls for the class. Implement this method to allow connections between components to show up in
361
- the interoperability UI.
362
-
363
- Returns:
364
- An IRISList containing all targets for this class. Default is None.
365
- """
366
- ## Parse the class code to find all invocations of send_request_sync and send_request_async
367
- ## and return the targets
368
- targer_list = []
369
- # get the source code of the class
370
- source = getsource(self.__class__)
371
- # find all invocations of send_request_sync and send_request_async
372
- for method in ['send_request_sync','send_request_async','SendRequestSync','SendRequestAsync']:
373
- i = source.find(method)
374
- while i != -1:
375
- j = source.find("(",i)
376
- if j != -1:
377
- k = source.find(",",j)
378
- if k != -1:
379
- target = source[j+1:k]
380
- if target.find("=") != -1:
381
- # it's a keyword argument, remove the keyword
382
- target = target[target.find("=")+1:].strip()
383
- if target not in targer_list:
384
- targer_list.append(target)
385
- i = source.find(method,i+1)
386
-
387
- for target in targer_list:
388
- # if target is a string, remove the quotes
389
- if target[0] == "'" and target[-1] == "'":
390
- targer_list[targer_list.index(target)] = target[1:-1]
391
- elif target[0] == '"' and target[-1] == '"':
392
- targer_list[targer_list.index(target)] = target[1:-1]
393
- # if target is a variable, try to find the value of the variable
394
- else:
395
- self.on_init()
396
- try:
397
- if target.find("self.") != -1:
398
- # it's a class variable
399
- targer_list[targer_list.index(target)] = getattr(self,target[target.find(".")+1:])
400
- elif target.find(".") != -1:
401
- # it's a class variable
402
- targer_list[targer_list.index(target)] = getattr(getattr(self,target[:target.find(".")]),target[target.find(".")+1:])
403
- else:
404
- targer_list[targer_list.index(target)] = getattr(self,target)
405
- except Exception as e:
406
- pass
407
-
408
- return targer_list
409
-
410
- # It's a subclass of the standard JSONEncoder class that knows how to encode date/time, decimal types,
411
- # and UUIDs.
412
- class IrisJSONEncoder(json.JSONEncoder):
413
- """
414
- JSONEncoder subclass that knows how to encode date/time, decimal types, and
415
- UUIDs.
416
- """
417
-
418
- def default(self, o):
419
- if o.__class__.__name__ == 'DataFrame':
420
- return 'dataframe:'+o.to_json(orient="table")
421
- elif isinstance(o, datetime.datetime):
422
- r = o.isoformat()
423
- if o.microsecond:
424
- r = r[:23] + r[26:]
425
- if r.endswith("+00:00"):
426
- r = r[:-6] + "Z"
427
- return 'datetime:'+r
428
- elif isinstance(o, datetime.date):
429
- return 'date:'+o.isoformat()
430
- elif isinstance(o, datetime.time):
431
- r = o.isoformat()
432
- if o.microsecond:
433
- r = r[:12]
434
- return 'time:'+r
435
- elif isinstance(o, decimal.Decimal):
436
- return 'decimal:'+str(o)
437
- elif isinstance(o, uuid.UUID):
438
- return 'uuid:'+str(o)
439
- elif isinstance(o, bytes):
440
- return 'bytes:'+base64.b64encode(o).decode("UTF-8")
441
- elif hasattr(o, '__dict__'):
442
- return o.__dict__
443
- else:
444
- return super().default(o)
445
-
446
- # It's a JSON decoder that looks for a colon in the value of a key/value pair. If it finds one, it
447
- # assumes the value is a string that represents a type and a value. It then converts the value to the
448
- # appropriate type
449
- class IrisJSONDecoder(json.JSONDecoder):
450
- def __init__(self, *args, **kwargs):
451
- json.JSONDecoder.__init__(
452
- self, object_hook=self.object_hook, *args, **kwargs)
453
-
454
- def object_hook(self, obj):
455
- ret = {}
456
- for key, value in obj.items():
457
- i = 0
458
- if isinstance(value, str):
459
- i = value.find(":")
460
- if (i>0):
461
- typ = value[:i]
462
- if typ == 'datetime':
463
- ret[key] = datetime.datetime.fromisoformat(value[i+1:])
464
- elif typ == 'date':
465
- ret[key] = datetime.date.fromisoformat(value[i+1:])
466
- elif typ == 'time':
467
- ret[key] = datetime.time.fromisoformat(value[i+1:])
468
- elif typ == 'dataframe':
469
- module = importlib.import_module('pandas')
470
- ret[key] = module.read_json(value[i+1:],orient="table")
471
- elif typ == 'decimal':
472
- ret[key] = decimal.Decimal(value[i+1:])
473
- elif typ == 'uuid':
474
- ret[key] = uuid.UUID(value[i+1:])
475
- elif typ == 'bytes':
476
- ret[key] = base64.b64decode((value[i+1:].encode("UTF-8")))
477
- else:
478
- ret[key] = value
479
- else:
480
- ret[key] = value
481
- return ret
1
+ from iop._business_host import _BusinessHost
grongier/pex/_cli.py CHANGED
@@ -1,152 +1,4 @@
1
- # _manager.py is the main entry point of the pex package
2
- # it's a command line interface to manage productions
3
- # eg :
4
- # python3 -m grongier.pex -h : display help and the default production name
5
- # python3 -m grongier.pex -l : list productions
6
- # python3 -m grongier.pex -d <production_name> : set the default production to <production_name>
7
- # python3 -m grongier.pex -s <production_name> : start a production named <production_name> if <production_name> is not set, the default production is started
8
- # python3 -m grongier.pex -k <production_name> : stop a production named <production_name> if <production_name> is not set, the default production is killed
9
- # python3 -m grongier.pex -r <production_name> : restart a production named <production_name> if <production_name> is not set, the default production is restarted
10
- # python3 -m grongier.pex -m <settings_file> : migrate a production and classes with the settings file <settings_file>
11
- # python3 -m grongier.pex -x <production_name> : export a production named <production_name> if <production_name> is not set, the default production is exported
12
- from grongier.pex._director import _Director
13
- from grongier.pex._utils import _Utils
14
-
15
- import argparse
16
- import json
17
- import os
18
- from importlib.metadata import version
19
-
20
- def parse_args():
21
- # parse arguments
22
- main_parser = argparse.ArgumentParser()
23
- parser = main_parser.add_mutually_exclusive_group()
24
- parser.add_argument('-d', '--default', help='set the default production', nargs='?', const='not_set')
25
- parser.add_argument('-l', '--list', help='list productions', action='store_true')
26
- parser.add_argument('-s', '--start', help='start a production', nargs='?', const='not_set')
27
- start = main_parser.add_argument_group('start arguments')
28
- start.add_argument('-D', '--detach', help='start a production in detach mode', action='store_true')
29
- parser.add_argument('-S', '--stop', help='stop a production', action='store_true')
30
- parser.add_argument('-k', '--kill', help='kill a production', action='store_true')
31
- parser.add_argument('-r', '--restart', help='restart a production', action='store_true')
32
- parser.add_argument('-x', '--status', help='status a production', action='store_true')
33
- parser.add_argument('-m', '-M', '--migrate', help='migrate production and classes with settings file')
34
- parser.add_argument('-e', '--export', help='export a production', nargs='?', const='not_set')
35
- parser.add_argument('-v', '--version', help='display version', action='store_true')
36
- parser.add_argument('-L', '--log', help='display log', nargs='?', const='not_set')
37
- parser.add_argument('-i', '--init', help='init the pex module in iris', nargs='?', const='not_set')
38
- parser.add_argument('-t', '--test', help='test the pex module in iris', nargs='?', const='not_set')
39
- test = main_parser.add_argument_group('test arguments')
40
- # add classname argument
41
- test.add_argument('-C', '--classname', help='test classname', nargs='?', const='not_set')
42
- # body argument
43
- test.add_argument('-B', '--body', help='test body', nargs='?', const='not_set')
44
- return main_parser
45
-
46
- def main(argv=None):
47
- # build arguments
48
- parser = parse_args()
49
- args = parser.parse_args(argv)
50
-
51
- if args.default:
52
- # set default production
53
- if args.default == 'not_set':
54
- # display default production name
55
- print(_Director.get_default_production())
56
- else:
57
- _Director.set_default_production(args.default)
58
-
59
- elif args.list:
60
- # display list of productions
61
- dikt = _Director.list_productions()
62
- print(json.dumps(dikt, indent=4))
63
-
64
- elif args.start:
65
- production_name = None
66
- if args.start == 'not_set':
67
- # start default production
68
- production_name = _Director.get_default_production()
69
- else:
70
- # start production with name
71
- production_name = args.start
72
- if args.detach:
73
- # start production in detach mode
74
- _Director.start_production(production_name)
75
- print(f"Production {production_name} started")
76
- else:
77
- _Director.start_production_with_log(production_name)
78
-
79
- elif args.init:
80
- if args.init == 'not_set':
81
- # set arg to None
82
- args.init = None
83
- _Utils.setup(args.start)
84
-
85
- elif args.kill:
86
- # kill a production
87
- _Director.shutdown_production()
88
-
89
- elif args.restart:
90
- # restart a production
91
- _Director.restart_production()
92
-
93
- elif args.migrate:
94
- # check if migrate is absolute path
95
- if os.path.isabs(args.migrate):
96
- # migrate a production with absolute path
97
- _Utils.migrate(args.migrate)
98
- else:
99
- # migrate a production with relative path
100
- _Utils.migrate(os.path.join(os.getcwd(), args.migrate))
101
-
102
- elif args.version:
103
- # display version
104
- print(version('iris-pex-embedded-python'))
105
-
106
- elif args.log:
107
- # display log
108
- if args.log == 'not_set':
109
- # display default production log
110
- _Director.log_production()
111
- else:
112
- _Director.log_production_top(args.log)
113
-
114
- elif args.stop:
115
- # stop a production
116
- _Director.stop_production()
117
- print(f"Production {_Director.get_default_production()} stopped")
118
-
119
- elif args.status:
120
- dikt=_Director.status_production()
121
- print(json.dumps(dikt, indent=4))
122
-
123
- elif args.test:
124
- classname = None
125
- body = None
126
- if args.test == 'not_set':
127
- # set arg to None
128
- args.test = None
129
- if args.classname:
130
- classname = args.classname
131
- if args.body:
132
- body = args.body
133
- response = _Director.test_component(args.test, classname=classname, body=body)
134
- print(response)
135
-
136
- elif args.export:
137
- if args.export == 'not_set':
138
- # export default production
139
- args.export=_Director.get_default_production()
140
-
141
- dikt = _Utils.export_production(args.export)
142
- print(json.dumps(dikt, indent=4))
143
-
144
- else:
145
- # display help
146
- parser.print_help()
147
- print()
148
- print("Default production : " + _Director.get_default_production())
149
-
1
+ from iop._cli import main
150
2
 
151
3
  if __name__ == '__main__':
152
- main()
4
+ main()