iris-pex-embedded-python 3.7.2b2__py3-none-any.whl → 4.0.0__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 (119) hide show
  1. iop/__init__.py +276 -18
  2. iop/__main__.py +3 -3
  3. iop/cli/__init__.py +1 -0
  4. iop/cli/formatting.py +45 -0
  5. iop/{_cli.py → cli/main.py} +238 -216
  6. iop/cli/parser.py +165 -0
  7. iop/cli/types.py +73 -0
  8. iop/cls/IOP/Common.cls +11 -2
  9. iop/cls/IOP/PrivateSession/Duplex.cls +1 -1
  10. iop/cls/IOP/Service/Remote/Rest/v1.cls +152 -5
  11. iop/cls/IOP/Utils.cls +814 -7
  12. iop/cls/IOP/Wrapper.cls +1 -1
  13. iop/components/__init__.py +16 -0
  14. iop/{_async_request.py → components/async_request.py} +7 -7
  15. iop/components/business_host.py +363 -0
  16. iop/components/business_operation.py +84 -0
  17. iop/{_business_process.py → components/business_process.py} +145 -125
  18. iop/components/business_service.py +106 -0
  19. iop/{_common.py → components/common.py} +160 -164
  20. iop/{_debugpy.py → components/debugpy.py} +11 -11
  21. iop/{_generator_request.py → components/generator_request.py} +4 -4
  22. iop/{_inbound_adapter.py → components/inbound_adapter.py} +10 -18
  23. iop/{_log_manager.py → components/log_manager.py} +1 -1
  24. iop/{_outbound_adapter.py → components/outbound_adapter.py} +1 -1
  25. iop/components/polling_business_service.py +48 -0
  26. iop/{_private_session_duplex.py → components/private_session_duplex.py} +7 -9
  27. iop/{_private_session_process.py → components/private_session_process.py} +2 -2
  28. iop/{_settings.py → components/settings.py} +23 -3
  29. iop/messages/__init__.py +7 -0
  30. iop/messages/base.py +61 -0
  31. iop/{_decorators.py → messages/decorators.py} +8 -2
  32. iop/messages/dispatch.py +351 -0
  33. iop/{_persistent_message.py → messages/persistent.py} +24 -19
  34. iop/{_serialization.py → messages/serialization.py} +34 -21
  35. iop/{_message_validator.py → messages/validation.py} +15 -13
  36. iop/migration/__init__.py +1 -0
  37. iop/migration/io.py +61 -0
  38. iop/migration/manifest.py +534 -0
  39. iop/migration/plans.py +80 -0
  40. iop/migration/utils.py +1126 -0
  41. iop/production/__init__.py +55 -0
  42. iop/production/actions.py +525 -0
  43. iop/production/common.py +103 -0
  44. iop/production/component.py +234 -0
  45. iop/production/declarations.py +190 -0
  46. iop/production/declarative.py +214 -0
  47. iop/production/diff.py +327 -0
  48. iop/production/import_.py +296 -0
  49. iop/production/inspection.py +92 -0
  50. iop/production/model.py +1143 -0
  51. iop/production/planning.py +678 -0
  52. iop/production/reconstruction.py +341 -0
  53. iop/production/rendering.py +610 -0
  54. iop/production/runtime.py +91 -0
  55. iop/production/source_inference.py +729 -0
  56. iop/production/types.py +546 -0
  57. iop/production/validation.py +452 -0
  58. iop/runtime/__init__.py +1 -0
  59. iop/runtime/director.py +415 -0
  60. iop/runtime/environment.py +59 -0
  61. iop/{_iris.py → runtime/iris.py} +2 -2
  62. iop/runtime/local.py +145 -0
  63. iop/{_director_protocol.py → runtime/protocol.py} +25 -8
  64. iop/runtime/remote/__init__.py +12 -0
  65. iop/runtime/remote/client.py +90 -0
  66. iop/runtime/remote/director.py +283 -0
  67. iop/runtime/remote/migration.py +57 -0
  68. iop/runtime/remote/settings.py +69 -0
  69. iop/runtime/remote/setup.py +72 -0
  70. {iris_pex_embedded_python-3.7.2b2.dist-info → iris_pex_embedded_python-4.0.0.dist-info}/METADATA +11 -2
  71. iris_pex_embedded_python-4.0.0.dist-info/RECORD +99 -0
  72. iris_pex_embedded_python-4.0.0.dist-info/entry_points.txt +2 -0
  73. iris_pex_embedded_python-4.0.0.dist-info/top_level.txt +1 -0
  74. grongier/__init__.py +0 -0
  75. grongier/cls/Grongier/PEX/BusinessOperation.cls +0 -8
  76. grongier/cls/Grongier/PEX/BusinessProcess.cls +0 -13
  77. grongier/cls/Grongier/PEX/BusinessService.cls +0 -8
  78. grongier/cls/Grongier/PEX/Common.cls +0 -10
  79. grongier/cls/Grongier/PEX/Director.cls +0 -10
  80. grongier/cls/Grongier/PEX/Duplex/Operation.cls +0 -4
  81. grongier/cls/Grongier/PEX/Duplex/Process.cls +0 -13
  82. grongier/cls/Grongier/PEX/Duplex/Service.cls +0 -4
  83. grongier/cls/Grongier/PEX/InboundAdapter.cls +0 -8
  84. grongier/cls/Grongier/PEX/Message.cls +0 -13
  85. grongier/cls/Grongier/PEX/OutboundAdapter.cls +0 -8
  86. grongier/cls/Grongier/PEX/PickleMessage.cls +0 -13
  87. grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +0 -8
  88. grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +0 -14
  89. grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +0 -14
  90. grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +0 -14
  91. grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +0 -14
  92. grongier/cls/Grongier/PEX/Test.cls +0 -10
  93. grongier/cls/Grongier/PEX/Utils.cls +0 -10
  94. grongier/cls/Grongier/Service/WSGI.cls +0 -4
  95. grongier/pex/__init__.py +0 -75
  96. grongier/pex/__main__.py +0 -4
  97. grongier/pex/_business_host.py +0 -1
  98. grongier/pex/_cli.py +0 -4
  99. grongier/pex/_common.py +0 -1
  100. grongier/pex/_director.py +0 -1
  101. grongier/pex/_utils.py +0 -1
  102. grongier/pex/wsgi/handlers.py +0 -104
  103. iop/_business_host.py +0 -322
  104. iop/_business_operation.py +0 -77
  105. iop/_business_service.py +0 -67
  106. iop/_director.py +0 -333
  107. iop/_dispatch.py +0 -194
  108. iop/_local.py +0 -106
  109. iop/_message.py +0 -45
  110. iop/_polling_business_service.py +0 -6
  111. iop/_remote.py +0 -473
  112. iop/_utils.py +0 -912
  113. iop/cls/IOP/Service/WSGI.cls +0 -310
  114. iop/wsgi/handlers.py +0 -112
  115. iris_pex_embedded_python-3.7.2b2.dist-info/RECORD +0 -96
  116. iris_pex_embedded_python-3.7.2b2.dist-info/entry_points.txt +0 -2
  117. iris_pex_embedded_python-3.7.2b2.dist-info/top_level.txt +0 -2
  118. {iris_pex_embedded_python-3.7.2b2.dist-info → iris_pex_embedded_python-4.0.0.dist-info}/WHEEL +0 -0
  119. {iris_pex_embedded_python-3.7.2b2.dist-info → iris_pex_embedded_python-4.0.0.dist-info}/licenses/LICENSE +0 -0
iop/cli/parser.py ADDED
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+
6
+ def create_parser() -> argparse.ArgumentParser:
7
+ """Create and configure the IOP CLI parser."""
8
+ main_parser = argparse.ArgumentParser(
9
+ epilog=(
10
+ "Remote mode: set IOP_URL (e.g. http://localhost:8080) to run all commands\n"
11
+ "against a remote IRIS instance via its REST API. Optional env vars:\n"
12
+ " IOP_USERNAME, IOP_PASSWORD, IOP_NAMESPACE (default: USER),\n"
13
+ " IOP_VERIFY_SSL (set to 0 to disable TLS verification).\n"
14
+ "Alternatively use -R /path/to/settings.py or set IOP_SETTINGS=\n"
15
+ "(file must contain a REMOTE_SETTINGS dict with at least 'url').\n"
16
+ "Use --force-local to suppress remote mode entirely."
17
+ ),
18
+ formatter_class=argparse.RawDescriptionHelpFormatter,
19
+ )
20
+ parser = main_parser.add_mutually_exclusive_group()
21
+
22
+ parser.add_argument(
23
+ "-d", "--default", help="set the default production", nargs="?", const="not_set"
24
+ )
25
+ parser.add_argument("-l", "--list", help="list productions", action="store_true")
26
+ parser.add_argument(
27
+ "-s", "--start", help="start a production", nargs="?", const="not_set"
28
+ )
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(
34
+ "-m",
35
+ "-M",
36
+ "--migrate",
37
+ help="migrate production and classes with a Python migration file",
38
+ )
39
+ parser.add_argument(
40
+ "-e", "--export", help="export a production", nargs="?", const="not_set"
41
+ )
42
+ parser.add_argument("-v", "--version", help="display version", action="store_true")
43
+ parser.add_argument("-L", "--log", help="display log", nargs="?", const="not_set")
44
+ parser.add_argument(
45
+ "-q",
46
+ "--queue",
47
+ help="display runtime queue information",
48
+ nargs="?",
49
+ const="not_set",
50
+ )
51
+ parser.add_argument(
52
+ "-i", "--init", help="init the iop module in iris", nargs="?", const="not_set"
53
+ )
54
+ parser.add_argument(
55
+ "--bindings",
56
+ help="list IOP-generated IRIS proxy class bindings",
57
+ action="store_true",
58
+ )
59
+ parser.add_argument(
60
+ "--unbind",
61
+ help="remove an IOP-generated IRIS proxy class binding",
62
+ )
63
+ parser.add_argument(
64
+ "-t", "--test", help="test the iop module in iris", nargs="?", const="not_set"
65
+ )
66
+ parser.add_argument("-u", "--update", help="update a production", action="store_true")
67
+ parser.add_argument(
68
+ "--plan",
69
+ help="build a conservative production change plan from a Python settings file",
70
+ )
71
+ parser.add_argument("--review-plan", help="print a saved production change plan")
72
+ parser.add_argument("--apply-plan", help="apply a saved production change plan")
73
+ parser.add_argument("--verify-plan", help="verify a saved production change plan")
74
+ parser.add_argument(
75
+ "--rollback-backup",
76
+ help="restore a production from a plan/apply backup directory",
77
+ )
78
+
79
+ start = main_parser.add_argument_group("start arguments")
80
+ start.add_argument(
81
+ "-D", "--detach", help="start a production in detach mode", action="store_true"
82
+ )
83
+
84
+ test = main_parser.add_argument_group("test arguments")
85
+ test.add_argument(
86
+ "-C", "--classname", help="test classname", nargs="?", const="not_set"
87
+ )
88
+ test.add_argument(
89
+ "-B",
90
+ "--body",
91
+ help="test body (JSON string or @path/to/file.json)",
92
+ nargs="?",
93
+ const="not_set",
94
+ )
95
+
96
+ migrate = main_parser.add_argument_group("migrate arguments")
97
+ migrate.add_argument(
98
+ "--force-local",
99
+ help="force local mode, skip remote even if REMOTE_SETTINGS or IOP_URL is present",
100
+ action="store_true",
101
+ )
102
+ migrate.add_argument(
103
+ "--dry-run",
104
+ "--explain",
105
+ dest="migration_plan",
106
+ help="show the migration plan and validation messages without writing to IRIS",
107
+ action="store_true",
108
+ )
109
+ migrate.add_argument(
110
+ "--strict-production-validation",
111
+ help="fail migration when production validation reports issues",
112
+ action="store_true",
113
+ )
114
+
115
+ export = main_parser.add_argument_group("export arguments")
116
+ export.add_argument(
117
+ "--format",
118
+ dest="export_format",
119
+ choices=("json", "python", "class", "graph", "mermaid"),
120
+ default="json",
121
+ help="export format for -e/--export",
122
+ )
123
+
124
+ bindings = main_parser.add_argument_group("bindings arguments")
125
+ bindings.add_argument(
126
+ "--unused",
127
+ help="with --bindings, show only proxy classes unused by productions",
128
+ action="store_true",
129
+ )
130
+
131
+ plan = main_parser.add_argument_group("production plan arguments")
132
+ plan.add_argument(
133
+ "--production",
134
+ help="target production name for --plan, or override the plan production",
135
+ )
136
+ plan.add_argument("--out", help="write --plan JSON to this path")
137
+ plan.add_argument(
138
+ "--settings",
139
+ help="settings.py file containing the desired Production for --apply-plan",
140
+ )
141
+ plan.add_argument(
142
+ "--backup-dir",
143
+ default=".iop/backups",
144
+ help="directory for apply backup artifacts",
145
+ )
146
+ plan.add_argument(
147
+ "--allow-destructive",
148
+ help="allow destructive plan operations or rollback",
149
+ action="store_true",
150
+ )
151
+
152
+ remote = main_parser.add_argument_group("remote arguments")
153
+ remote.add_argument(
154
+ "-R",
155
+ "--remote-settings",
156
+ help="path to a settings.py containing REMOTE_SETTINGS (overrides IOP_SETTINGS env var)",
157
+ metavar="FILE",
158
+ )
159
+
160
+ namespace = main_parser.add_argument_group("namespace arguments")
161
+ namespace.add_argument(
162
+ "-n", "--namespace", help="set namespace", nargs="?", const="not_set"
163
+ )
164
+
165
+ return main_parser
iop/cli/types.py ADDED
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from enum import Enum, auto
5
+
6
+
7
+ class CommandType(Enum):
8
+ DEFAULT = auto()
9
+ LIST = auto()
10
+ START = auto()
11
+ STOP = auto()
12
+ KILL = auto()
13
+ RESTART = auto()
14
+ STATUS = auto()
15
+ TEST = auto()
16
+ VERSION = auto()
17
+ EXPORT = auto()
18
+ MIGRATE = auto()
19
+ LOG = auto()
20
+ QUEUE = auto()
21
+ INIT = auto()
22
+ BINDINGS = auto()
23
+ UNBIND = auto()
24
+ HELP = auto()
25
+ UPDATE = auto()
26
+ PLAN = auto()
27
+ REVIEW_PLAN = auto()
28
+ APPLY_PLAN = auto()
29
+ VERIFY_PLAN = auto()
30
+ ROLLBACK_BACKUP = auto()
31
+
32
+
33
+ @dataclass
34
+ class CommandArgs:
35
+ """Container for parsed command arguments."""
36
+
37
+ default: str | None = None
38
+ list: bool = False
39
+ start: str | None = None
40
+ detach: bool = False
41
+ stop: bool = False
42
+ kill: bool = False
43
+ restart: bool = False
44
+ status: bool = False
45
+ migrate: str | None = None
46
+ export: str | None = None
47
+ export_format: str = "json"
48
+ version: bool = False
49
+ log: str | None = None
50
+ queue: str | None = None
51
+ init: str | None = None
52
+ bindings: bool = False
53
+ unused: bool = False
54
+ unbind: str | None = None
55
+ test: str | None = None
56
+ classname: str | None = None
57
+ body: str | None = None
58
+ namespace: str | None = None
59
+ force_local: bool = False
60
+ remote_settings: str | None = None
61
+ update: bool = False
62
+ migration_plan: bool = False
63
+ strict_production_validation: bool = False
64
+ plan: str | None = None
65
+ production: str | None = None
66
+ out: str | None = None
67
+ review_plan: str | None = None
68
+ apply_plan: str | None = None
69
+ verify_plan: str | None = None
70
+ rollback_backup: str | None = None
71
+ settings: str | None = None
72
+ backup_dir: str = ".iop/backups"
73
+ allow_destructive: bool = False
iop/cls/IOP/Common.cls CHANGED
@@ -187,7 +187,7 @@ Method OnTearDown() As %Status
187
187
  set tSC = $$$OK
188
188
  if $isObject(..%class) {
189
189
  try {
190
- do ..%class."_dispatch_on_tear_down"()
190
+ do ..%class."_dispatch_on_tear_down"($this)
191
191
  } catch ex {
192
192
  set tSC = ex.AsStatus()
193
193
  }
@@ -313,7 +313,7 @@ ClassMethod OnGetConnections(
313
313
  do pItem.GetModifiedSetting("%classname", .tClassname)
314
314
  do pItem.GetModifiedSetting("%module", .tModule)
315
315
 
316
- // try to instantiate class
316
+ // Prepare the Python import path for connection discovery.
317
317
  if tClasspaths '="" {
318
318
  set sys = ##class(%SYS.Python).Import("sys")
319
319
  set delimiter = $s($system.Version.GetOS()="Windows":";",1:":")
@@ -329,7 +329,14 @@ ClassMethod OnGetConnections(
329
329
  set builtins = ##class(%SYS.Python).Import("builtins")
330
330
  set module = ##class(%SYS.Python).Import(tModule)
331
331
  set class = builtins.getattr(module, tClassname)
332
+ // Allocate without calling Python __init__. Connection discovery must not
333
+ // run user startup code; IoP uses on_init() as the lifecycle hook.
332
334
  set tClass = class."__new__"(class)
335
+ Try {
336
+ do tClass."_warn_if_custom_init"()
337
+ }
338
+ Catch ex {
339
+ }
333
340
 
334
341
  set tPythonList = tClass."on_get_connections"()
335
342
  set tPythonListLen = tPythonList."__len__"()
@@ -535,6 +542,8 @@ Method CreateClassInstance(module As %SYS.Python) As %SYS.Python [ Private ]
535
542
  {
536
543
  set builtins = ##class(%SYS.Python).Import("builtins")
537
544
  set class = builtins.getattr(module, ..%classname)
545
+ // Intentionally bypass Python __init__. IRIS applies handles/settings and
546
+ // then calls on_init() through _dispatch_on_init().
538
547
  quit class."__new__"(class)
539
548
  }
540
549
 
@@ -250,7 +250,7 @@ Method OnTearDown() As %Status
250
250
  #dim tSC As %Status = $$$OK
251
251
  try {
252
252
  If ..%InPrivateSession Set tSC=..StopPrivateSession() Quit:$$$ISERR(tSC)
253
- do ..%class."_dispatch_on_tear_down"()
253
+ do ..%class."_dispatch_on_tear_down"($this)
254
254
  } catch {
255
255
  Set tSC=$$$EnsSystemError
256
256
  }
@@ -14,11 +14,18 @@ XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
14
14
  <Route Url="/kill" Method="POST" Call="PostKill"/>
15
15
  <Route Url="/restart" Method="POST" Call="PostRestart"/>
16
16
  <Route Url="/update" Method="POST" Call="PostUpdate"/>
17
+ <Route Url="/component/start" Method="POST" Call="PostComponentStart"/>
18
+ <Route Url="/component/stop" Method="POST" Call="PostComponentStop"/>
19
+ <Route Url="/component/restart" Method="POST" Call="PostComponentRestart"/>
20
+ <Route Url="/bindings" Method="GET" Call="GetBindings"/>
21
+ <Route Url="/binding" Method="DELETE" Call="DeleteBinding"/>
17
22
  <Route Url="/list" Method="GET" Call="GetList"/>
18
23
  <Route Url="/default" Method="GET" Call="GetDefault"/>
19
24
  <Route Url="/default" Method="PUT" Call="PutDefault"/>
20
25
  <Route Url="/log" Method="GET" Call="GetLog"/>
21
26
  <Route Url="/export" Method="GET" Call="GetExport"/>
27
+ <Route Url="/connections" Method="GET" Call="GetConnections"/>
28
+ <Route Url="/queues" Method="GET" Call="GetQueues"/>
22
29
  <Route Url="/test" Method="POST" Call="PostTest"/>
23
30
  </Routes>
24
31
  }
@@ -121,7 +128,19 @@ ClassMethod PostRestart() As %Status
121
128
  Try { Set dyna = {}.%FromJSON(%request.Content) } Catch { Set dyna = {} }
122
129
  Set ns = ..ResolveNs(dyna)
123
130
  If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
124
- $$$ThrowOnError(##class(Ens.Director).RestartProduction())
131
+ $$$ThrowOnError(##class(Ens.Director).GetProductionStatus(.production, .status))
132
+ If production = "" { Set production = $Get(^Ens.Configuration("csp","LastProduction")) }
133
+ If production = "" { Throw $$$ERROR("NoProductionSpecified") }
134
+ Set sc = ##class(Ens.Director).RestartProduction()
135
+ If $$$ISERR(sc) {
136
+ Set errorText = $SYSTEM.Status.GetErrorText(sc)
137
+ If $Find(errorText, "ErrProductionNotQuiescent") {
138
+ $$$ThrowOnError(##class(Ens.Director).StopProduction(10, 1))
139
+ $$$ThrowOnError(##class(Ens.Director).StartProduction(production))
140
+ } Else {
141
+ $$$ThrowOnError(sc)
142
+ }
143
+ }
125
144
  Return ..%WriteResponse({"status": "restarted"}.%ToJSON())
126
145
  } Catch ex {
127
146
  Return ..%WriteErrorResponse(ex.DisplayString())
@@ -141,6 +160,89 @@ ClassMethod PostUpdate() As %Status
141
160
  }
142
161
  }
143
162
 
163
+ ClassMethod PostComponentStart() As %Status
164
+ {
165
+ Try {
166
+ Set dyna = {}.%FromJSON(%request.Content)
167
+ Set ns = ..ResolveNs(dyna)
168
+ Set component = dyna.%Get("component")
169
+ If component = "" { Set component = dyna.%Get("item") }
170
+ If component = "" { Throw $$$ERROR("NoComponentSpecified") }
171
+ If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
172
+ $$$ThrowOnError(##class(Ens.Director).EnableConfigItem(component, 1, 1))
173
+ Return ..%WriteResponse({"status": "started", "component": (component)}.%ToJSON())
174
+ } Catch ex {
175
+ Return ..%WriteErrorResponse(ex.DisplayString())
176
+ }
177
+ }
178
+
179
+ ClassMethod PostComponentStop() As %Status
180
+ {
181
+ Try {
182
+ Set dyna = {}.%FromJSON(%request.Content)
183
+ Set ns = ..ResolveNs(dyna)
184
+ Set component = dyna.%Get("component")
185
+ If component = "" { Set component = dyna.%Get("item") }
186
+ If component = "" { Throw $$$ERROR("NoComponentSpecified") }
187
+ If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
188
+ $$$ThrowOnError(##class(Ens.Director).EnableConfigItem(component, 0, 1))
189
+ Return ..%WriteResponse({"status": "stopped", "component": (component)}.%ToJSON())
190
+ } Catch ex {
191
+ Return ..%WriteErrorResponse(ex.DisplayString())
192
+ }
193
+ }
194
+
195
+ ClassMethod PostComponentRestart() As %Status
196
+ {
197
+ Try {
198
+ Set dyna = {}.%FromJSON(%request.Content)
199
+ Set ns = ..ResolveNs(dyna)
200
+ Set component = dyna.%Get("component")
201
+ If component = "" { Set component = dyna.%Get("item") }
202
+ If component = "" { Throw $$$ERROR("NoComponentSpecified") }
203
+ If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
204
+ $$$ThrowOnError(##class(Ens.Director).EnableConfigItem(component, 0, 1))
205
+ $$$ThrowOnError(##class(Ens.Director).EnableConfigItem(component, 1, 1))
206
+ Return ..%WriteResponse({"status": "restarted", "component": (component)}.%ToJSON())
207
+ } Catch ex {
208
+ Return ..%WriteErrorResponse(ex.DisplayString())
209
+ }
210
+ }
211
+
212
+ ClassMethod DeleteBinding() As %Status
213
+ {
214
+ Try {
215
+ Set ns = ..GetNsParam()
216
+ Set classname = %request.Get("class")
217
+ If classname = "" { Set classname = %request.Get("classname") }
218
+ If classname = "" { Throw $$$ERROR("NoClassSpecified") }
219
+ If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
220
+ $$$ThrowOnError(##class(IOP.Utils).DeleteComponentProxy(classname))
221
+ Return ..%WriteResponse({"status": "unbound", "class": (classname)}.%ToJSON())
222
+ } Catch ex {
223
+ Return ..%WriteErrorResponse(ex.DisplayString())
224
+ }
225
+ }
226
+
227
+ ClassMethod GetBindings() As %Status
228
+ {
229
+ Try {
230
+ Set ns = ..GetNsParam()
231
+ Set unused = ..BooleanQueryParam(%request.Get("unused"))
232
+ If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
233
+ Set jsonStr = ##class(IOP.Utils).ListComponentProxies(unused)
234
+ Return ..%WriteResponse(jsonStr)
235
+ } Catch ex {
236
+ Return ..%WriteErrorResponse(ex.DisplayString())
237
+ }
238
+ }
239
+
240
+ ClassMethod BooleanQueryParam(pValue As %String) As %Boolean [ Internal, Private ]
241
+ {
242
+ Set value = $ZCONVERT(pValue,"L")
243
+ Quit $Select(value="1":1,value="true":1,value="yes":1,value="on":1,1:0)
244
+ }
245
+
144
246
  ClassMethod GetList() As %Status
145
247
  {
146
248
  Try {
@@ -248,8 +350,45 @@ ClassMethod GetExport() As %Status
248
350
  While 'xdata.AtEnd { Set xml = xml _ xdata.Read(32000) }
249
351
 
250
352
  // Convert to JSON via Python xmltodict
251
- Set iopUtils = ##class(IOP.Wrapper).Import("iop._utils")
252
- Set jsonStr = iopUtils."_Utils"."xml_to_json"(xml)
353
+ Set iopUtils = ##class(IOP.Wrapper).Import("iop.migration.utils")
354
+ Set builtins = ##class(%SYS.Python).Import("builtins")
355
+ If builtins.hasattr(iopUtils, "xml_to_json") {
356
+ Set jsonStr = builtins.getattr(iopUtils, "xml_to_json")."__call__"(xml)
357
+ } Else {
358
+ Set jsonStr = iopUtils."_Utils"."xml_to_json"(xml)
359
+ }
360
+ Return ..%WriteResponse(jsonStr)
361
+ } Catch ex {
362
+ Return ..%WriteErrorResponse(ex.DisplayString())
363
+ }
364
+ }
365
+
366
+ /// GET /connections?production=MyApp.Production&namespace=USER
367
+ /// Returns runtime graph connections from OnGetConnections.
368
+ ClassMethod GetConnections() As %Status
369
+ {
370
+ Try {
371
+ Set ns = ..GetNsParam()
372
+ If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
373
+ Set production = %request.Get("production")
374
+ If production = "" { Set production = $Get(^Ens.Configuration("csp","LastProduction"), "") }
375
+ Set jsonStr = ##class(IOP.Utils).ExportProductionConnections(production)
376
+ Return ..%WriteResponse(jsonStr)
377
+ } Catch ex {
378
+ Return ..%WriteErrorResponse(ex.DisplayString())
379
+ }
380
+ }
381
+
382
+ /// GET /queues?production=MyApp.Production&namespace=USER
383
+ /// Returns queue counters for production items.
384
+ ClassMethod GetQueues() As %Status
385
+ {
386
+ Try {
387
+ Set ns = ..GetNsParam()
388
+ If ns '= "" { Do ..NamespaceCheck(ns) New $NAMESPACE Set $NAMESPACE = ns }
389
+ Set production = %request.Get("production")
390
+ If production = "" { Set production = $Get(^Ens.Configuration("csp","LastProduction"), "") }
391
+ Set jsonStr = ##class(IOP.Utils).ExportProductionQueueInfo(production)
253
392
  Return ..%WriteResponse(jsonStr)
254
393
  } Catch ex {
255
394
  Return ..%WriteErrorResponse(ex.DisplayString())
@@ -359,6 +498,9 @@ ClassMethod PutMigrate() As %DynamicObject
359
498
  set namespace = ..ResolveNs(dyna)
360
499
  set targetDirectory = dyna.%Get("remote_folder")
361
500
  set packageName = dyna.%Get("package")
501
+ set settingsFile = dyna.%Get("settings_file")
502
+ set strictProductionValidation = dyna.%Get("strict_production_validation")
503
+ If settingsFile = "" { Set settingsFile = "settings.py" }
362
504
  // check for namespace existence and user permissions against namespace
363
505
  If '..NamespaceCheck(namespace) {
364
506
  Return ""
@@ -407,8 +549,13 @@ ClassMethod PutMigrate() As %DynamicObject
407
549
 
408
550
  //Do the iop migration
409
551
 
410
- set iopUtils = ##class(IOP.Wrapper).Import("iop._utils")
411
- do iopUtils."_Utils".migrate(##class(%Library.File).NormalizeFilename("settings.py", packagePath))
552
+ set iopUtils = ##class(IOP.Wrapper).Import("iop.migration.utils")
553
+ set builtins = ##class(%SYS.Python).Import("builtins")
554
+ If builtins.hasattr(iopUtils, "migrate") {
555
+ do builtins.getattr(iopUtils, "migrate")."__call__"(##class(%Library.File).NormalizeFilename(settingsFile, packagePath),"REMOTE",namespace,strictProductionValidation)
556
+ } Else {
557
+ do iopUtils."_Utils".migrate(##class(%Library.File).NormalizeFilename(settingsFile, packagePath))
558
+ }
412
559
  }
413
560
  Catch ex {
414
561
  $$$ThrowOnError(ex.AsStatus())