iris-pex-embedded-python 2.3.27b2__py3-none-any.whl → 3.2.1b3__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 -100
  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 -511
  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 +196 -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 +3 -2
  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.1b3.dist-info/METADATA +90 -0
  71. iris_pex_embedded_python-3.2.1b3.dist-info/RECORD +139 -0
  72. {iris_pex_embedded_python-2.3.27b2.dist-info → iris_pex_embedded_python-3.2.1b3.dist-info}/WHEEL +1 -1
  73. iris_pex_embedded_python-3.2.1b3.dist-info/entry_points.txt +2 -0
  74. {iris_pex_embedded_python-2.3.27b2.dist-info → iris_pex_embedded_python-3.2.1b3.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.27b2.dist-info/METADATA +0 -1384
  82. iris_pex_embedded_python-2.3.27b2.dist-info/RECORD +0 -113
  83. iris_pex_embedded_python-2.3.27b2.dist-info/entry_points.txt +0 -2
  84. {grongier/pex → iop}/_pickle_message.py +0 -0
  85. {iris_pex_embedded_python-2.3.27b2.dist-info → iris_pex_embedded_python-3.2.1b3.dist-info}/LICENSE +0 -0
@@ -0,0 +1,71 @@
1
+ import importlib
2
+ from typing import Any, List, Optional, Union, Tuple
3
+ from iop._business_host import _BusinessHost
4
+
5
+ class _BusinessOperation(_BusinessHost):
6
+ """Business operation component that handles outbound communication.
7
+
8
+ Responsible for sending messages to external systems. Can optionally use an
9
+ adapter to handle the outbound messaging protocol.
10
+ """
11
+
12
+ DISPATCH: List[Tuple[str, str]] = []
13
+ Adapter: Any = None
14
+ adapter: Any = None
15
+
16
+ def on_message(self, request: Any) -> Any:
17
+ """Handle incoming messages.
18
+
19
+ Process messages received from other production components and either
20
+ send to external system or forward to another component.
21
+
22
+ Args:
23
+ request: The incoming message
24
+
25
+ Returns:
26
+ Response message
27
+ """
28
+ return self.OnMessage(request)
29
+
30
+ def on_keepalive(self) -> None:
31
+ """
32
+ Called when the server sends a keepalive message.
33
+ """
34
+ return
35
+
36
+ def _set_iris_handles(self, handle_current: Any, handle_partner: Any) -> None:
37
+ """For internal use only."""
38
+ self.iris_handle = handle_current
39
+ if type(handle_partner).__module__.find('iris') == 0:
40
+ if handle_partner._IsA("Grongier.PEX.OutboundAdapter") or handle_partner._IsA("IOP.OutboundAdapter"):
41
+ module = importlib.import_module(handle_partner.GetModule())
42
+ handle_partner = getattr(module, handle_partner.GetClassname())()
43
+ self.Adapter = self.adapter = handle_partner
44
+ return
45
+
46
+ def _dispatch_on_init(self, host_object: Any) -> None:
47
+ """For internal use only."""
48
+ self._create_dispatch()
49
+ self.on_init()
50
+ return
51
+
52
+ @_BusinessHost.input_deserialzer
53
+ @_BusinessHost.output_serialzer
54
+ def _dispatch_on_message(self, request: Any) -> Any:
55
+ """For internal use only."""
56
+ return self._dispach_message(request)
57
+
58
+ def OnMessage(self, request: Any) -> Any:
59
+ """DEPRECATED : use on_message
60
+ Called when the business operation receives a message from another production component.
61
+ Typically, the operation will either send the message to the external system or forward it to a business process or another business operation.
62
+ If the operation has an adapter, it uses the Adapter.invoke() method to call the method on the adapter that sends the message to the external system.
63
+ If the operation is forwarding the message to another production component, it uses the SendRequestAsync() or the SendRequestSync() method
64
+
65
+ Parameters:
66
+ request: An instance of either a subclass of Message or of IRISObject containing the incoming message for the business operation.
67
+
68
+ Returns:
69
+ The response object
70
+ """
71
+ return
@@ -0,0 +1,220 @@
1
+ from typing import Any, List, Optional, Union
2
+ from iop._business_host import _BusinessHost
3
+
4
+ class _BusinessProcess(_BusinessHost):
5
+ """Business process component that contains routing and transformation logic.
6
+
7
+ A business process can receive messages from services, other processes, or operations.
8
+ It can modify messages, transform formats, and route based on content.
9
+ """
10
+
11
+ DISPATCH: List[tuple] = []
12
+ PERSISTENT_PROPERTY_LIST: Optional[List[str]] = None
13
+
14
+ def on_message(self, request: Any) -> Any:
15
+ """Handle incoming messages.
16
+
17
+ Args:
18
+ request: The incoming message
19
+
20
+ Returns:
21
+ Response message
22
+ """
23
+ return self.on_request(request)
24
+
25
+ def on_request(self, request: Any) -> Any:
26
+ """Process initial requests sent to this component.
27
+
28
+ Args:
29
+ request: The incoming request message
30
+
31
+ Returns:
32
+ Response message
33
+ """
34
+ return self.OnRequest(request)
35
+
36
+ def on_response(self, request: Any, response: Any, call_request: Any, call_response: Any, completion_key: str) -> Any:
37
+ """Handle responses to messages sent by this component.
38
+
39
+ Args:
40
+ request: The initial request message
41
+ response: The response message
42
+ call_request: The request sent to the target
43
+ call_response: The incoming response
44
+ completion_key: The completion key specified in the outgoing SendAsync() method
45
+
46
+ Returns:
47
+ Response message
48
+ """
49
+ return self.OnResponse(request, response, call_request, call_response, completion_key)
50
+
51
+ def on_complete(self, request: Any, response: Any) -> Any:
52
+ """Called after all responses to requests sent by this component have been handled.
53
+
54
+ Args:
55
+ request: The initial request message
56
+ response: The response message
57
+
58
+ Returns:
59
+ Response message
60
+ """
61
+ return self.OnComplete(request, response)
62
+
63
+ @_BusinessHost.input_serialzer_param(0,'response')
64
+ def reply(self, response: Any) -> None:
65
+ """Send the specified response to the production component that sent the initial request.
66
+
67
+ Args:
68
+ response: The response message
69
+ """
70
+ return self.iris_handle.dispatchReply(response)
71
+
72
+ @_BusinessHost.input_serialzer_param(1,'request')
73
+ def send_request_async(self, target: str, request: Any, response_required: bool=True, completion_key: Optional[str]=None, description: Optional[str]=None) -> None:
74
+ """Send the specified message to the target business process or business operation asynchronously.
75
+
76
+ Args:
77
+ target: The name of the business process or operation to receive the request
78
+ request: The message to send to the target
79
+ response_required: Whether a response is required
80
+ completion_key: A string that will be returned with the response if the maximum time is exceeded
81
+ description: An optional description property in the message header
82
+
83
+ Raises:
84
+ TypeError: If request is not of type Message or IRISObject
85
+ """
86
+ if response_required:
87
+ response_required = 1
88
+ else:
89
+ response_required = 0
90
+ return self.iris_handle.dispatchSendRequestAsync(target, request, response_required, completion_key, description)
91
+
92
+ def set_timer(self, timeout: Union[int, str], completion_key: Optional[str]=None) -> None:
93
+ """Specify the maximum time the business process will wait for responses.
94
+
95
+ Args:
96
+ timeout: The maximum time to wait for responses
97
+ completion_key: A string that will be returned with the response if the maximum time is exceeded
98
+ """
99
+ self.iris_handle.dispatchSetTimer(timeout, completion_key)
100
+ return
101
+
102
+ def _set_iris_handles(self, handle_current: Any, handle_partner: Any) -> None:
103
+ """For internal use only."""
104
+ self.iris_handle = handle_current
105
+ return
106
+
107
+ def _save_persistent_properties(self, host_object: Any) -> None:
108
+ """For internal use only."""
109
+ if self.PERSISTENT_PROPERTY_LIST is None:
110
+ return
111
+ for prop in self.PERSISTENT_PROPERTY_LIST:
112
+ val = getattr(self, prop, None)
113
+ typ = val.__class__.__name__
114
+ if typ in ["str", "int", "float", "bool", "bytes"]:
115
+ try:
116
+ host_object.setPersistentProperty(prop, val)
117
+ except:
118
+ pass
119
+ return
120
+
121
+ def _restore_persistent_properties(self, host_object: Any) -> None:
122
+ """For internal use only."""
123
+ if self.PERSISTENT_PROPERTY_LIST is None:
124
+ return
125
+ for prop in self.PERSISTENT_PROPERTY_LIST:
126
+ try:
127
+ val = host_object.getPersistentProperty(prop)
128
+ setattr(self, prop, val)
129
+ except:
130
+ pass
131
+ return
132
+
133
+ def _dispatch_on_connected(self, host_object: Any) -> None:
134
+ """For internal use only."""
135
+ self.on_connected()
136
+ self._save_persistent_properties(host_object)
137
+ return
138
+
139
+ def _dispatch_on_init(self, host_object: Any) -> None:
140
+ """For internal use only."""
141
+ self._restore_persistent_properties(host_object)
142
+ self._create_dispatch()
143
+ self.on_init()
144
+ self._save_persistent_properties(host_object)
145
+ return
146
+
147
+ def _dispatch_on_tear_down(self, host_object: Any) -> None:
148
+ """For internal use only."""
149
+ self._restore_persistent_properties(host_object)
150
+ self.on_tear_down()
151
+ self._save_persistent_properties(host_object)
152
+ return
153
+
154
+ @_BusinessHost.input_deserialzer
155
+ @_BusinessHost.output_serialzer
156
+ def _dispatch_on_request(self, host_object: Any, request: Any) -> Any:
157
+ """For internal use only."""
158
+ self._restore_persistent_properties(host_object)
159
+ return_object = self._dispach_message(request)
160
+ self._save_persistent_properties(host_object)
161
+ return return_object
162
+
163
+ @_BusinessHost.input_deserialzer
164
+ @_BusinessHost.output_serialzer
165
+ def _dispatch_on_response(self, host_object: Any, request: Any, response: Any, call_request: Any, call_response: Any, completion_key: str) -> Any:
166
+ """For internal use only."""
167
+ self._restore_persistent_properties(host_object)
168
+ return_object = self.on_response(request, response, call_request, call_response, completion_key)
169
+ self._save_persistent_properties(host_object)
170
+ return return_object
171
+
172
+ @_BusinessHost.input_deserialzer
173
+ @_BusinessHost.output_serialzer
174
+ def _dispatch_on_complete(self, host_object: Any, request: Any, response: Any) -> Any:
175
+ """For internal use only."""
176
+ self._restore_persistent_properties(host_object)
177
+ return_object = self.on_complete(request, response)
178
+ self._save_persistent_properties(host_object)
179
+ return return_object
180
+
181
+ def OnRequest(self, request: Any) -> Any:
182
+ """
183
+ DEPRECATED: Use on_request.
184
+
185
+ Args:
186
+ request: The incoming request message
187
+
188
+ Returns:
189
+ Response message
190
+ """
191
+ return
192
+
193
+ def OnResponse(self, request: Any, response: Any, call_request: Any, call_response: Any, completion_key: str) -> Any:
194
+ """
195
+ DEPRECATED: Use on_response.
196
+
197
+ Args:
198
+ request: The initial request message
199
+ response: The response message
200
+ call_request: The request sent to the target
201
+ call_response: The incoming response
202
+ completion_key: The completion key specified in the outgoing SendAsync() method
203
+
204
+ Returns:
205
+ Response message
206
+ """
207
+ return response
208
+
209
+ def OnComplete(self, request: Any, response: Any) -> Any:
210
+ """
211
+ DEPRECATED: Use on_complete.
212
+
213
+ Args:
214
+ request: The initial request message
215
+ response: The response message
216
+
217
+ Returns:
218
+ Response message
219
+ """
220
+ return response
@@ -1,5 +1,5 @@
1
1
  import importlib
2
- from grongier.pex._business_host import _BusinessHost
2
+ from iop._business_host import _BusinessHost
3
3
 
4
4
  class _BusinessService(_BusinessHost):
5
5
  """ This class is responsible for receiving the data from external system and sending it to business processes or business operations in the production.
@@ -30,7 +30,7 @@ class _BusinessService(_BusinessHost):
30
30
  """ For internal use only. """
31
31
  self.iris_handle = handle_current
32
32
  if type(handle_partner).__module__.find('iris') == 0:
33
- if handle_partner._IsA("Grongier.PEX.InboundAdapter"):
33
+ if handle_partner._IsA("Grongier.PEX.InboundAdapter") or handle_partner._IsA("IOP.InboundAdapter"):
34
34
  module = importlib.import_module(handle_partner.GetModule())
35
35
  handle_partner = getattr(module, handle_partner.GetClassname())()
36
36
  self.Adapter = self.adapter = handle_partner
iop/_cli.py ADDED
@@ -0,0 +1,196 @@
1
+ from __future__ import annotations
2
+ import argparse
3
+ import json
4
+ import os
5
+ from dataclasses import dataclass
6
+ from enum import Enum, auto
7
+ import sys
8
+ from typing import Optional, Callable
9
+ from importlib.metadata import version
10
+
11
+ from iop._director import _Director
12
+ from iop._utils import _Utils
13
+
14
+ class CommandType(Enum):
15
+ DEFAULT = auto()
16
+ LIST = auto()
17
+ START = auto()
18
+ STOP = auto()
19
+ KILL = auto()
20
+ RESTART = auto()
21
+ STATUS = auto()
22
+ TEST = auto()
23
+ VERSION = auto()
24
+ EXPORT = auto()
25
+ MIGRATE = auto()
26
+ LOG = auto()
27
+ INIT = auto()
28
+ HELP = auto()
29
+
30
+ @dataclass
31
+ class CommandArgs:
32
+ """Container for parsed command arguments"""
33
+ default: Optional[str] = None
34
+ list: bool = False
35
+ start: Optional[str] = None
36
+ detach: bool = False
37
+ stop: bool = False
38
+ kill: bool = False
39
+ restart: bool = False
40
+ status: bool = False
41
+ migrate: Optional[str] = None
42
+ export: Optional[str] = None
43
+ version: bool = False
44
+ log: Optional[str] = None
45
+ init: Optional[str] = None
46
+ test: Optional[str] = None
47
+ classname: Optional[str] = None
48
+ body: Optional[str] = None
49
+
50
+ class Command:
51
+ def __init__(self, args: CommandArgs):
52
+ self.args = args
53
+
54
+ def execute(self) -> None:
55
+ command_type = self._determine_command_type()
56
+ command_handlers = {
57
+ CommandType.DEFAULT: self._handle_default,
58
+ CommandType.LIST: self._handle_list,
59
+ CommandType.START: self._handle_start,
60
+ CommandType.STOP: self._handle_stop,
61
+ CommandType.KILL: self._handle_kill,
62
+ CommandType.RESTART: self._handle_restart,
63
+ CommandType.STATUS: self._handle_status,
64
+ CommandType.TEST: self._handle_test,
65
+ CommandType.VERSION: self._handle_version,
66
+ CommandType.EXPORT: self._handle_export,
67
+ CommandType.MIGRATE: self._handle_migrate,
68
+ CommandType.LOG: self._handle_log,
69
+ CommandType.INIT: self._handle_init,
70
+ CommandType.HELP: self._handle_help
71
+ }
72
+ handler = command_handlers.get(command_type)
73
+ if handler:
74
+ handler()
75
+
76
+ def _determine_command_type(self) -> CommandType:
77
+ if self.args.default: return CommandType.DEFAULT
78
+ if self.args.list: return CommandType.LIST
79
+ if self.args.start: return CommandType.START
80
+ if self.args.stop: return CommandType.STOP
81
+ if self.args.kill: return CommandType.KILL
82
+ if self.args.restart: return CommandType.RESTART
83
+ if self.args.status: return CommandType.STATUS
84
+ if self.args.test: return CommandType.TEST
85
+ if self.args.version: return CommandType.VERSION
86
+ if self.args.export: return CommandType.EXPORT
87
+ if self.args.migrate: return CommandType.MIGRATE
88
+ if self.args.log: return CommandType.LOG
89
+ if self.args.init: return CommandType.INIT
90
+ return CommandType.HELP
91
+
92
+ def _handle_default(self) -> None:
93
+ if self.args.default == 'not_set':
94
+ print(_Director.get_default_production())
95
+ else:
96
+ _Director.set_default_production(self.args.default)
97
+
98
+ def _handle_list(self) -> None:
99
+ dikt = _Director.list_productions()
100
+ print(json.dumps(dikt, indent=4))
101
+
102
+ def _handle_start(self) -> None:
103
+ production_name = self.args.start if self.args.start != 'not_set' else _Director.get_default_production()
104
+ if self.args.detach:
105
+ _Director.start_production(production_name)
106
+ print(f"Production {production_name} started")
107
+ else:
108
+ _Director.start_production_with_log(production_name)
109
+
110
+ def _handle_stop(self) -> None:
111
+ _Director.stop_production()
112
+ print(f"Production {_Director.get_default_production()} stopped")
113
+
114
+ def _handle_kill(self) -> None:
115
+ _Director.shutdown_production()
116
+
117
+ def _handle_restart(self) -> None:
118
+ _Director.restart_production()
119
+
120
+ def _handle_status(self) -> None:
121
+ print(json.dumps(_Director.status_production(), indent=4))
122
+
123
+ def _handle_test(self) -> None:
124
+ test_name = None if self.args.test == 'not_set' else self.args.test
125
+ response = _Director.test_component(
126
+ test_name,
127
+ classname=self.args.classname if self.args.classname != 'not_set' else None,
128
+ body=self.args.body if self.args.body != 'not_set' else None
129
+ )
130
+ print(response)
131
+
132
+ def _handle_version(self) -> None:
133
+ print(version('iris-pex-embedded-python'))
134
+
135
+ def _handle_export(self) -> None:
136
+ export_name = _Director.get_default_production() if self.args.export == 'not_set' else self.args.export
137
+ print(json.dumps(_Utils.export_production(export_name), indent=4))
138
+
139
+ def _handle_migrate(self) -> None:
140
+ migrate_path = self.args.migrate
141
+ if not os.path.isabs(migrate_path):
142
+ migrate_path = os.path.join(os.getcwd(), migrate_path)
143
+ _Utils.migrate(migrate_path)
144
+
145
+ def _handle_log(self) -> None:
146
+ log_name = _Director.get_default_production() if self.args.log == 'not_set' else self.args.log
147
+ print(_Director.get_production_log(log_name))
148
+
149
+ def _handle_init(self) -> None:
150
+ _Utils.setup(None)
151
+
152
+ def _handle_help(self) -> None:
153
+ create_parser().print_help()
154
+ print(f"\nDefault production: {_Director.get_default_production()}")
155
+
156
+ def create_parser() -> argparse.ArgumentParser:
157
+ """Create and configure argument parser"""
158
+ main_parser = argparse.ArgumentParser()
159
+ parser = main_parser.add_mutually_exclusive_group()
160
+
161
+ # Main commands
162
+ parser.add_argument('-d', '--default', help='set the default production', nargs='?', const='not_set')
163
+ parser.add_argument('-l', '--list', help='list productions', action='store_true')
164
+ parser.add_argument('-s', '--start', help='start a production', nargs='?', const='not_set')
165
+ parser.add_argument('-S', '--stop', help='stop a production', action='store_true')
166
+ parser.add_argument('-k', '--kill', help='kill a production', action='store_true')
167
+ parser.add_argument('-r', '--restart', help='restart a production', action='store_true')
168
+ parser.add_argument('-x', '--status', help='status a production', action='store_true')
169
+ parser.add_argument('-m', '-M', '--migrate', help='migrate production and classes with settings file')
170
+ parser.add_argument('-e', '--export', help='export a production', nargs='?', const='not_set')
171
+ parser.add_argument('-v', '--version', help='display version', action='store_true')
172
+ parser.add_argument('-L', '--log', help='display log', nargs='?', const='not_set')
173
+ parser.add_argument('-i', '--init', help='init the pex module in iris', nargs='?', const='not_set')
174
+ parser.add_argument('-t', '--test', help='test the pex module in iris', nargs='?', const='not_set')
175
+
176
+ # Command groups
177
+ start = main_parser.add_argument_group('start arguments')
178
+ start.add_argument('-D', '--detach', help='start a production in detach mode', action='store_true')
179
+
180
+ test = main_parser.add_argument_group('test arguments')
181
+ test.add_argument('-C', '--classname', help='test classname', nargs='?', const='not_set')
182
+ test.add_argument('-B', '--body', help='test body', nargs='?', const='not_set')
183
+
184
+ return main_parser
185
+
186
+ def main(argv=None) -> None:
187
+ parser = create_parser()
188
+ args = parser.parse_args(argv)
189
+ cmd_args = CommandArgs(**vars(args))
190
+
191
+ command = Command(cmd_args)
192
+ command.execute()
193
+ sys.exit(0)
194
+
195
+ if __name__ == '__main__':
196
+ main()