iris-pex-embedded-python 3.7.2b1__py3-none-any.whl → 3.7.2b2__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.
- grongier/pex/__init__.py +9 -0
- iop/__init__.py +9 -0
- iop/_cli.py +29 -0
- iop/_common.py +240 -78
- iop/_local.py +1 -1
- iop/_polling_business_service.py +6 -0
- iop/_settings.py +188 -0
- iop/_utils.py +219 -17
- iop/cls/IOP/Utils.cls +21 -1
- {iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/METADATA +1 -1
- {iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/RECORD +15 -13
- {iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/WHEEL +0 -0
- {iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/entry_points.txt +0 -0
- {iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/licenses/LICENSE +0 -0
- {iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/top_level.txt +0 -0
grongier/pex/__init__.py
CHANGED
|
@@ -6,11 +6,16 @@ from iop._inbound_adapter import _InboundAdapter
|
|
|
6
6
|
from iop._message import _Message
|
|
7
7
|
from iop._message import _PickleMessage
|
|
8
8
|
from iop._outbound_adapter import _OutboundAdapter
|
|
9
|
+
from iop._polling_business_service import _PollingBusinessServiceMixin
|
|
9
10
|
from iop._persistent_message import Field as Field
|
|
10
11
|
from iop._persistent_message import Model as Model
|
|
11
12
|
from iop._persistent_message import _PersistentMessage
|
|
12
13
|
from iop._private_session_duplex import _PrivateSessionDuplex
|
|
13
14
|
from iop._private_session_process import _PrivateSessionProcess
|
|
15
|
+
from iop._settings import Category as Category
|
|
16
|
+
from iop._settings import Setting as Setting
|
|
17
|
+
from iop._settings import controls as controls
|
|
18
|
+
from iop._settings import setting as setting
|
|
14
19
|
from iop._utils import _Utils
|
|
15
20
|
|
|
16
21
|
|
|
@@ -30,6 +35,10 @@ class BusinessService(_BusinessService):
|
|
|
30
35
|
pass
|
|
31
36
|
|
|
32
37
|
|
|
38
|
+
class PollingBusinessService(_PollingBusinessServiceMixin, BusinessService):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
33
42
|
class BusinessOperation(_BusinessOperation):
|
|
34
43
|
pass
|
|
35
44
|
|
iop/__init__.py
CHANGED
|
@@ -10,11 +10,16 @@ from iop._message import (
|
|
|
10
10
|
_PydanticPickleMessage,
|
|
11
11
|
)
|
|
12
12
|
from iop._outbound_adapter import _OutboundAdapter
|
|
13
|
+
from iop._polling_business_service import _PollingBusinessServiceMixin
|
|
13
14
|
from iop._persistent_message import Field as Field
|
|
14
15
|
from iop._persistent_message import Model as Model
|
|
15
16
|
from iop._persistent_message import _PersistentMessage
|
|
16
17
|
from iop._private_session_duplex import _PrivateSessionDuplex
|
|
17
18
|
from iop._private_session_process import _PrivateSessionProcess
|
|
19
|
+
from iop._settings import Category as Category
|
|
20
|
+
from iop._settings import Setting as Setting
|
|
21
|
+
from iop._settings import controls as controls
|
|
22
|
+
from iop._settings import setting as setting
|
|
18
23
|
from iop._utils import _Utils
|
|
19
24
|
|
|
20
25
|
|
|
@@ -34,6 +39,10 @@ class BusinessService(_BusinessService):
|
|
|
34
39
|
pass
|
|
35
40
|
|
|
36
41
|
|
|
42
|
+
class PollingBusinessService(_PollingBusinessServiceMixin, BusinessService):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
37
46
|
class BusinessOperation(_BusinessOperation):
|
|
38
47
|
pass
|
|
39
48
|
|
iop/_cli.py
CHANGED
|
@@ -13,6 +13,7 @@ from importlib.metadata import version
|
|
|
13
13
|
from ._local import _LocalDirector
|
|
14
14
|
from ._remote import _RemoteDirector, get_remote_settings
|
|
15
15
|
from ._director_protocol import DirectorProtocol
|
|
16
|
+
from ._utils import _Utils
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class CommandType(Enum):
|
|
@@ -57,6 +58,7 @@ class CommandArgs:
|
|
|
57
58
|
force_local: bool = False
|
|
58
59
|
remote_settings: Optional[str] = None
|
|
59
60
|
update: bool = False
|
|
61
|
+
migration_plan: bool = False
|
|
60
62
|
|
|
61
63
|
|
|
62
64
|
class Command:
|
|
@@ -252,7 +254,27 @@ class Command:
|
|
|
252
254
|
if migrate_path is not None:
|
|
253
255
|
if not os.path.isabs(migrate_path):
|
|
254
256
|
migrate_path = os.path.join(os.getcwd(), migrate_path)
|
|
257
|
+
mode = "REMOTE" if self._is_remote else "LOCAL"
|
|
258
|
+
if self.args.migration_plan:
|
|
259
|
+
print(
|
|
260
|
+
_Utils.explain_migration(
|
|
261
|
+
migrate_path, mode=mode, namespace=self.director.namespace
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
return
|
|
265
|
+
if self._is_remote:
|
|
266
|
+
print(
|
|
267
|
+
_Utils.explain_migration(
|
|
268
|
+
migrate_path, mode=mode, namespace=self.director.namespace
|
|
269
|
+
)
|
|
270
|
+
)
|
|
255
271
|
self.director.migrate(migrate_path)
|
|
272
|
+
if self._is_remote:
|
|
273
|
+
print(
|
|
274
|
+
_Utils.format_migration_success(
|
|
275
|
+
migrate_path, namespace=self.director.namespace
|
|
276
|
+
)
|
|
277
|
+
)
|
|
256
278
|
|
|
257
279
|
def _handle_log(self) -> None:
|
|
258
280
|
if self.args.log == "not_set":
|
|
@@ -406,6 +428,13 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
406
428
|
help="force local mode, skip remote even if REMOTE_SETTINGS or IOP_URL is present",
|
|
407
429
|
action="store_true",
|
|
408
430
|
)
|
|
431
|
+
migrate.add_argument(
|
|
432
|
+
"--dry-run",
|
|
433
|
+
"--explain",
|
|
434
|
+
dest="migration_plan",
|
|
435
|
+
help="show the migration plan and validation messages without writing to IRIS",
|
|
436
|
+
action="store_true",
|
|
437
|
+
)
|
|
409
438
|
|
|
410
439
|
remote = main_parser.add_argument_group("remote arguments")
|
|
411
440
|
remote.add_argument(
|
iop/_common.py
CHANGED
|
@@ -1,11 +1,143 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import inspect
|
|
3
3
|
import traceback
|
|
4
|
-
from
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from types import UnionType
|
|
6
|
+
from typing import (
|
|
7
|
+
Annotated,
|
|
8
|
+
Any,
|
|
9
|
+
ClassVar,
|
|
10
|
+
List,
|
|
11
|
+
Optional,
|
|
12
|
+
Tuple,
|
|
13
|
+
Union,
|
|
14
|
+
get_args,
|
|
15
|
+
get_origin,
|
|
16
|
+
get_type_hints,
|
|
17
|
+
)
|
|
5
18
|
|
|
6
19
|
from . import _iris
|
|
7
|
-
from ._log_manager import LogManager, logging
|
|
8
20
|
from ._debugpy import debugpython
|
|
21
|
+
from ._log_manager import LogManager, logging
|
|
22
|
+
from ._settings import Setting
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_NO_VALUE = object()
|
|
26
|
+
|
|
27
|
+
_EXCLUDED_SETTING_NAMES = {
|
|
28
|
+
"INFO_URL",
|
|
29
|
+
"ICON_URL",
|
|
30
|
+
"PERSISTENT_PROPERTY_LIST",
|
|
31
|
+
"log_to_console",
|
|
32
|
+
"logger",
|
|
33
|
+
"iris_handle",
|
|
34
|
+
"DISPATCH",
|
|
35
|
+
"adapter",
|
|
36
|
+
"Adapter",
|
|
37
|
+
"buffer",
|
|
38
|
+
"BusinessHost",
|
|
39
|
+
"business_host",
|
|
40
|
+
"business_host_python",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_PYTHON_TYPE_TO_IRIS = {
|
|
44
|
+
int: "Integer",
|
|
45
|
+
float: "Numeric",
|
|
46
|
+
complex: "Numeric",
|
|
47
|
+
bool: "Boolean",
|
|
48
|
+
str: "String",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_SIMPLE_TYPE_NAMES = {
|
|
52
|
+
"int": "Integer",
|
|
53
|
+
"integer": "Integer",
|
|
54
|
+
"float": "Numeric",
|
|
55
|
+
"complex": "Numeric",
|
|
56
|
+
"number": "Numeric",
|
|
57
|
+
"numeric": "Numeric",
|
|
58
|
+
"bool": "Boolean",
|
|
59
|
+
"boolean": "Boolean",
|
|
60
|
+
"str": "String",
|
|
61
|
+
"string": "String",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _string_metadata(value: Any) -> str:
|
|
66
|
+
if value is None:
|
|
67
|
+
return ""
|
|
68
|
+
if isinstance(value, Enum):
|
|
69
|
+
return str(value.value)
|
|
70
|
+
return str(value)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _type_hints_with_extras(cls) -> dict[str, Any]:
|
|
74
|
+
try:
|
|
75
|
+
return get_type_hints(cls, include_extras=True)
|
|
76
|
+
except Exception:
|
|
77
|
+
hints: dict[str, Any] = {}
|
|
78
|
+
for base in reversed(inspect.getmro(cls)):
|
|
79
|
+
hints.update(getattr(base, "__annotations__", {}))
|
|
80
|
+
return hints
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _unwrap_annotated(data_type: Any) -> tuple[Any, tuple[Any, ...]]:
|
|
84
|
+
if get_origin(data_type) is Annotated:
|
|
85
|
+
args = get_args(data_type)
|
|
86
|
+
if args:
|
|
87
|
+
return args[0], args[1:]
|
|
88
|
+
return data_type, ()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _setting_from_annotation(data_type: Any) -> tuple[Any, Optional[Setting]]:
|
|
92
|
+
data_type, metadata = _unwrap_annotated(data_type)
|
|
93
|
+
setting = None
|
|
94
|
+
for item in metadata:
|
|
95
|
+
if isinstance(item, Setting):
|
|
96
|
+
setting = item
|
|
97
|
+
return data_type, setting
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _unwrap_optional(data_type: Any) -> Any:
|
|
101
|
+
origin = get_origin(data_type)
|
|
102
|
+
if origin in (Union, UnionType):
|
|
103
|
+
args = [arg for arg in get_args(data_type) if arg is not type(None)]
|
|
104
|
+
if len(args) == 1:
|
|
105
|
+
return args[0]
|
|
106
|
+
return data_type
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _iris_data_type(data_type: Any) -> Optional[str]:
|
|
110
|
+
if data_type is None or data_type == "":
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
data_type, _ = _unwrap_annotated(data_type)
|
|
114
|
+
data_type = _unwrap_optional(data_type)
|
|
115
|
+
|
|
116
|
+
if data_type is Any or data_type is object:
|
|
117
|
+
return "String"
|
|
118
|
+
|
|
119
|
+
if isinstance(data_type, str):
|
|
120
|
+
data_type = data_type.strip()
|
|
121
|
+
return _SIMPLE_TYPE_NAMES.get(data_type.lower(), data_type)
|
|
122
|
+
|
|
123
|
+
if data_type in _PYTHON_TYPE_TO_IRIS:
|
|
124
|
+
return _PYTHON_TYPE_TO_IRIS[data_type]
|
|
125
|
+
|
|
126
|
+
origin = get_origin(data_type)
|
|
127
|
+
if origin in _PYTHON_TYPE_TO_IRIS:
|
|
128
|
+
return _PYTHON_TYPE_TO_IRIS[origin]
|
|
129
|
+
if origin is not None:
|
|
130
|
+
return "String"
|
|
131
|
+
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _is_setting_member(name: str, value: Any) -> bool:
|
|
136
|
+
if name.startswith("_") or name in _EXCLUDED_SETTING_NAMES:
|
|
137
|
+
return False
|
|
138
|
+
return not (
|
|
139
|
+
inspect.ismethod(value) or inspect.isfunction(value) or inspect.isclass(value)
|
|
140
|
+
)
|
|
9
141
|
|
|
10
142
|
|
|
11
143
|
class _Common(metaclass=abc.ABCMeta):
|
|
@@ -168,87 +300,117 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
168
300
|
- Required flag
|
|
169
301
|
- Category
|
|
170
302
|
- Description
|
|
303
|
+
- Control/editor context
|
|
171
304
|
|
|
172
305
|
Only includes non-private class attributes and properties.
|
|
173
306
|
"""
|
|
174
307
|
ret = []
|
|
175
308
|
try:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
309
|
+
annotations = _type_hints_with_extras(cls)
|
|
310
|
+
members = dict(inspect.getmembers(cls))
|
|
311
|
+
|
|
312
|
+
names = [
|
|
313
|
+
name
|
|
314
|
+
for name, value in members.items()
|
|
315
|
+
if _is_setting_member(name, value)
|
|
316
|
+
]
|
|
317
|
+
for name in annotations:
|
|
318
|
+
if (
|
|
319
|
+
name in names
|
|
320
|
+
or name.startswith("_")
|
|
321
|
+
or name in _EXCLUDED_SETTING_NAMES
|
|
322
|
+
):
|
|
323
|
+
continue
|
|
324
|
+
value = members.get(name, _NO_VALUE)
|
|
325
|
+
if value is not _NO_VALUE and not _is_setting_member(name, value):
|
|
326
|
+
continue
|
|
327
|
+
names.append(name)
|
|
328
|
+
|
|
329
|
+
for name in names:
|
|
330
|
+
member_exists = name in members
|
|
331
|
+
val = members.get(name, "")
|
|
332
|
+
annotated_type, annotated_setting = _setting_from_annotation(
|
|
333
|
+
annotations.get(name)
|
|
334
|
+
)
|
|
335
|
+
value_setting = val if isinstance(val, Setting) else None
|
|
336
|
+
setting_info = value_setting or annotated_setting
|
|
337
|
+
|
|
338
|
+
if setting_info is not None and setting_info.exclude:
|
|
339
|
+
continue
|
|
340
|
+
|
|
341
|
+
req = bool(setting_info.required) if setting_info is not None else False
|
|
342
|
+
cat = setting_info.category if setting_info is not None else ""
|
|
343
|
+
desc = setting_info.description if setting_info is not None else ""
|
|
344
|
+
control = setting_info.control if setting_info is not None else ""
|
|
345
|
+
|
|
346
|
+
if value_setting is not None:
|
|
347
|
+
val = value_setting.default if value_setting.has_default else ""
|
|
348
|
+
elif (
|
|
349
|
+
not member_exists
|
|
350
|
+
and annotated_setting is not None
|
|
351
|
+
and annotated_setting.has_default
|
|
352
|
+
):
|
|
353
|
+
val = annotated_setting.default
|
|
354
|
+
elif not member_exists:
|
|
355
|
+
val = ""
|
|
356
|
+
|
|
357
|
+
if isinstance(val, property) or (val is None):
|
|
358
|
+
val = ""
|
|
359
|
+
|
|
360
|
+
if setting_info is not None and setting_info.iris_type:
|
|
361
|
+
data_type = setting_info.iris_type
|
|
362
|
+
else:
|
|
363
|
+
data_type_source = (
|
|
364
|
+
setting_info.data_type
|
|
365
|
+
if setting_info is not None and setting_info.data_type
|
|
366
|
+
else annotated_type
|
|
367
|
+
)
|
|
368
|
+
data_type = _iris_data_type(data_type_source)
|
|
369
|
+
if data_type is None:
|
|
370
|
+
data_type = _iris_data_type(type(val)) or "String"
|
|
371
|
+
|
|
372
|
+
# Legacy attr_info() support. Values supplied here keep working
|
|
373
|
+
# and can also provide the new control/editor context field.
|
|
374
|
+
if hasattr(cls, name + "_info"):
|
|
375
|
+
func = getattr(cls, name + "_info")
|
|
376
|
+
if callable(func):
|
|
377
|
+
info_annotations = getattr(func, "__annotations__", {}).get(
|
|
378
|
+
"return"
|
|
379
|
+
)
|
|
380
|
+
if info_annotations is not None:
|
|
381
|
+
if bool(info_annotations.get("ExcludeFromSettings")):
|
|
382
|
+
continue
|
|
383
|
+
req = bool(info_annotations.get("IsRequired", req))
|
|
384
|
+
cat = _string_metadata(
|
|
385
|
+
info_annotations.get("Category", cat)
|
|
386
|
+
)
|
|
387
|
+
desc = _string_metadata(
|
|
388
|
+
info_annotations.get("Description", desc)
|
|
389
|
+
)
|
|
390
|
+
control = _string_metadata(
|
|
391
|
+
info_annotations.get(
|
|
392
|
+
"Control",
|
|
393
|
+
info_annotations.get("EditorContext", control),
|
|
394
|
+
)
|
|
395
|
+
)
|
|
396
|
+
dt = info_annotations.get("DataType")
|
|
397
|
+
if (dt is not None) and ("" != dt):
|
|
398
|
+
data_type = _iris_data_type(dt) or str(dt)
|
|
399
|
+
default = func()
|
|
400
|
+
if default is not None:
|
|
401
|
+
val = default
|
|
402
|
+
|
|
403
|
+
ret.append(
|
|
404
|
+
[
|
|
405
|
+
name, # Name
|
|
406
|
+
data_type, # DataType
|
|
407
|
+
val, # Default Value
|
|
408
|
+
req, # Required
|
|
409
|
+
_string_metadata(cat), # Category
|
|
410
|
+
_string_metadata(desc), # Description
|
|
411
|
+
_string_metadata(control), # Control/editor context
|
|
412
|
+
]
|
|
413
|
+
)
|
|
252
414
|
except Exception:
|
|
253
415
|
pass
|
|
254
416
|
return ret
|
iop/_local.py
CHANGED
|
@@ -95,7 +95,7 @@ class _LocalDirector(_DirectorProtocol):
|
|
|
95
95
|
# ------------------------------------------------------------------
|
|
96
96
|
|
|
97
97
|
def migrate(self, path: str) -> None:
|
|
98
|
-
_Utils.migrate(path)
|
|
98
|
+
_Utils.migrate(path, mode="LOCAL", namespace=self.namespace)
|
|
99
99
|
|
|
100
100
|
# ------------------------------------------------------------------
|
|
101
101
|
# Metadata
|
iop/_settings.py
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
_MISSING = object()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Category(str, Enum):
|
|
9
|
+
"""Common IRIS production setting categories for Management Portal grouping."""
|
|
10
|
+
|
|
11
|
+
INFO = "Info"
|
|
12
|
+
BASIC = "Basic"
|
|
13
|
+
CONNECTION = "Connection"
|
|
14
|
+
ADDITIONAL = "Additional"
|
|
15
|
+
ALERTING = "Alerting"
|
|
16
|
+
DEV = "Dev"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _string_value(value: Any) -> str:
|
|
20
|
+
if isinstance(value, Enum):
|
|
21
|
+
return str(value.value)
|
|
22
|
+
return str(value)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Setting:
|
|
26
|
+
"""Metadata for an IRIS production setting."""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
default: Any = _MISSING,
|
|
31
|
+
*,
|
|
32
|
+
data_type: Any = None,
|
|
33
|
+
iris_type: str | None = None,
|
|
34
|
+
category: str | Category | None = None,
|
|
35
|
+
required: bool = False,
|
|
36
|
+
description: str = "",
|
|
37
|
+
control: str | None = None,
|
|
38
|
+
exclude: bool = False,
|
|
39
|
+
):
|
|
40
|
+
self.default = default
|
|
41
|
+
self.data_type = data_type
|
|
42
|
+
self.iris_type = iris_type
|
|
43
|
+
self.category = _string_value(category) if category is not None else None
|
|
44
|
+
self.required = required
|
|
45
|
+
self.description = description or ""
|
|
46
|
+
self.control = control or ""
|
|
47
|
+
self.exclude = exclude
|
|
48
|
+
self.name = ""
|
|
49
|
+
|
|
50
|
+
def __set_name__(self, owner, name):
|
|
51
|
+
self.name = name
|
|
52
|
+
|
|
53
|
+
def __get__(self, instance, owner=None):
|
|
54
|
+
if instance is None:
|
|
55
|
+
return self
|
|
56
|
+
if self.name in instance.__dict__:
|
|
57
|
+
return instance.__dict__[self.name]
|
|
58
|
+
if self.default is _MISSING:
|
|
59
|
+
return None
|
|
60
|
+
return self.default
|
|
61
|
+
|
|
62
|
+
def __set__(self, instance, value):
|
|
63
|
+
instance.__dict__[self.name] = value
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def has_default(self) -> bool:
|
|
67
|
+
return self.default is not _MISSING
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def setting(default: Any = _MISSING, **kwargs) -> Setting:
|
|
71
|
+
return Setting(default, **kwargs)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class _Controls:
|
|
75
|
+
"""Helpers for IRIS production setting editor controls."""
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def raw(value: str) -> str:
|
|
79
|
+
"""Return an advanced IRIS editor context string unchanged."""
|
|
80
|
+
return value
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def selector(
|
|
84
|
+
context: str | None = None, *, multi_select: bool | None = None, **params
|
|
85
|
+
) -> str:
|
|
86
|
+
"""Build an IRIS selector editor context from a context search string."""
|
|
87
|
+
query = []
|
|
88
|
+
if multi_select is not None:
|
|
89
|
+
query.append(f"multiSelect={1 if multi_select else 0}")
|
|
90
|
+
if context:
|
|
91
|
+
if not (context.startswith("{") and context.endswith("}")):
|
|
92
|
+
context = "{" + context + "}"
|
|
93
|
+
query.append(f"context={context}")
|
|
94
|
+
for key, value in params.items():
|
|
95
|
+
if value is not None:
|
|
96
|
+
query.append(f"{key}={value}")
|
|
97
|
+
return "selector" + (f"?{'&'.join(query)}" if query else "")
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def production_item(
|
|
101
|
+
*,
|
|
102
|
+
targets: bool = True,
|
|
103
|
+
production_name: str = "@productionId",
|
|
104
|
+
multi_select: bool = False,
|
|
105
|
+
) -> str:
|
|
106
|
+
"""Select production items, normally target components, from a production."""
|
|
107
|
+
context = (
|
|
108
|
+
"Ens.ContextSearch/ProductionItems?"
|
|
109
|
+
f"targets={1 if targets else 0}&productionName={production_name}"
|
|
110
|
+
)
|
|
111
|
+
return _Controls.selector(context, multi_select=multi_select or None)
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def partner() -> str:
|
|
115
|
+
"""Select a partner setting value."""
|
|
116
|
+
return "partnerSelector"
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def rule() -> str:
|
|
120
|
+
"""Select an IRIS rule definition."""
|
|
121
|
+
return "ruleSelector"
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def credentials() -> str:
|
|
125
|
+
"""Select an IRIS credentials entry."""
|
|
126
|
+
return "credentialsSelector"
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
def directory() -> str:
|
|
130
|
+
"""Select a directory path."""
|
|
131
|
+
return "directorySelector"
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def file() -> str:
|
|
135
|
+
"""Select a file path."""
|
|
136
|
+
return "fileSelector"
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def dtl() -> str:
|
|
140
|
+
"""Select an IRIS DTL data transformation."""
|
|
141
|
+
return "dtlSelector"
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def schedule() -> str:
|
|
145
|
+
"""Select an IRIS schedule."""
|
|
146
|
+
return "scheduleSelector"
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def ssl_config() -> str:
|
|
150
|
+
"""Select an IRIS SSL/TLS configuration."""
|
|
151
|
+
return "sslConfigSelector"
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def bpl() -> str:
|
|
155
|
+
"""Select an IRIS BPL business process."""
|
|
156
|
+
return "bplSelector"
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def character_set() -> str:
|
|
160
|
+
"""Select an IRIS character set."""
|
|
161
|
+
return _Controls.selector("Ens.ContextSearch/CharacterSets")
|
|
162
|
+
|
|
163
|
+
charset = character_set
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def framing(*, host: str = "@currHostId", prop: str = "Framing") -> str:
|
|
167
|
+
"""Select a display-list value such as the current host framing option."""
|
|
168
|
+
return _Controls.selector(
|
|
169
|
+
f"Ens.ContextSearch/getDisplayList?host={host}&prop={prop}"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def local_interface() -> str:
|
|
174
|
+
"""Select a configured TCP local interface."""
|
|
175
|
+
return _Controls.selector("Ens.ContextSearch/TCPLocalInterfaces")
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def schema_category(host: str) -> str:
|
|
179
|
+
"""Select a schema category for the specified host expression."""
|
|
180
|
+
return _Controls.selector(f"Ens.ContextSearch/SchemaCategories?host={host}")
|
|
181
|
+
|
|
182
|
+
@staticmethod
|
|
183
|
+
def search_table(host: str) -> str:
|
|
184
|
+
"""Select a search table class for the specified host expression."""
|
|
185
|
+
return _Controls.selector(f"Ens.ContextSearch/SearchTableClasses?host={host}")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
controls = _Controls()
|
iop/_utils.py
CHANGED
|
@@ -6,7 +6,7 @@ import importlib.resources
|
|
|
6
6
|
import json
|
|
7
7
|
import inspect
|
|
8
8
|
import ast
|
|
9
|
-
from typing import Optional, Tuple
|
|
9
|
+
from typing import Any, Optional, Tuple
|
|
10
10
|
|
|
11
11
|
import xmltodict
|
|
12
12
|
from pydantic import TypeAdapter
|
|
@@ -71,6 +71,13 @@ class _Utils:
|
|
|
71
71
|
|
|
72
72
|
:param cls: The class to register
|
|
73
73
|
"""
|
|
74
|
+
if is_persistent_message_class(msg_cls):
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"{_Utils._python_classname(msg_cls)} is a PersistentMessage. "
|
|
77
|
+
"Register it in CLASSES, not SCHEMAS."
|
|
78
|
+
)
|
|
79
|
+
if not inspect.isclass(msg_cls):
|
|
80
|
+
raise ValueError("SCHEMAS entries must be message classes.")
|
|
74
81
|
if issubclass(msg_cls, _PydanticMessage):
|
|
75
82
|
schema = msg_cls.model_json_schema()
|
|
76
83
|
elif issubclass(msg_cls, _Message):
|
|
@@ -78,7 +85,8 @@ class _Utils:
|
|
|
78
85
|
schema = type_adapter.json_schema()
|
|
79
86
|
else:
|
|
80
87
|
raise ValueError(
|
|
81
|
-
"
|
|
88
|
+
f"{_Utils._python_classname(msg_cls)} cannot be registered as a "
|
|
89
|
+
"DTL schema. Use a Message or PydanticMessage subclass."
|
|
82
90
|
)
|
|
83
91
|
schema_name = msg_cls.__module__ + "." + msg_cls.__name__
|
|
84
92
|
schema_str = json.dumps(schema)
|
|
@@ -118,6 +126,23 @@ class _Utils:
|
|
|
118
126
|
msg_cls, iris_classname, sync_schema=sync_schema
|
|
119
127
|
)
|
|
120
128
|
|
|
129
|
+
@staticmethod
|
|
130
|
+
def _python_classname(value: Any) -> str:
|
|
131
|
+
module = getattr(value, "__module__", "")
|
|
132
|
+
name = getattr(value, "__name__", repr(value))
|
|
133
|
+
return f"{module}.{name}" if module else str(name)
|
|
134
|
+
|
|
135
|
+
@staticmethod
|
|
136
|
+
def _is_message_schema_class(value: Any) -> bool:
|
|
137
|
+
try:
|
|
138
|
+
return (
|
|
139
|
+
inspect.isclass(value)
|
|
140
|
+
and (issubclass(value, _Message) or issubclass(value, _PydanticMessage))
|
|
141
|
+
and not is_persistent_message_class(value)
|
|
142
|
+
)
|
|
143
|
+
except TypeError:
|
|
144
|
+
return False
|
|
145
|
+
|
|
121
146
|
@staticmethod
|
|
122
147
|
def get_python_settings() -> Tuple[str, str, str]:
|
|
123
148
|
import iris_utils._cli
|
|
@@ -268,6 +293,7 @@ class _Utils:
|
|
|
268
293
|
"BusinessOperation",
|
|
269
294
|
"BusinessProcess",
|
|
270
295
|
"BusinessService",
|
|
296
|
+
"PollingBusinessService",
|
|
271
297
|
"DuplexService",
|
|
272
298
|
"DuplexProcess",
|
|
273
299
|
"DuplexOperation",
|
|
@@ -329,7 +355,9 @@ class _Utils:
|
|
|
329
355
|
return module
|
|
330
356
|
|
|
331
357
|
@staticmethod
|
|
332
|
-
def migrate(
|
|
358
|
+
def migrate(
|
|
359
|
+
filename=None, mode: Optional[str] = None, namespace: Optional[str] = None
|
|
360
|
+
):
|
|
333
361
|
"""
|
|
334
362
|
Read the settings.py file and register all the components
|
|
335
363
|
settings.py file has two dictionaries:
|
|
@@ -345,9 +373,120 @@ class _Utils:
|
|
|
345
373
|
"""
|
|
346
374
|
settings, path = _Utils._load_settings(filename)
|
|
347
375
|
|
|
348
|
-
|
|
376
|
+
try:
|
|
377
|
+
plan = _Utils._build_migration_plan(
|
|
378
|
+
settings, path, filename, mode=mode, namespace=namespace
|
|
379
|
+
)
|
|
380
|
+
print(_Utils.format_migration_plan(plan))
|
|
381
|
+
_Utils._register_settings_components(settings, path)
|
|
382
|
+
print(
|
|
383
|
+
_Utils.format_migration_success(
|
|
384
|
+
filename or inspect.getfile(settings), namespace=namespace
|
|
385
|
+
)
|
|
386
|
+
)
|
|
387
|
+
finally:
|
|
388
|
+
_Utils._cleanup_sys_path(path)
|
|
389
|
+
|
|
390
|
+
@staticmethod
|
|
391
|
+
def explain_migration(
|
|
392
|
+
filename=None, mode: Optional[str] = None, namespace: Optional[str] = None
|
|
393
|
+
):
|
|
394
|
+
"""Return a human-readable migration plan without writing to IRIS."""
|
|
395
|
+
settings, path = _Utils._load_settings(filename)
|
|
396
|
+
try:
|
|
397
|
+
plan = _Utils._build_migration_plan(
|
|
398
|
+
settings, path, filename, mode=mode, namespace=namespace
|
|
399
|
+
)
|
|
400
|
+
return _Utils.format_migration_plan(plan)
|
|
401
|
+
finally:
|
|
402
|
+
_Utils._cleanup_sys_path(path)
|
|
403
|
+
|
|
404
|
+
@staticmethod
|
|
405
|
+
def format_migration_success(filename, namespace: Optional[str] = None):
|
|
406
|
+
suffix = f" in namespace {namespace}" if namespace else ""
|
|
407
|
+
return f"Migration succeeded{suffix}: {filename}"
|
|
349
408
|
|
|
350
|
-
|
|
409
|
+
@staticmethod
|
|
410
|
+
def format_migration_plan(plan):
|
|
411
|
+
"""Format a migration plan for CLI and migration output."""
|
|
412
|
+
lines = [f"Migration plan: {plan['settings']}"]
|
|
413
|
+
if plan.get("mode"):
|
|
414
|
+
lines.append(f"Mode: {plan['mode']}")
|
|
415
|
+
if plan.get("namespace"):
|
|
416
|
+
lines.append(f"Namespace: {plan['namespace']}")
|
|
417
|
+
lines.append("")
|
|
418
|
+
lines.extend(_Utils._format_plan_section("CLASSES", plan["classes"]))
|
|
419
|
+
lines.extend(_Utils._format_plan_section("SCHEMAS", plan["schemas"]))
|
|
420
|
+
lines.extend(_Utils._format_plan_section("PRODUCTIONS", plan["productions"]))
|
|
421
|
+
return "\n".join(lines)
|
|
422
|
+
|
|
423
|
+
@staticmethod
|
|
424
|
+
def _format_plan_section(title, entries):
|
|
425
|
+
lines = [f"{title}:"]
|
|
426
|
+
if entries:
|
|
427
|
+
lines.extend(f" {entry}" for entry in entries)
|
|
428
|
+
else:
|
|
429
|
+
lines.append(" none")
|
|
430
|
+
lines.append("")
|
|
431
|
+
return lines
|
|
432
|
+
|
|
433
|
+
@staticmethod
|
|
434
|
+
def _build_migration_plan(
|
|
435
|
+
settings,
|
|
436
|
+
path,
|
|
437
|
+
filename=None,
|
|
438
|
+
mode: Optional[str] = None,
|
|
439
|
+
namespace: Optional[str] = None,
|
|
440
|
+
):
|
|
441
|
+
"""Build and validate a migration plan from a settings module."""
|
|
442
|
+
if not path:
|
|
443
|
+
path = os.path.dirname(inspect.getfile(settings))
|
|
444
|
+
|
|
445
|
+
plan = {
|
|
446
|
+
"settings": filename or inspect.getfile(settings),
|
|
447
|
+
"mode": mode,
|
|
448
|
+
"namespace": namespace,
|
|
449
|
+
"classes": [],
|
|
450
|
+
"schemas": [],
|
|
451
|
+
"productions": [],
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
classes = getattr(settings, "CLASSES", {})
|
|
455
|
+
if not isinstance(classes, dict):
|
|
456
|
+
raise ValueError("CLASSES must be a dictionary.")
|
|
457
|
+
for key, value in classes.items():
|
|
458
|
+
kind, target = _Utils._classify_class_setting(value, path)
|
|
459
|
+
if kind == "message_schema":
|
|
460
|
+
schema_hint = value.__name__ if inspect.isclass(value) else target
|
|
461
|
+
raise ValueError(
|
|
462
|
+
f"{target} is a Message/PydanticMessage and cannot be registered "
|
|
463
|
+
f"in CLASSES. Use SCHEMAS = [{schema_hint}] if you "
|
|
464
|
+
"need DTL support. Otherwise, no migration is required for this "
|
|
465
|
+
"message."
|
|
466
|
+
)
|
|
467
|
+
if kind == "persistent_message":
|
|
468
|
+
plan["classes"].append(f"{key} -> {target} (PersistentMessage)")
|
|
469
|
+
else:
|
|
470
|
+
plan["classes"].append(f"{key} -> {target} (component)")
|
|
471
|
+
|
|
472
|
+
schemas = getattr(settings, "SCHEMAS", None)
|
|
473
|
+
if schemas is not None:
|
|
474
|
+
if not isinstance(schemas, list):
|
|
475
|
+
raise ValueError("SCHEMAS must be a list of message classes.")
|
|
476
|
+
for cls in schemas:
|
|
477
|
+
_Utils._validate_dtl_schema_class(cls, "SCHEMAS")
|
|
478
|
+
plan["schemas"].append(_Utils._python_classname(cls))
|
|
479
|
+
|
|
480
|
+
productions = getattr(settings, "PRODUCTIONS", None)
|
|
481
|
+
if productions is not None:
|
|
482
|
+
if not isinstance(productions, list):
|
|
483
|
+
raise ValueError("PRODUCTIONS must be a list.")
|
|
484
|
+
for production in productions:
|
|
485
|
+
if not isinstance(production, dict) or not production:
|
|
486
|
+
raise ValueError("Each PRODUCTION entry must be a non-empty dict.")
|
|
487
|
+
plan["productions"].append(next(iter(production.keys())))
|
|
488
|
+
|
|
489
|
+
return plan
|
|
351
490
|
|
|
352
491
|
@staticmethod
|
|
353
492
|
def _load_settings(filename):
|
|
@@ -390,6 +529,52 @@ class _Utils:
|
|
|
390
529
|
else:
|
|
391
530
|
return os.getcwd()
|
|
392
531
|
|
|
532
|
+
@staticmethod
|
|
533
|
+
def _classify_class_setting(value, root_path=None):
|
|
534
|
+
if inspect.isclass(value):
|
|
535
|
+
if is_persistent_message_class(value):
|
|
536
|
+
return "persistent_message", _Utils._python_classname(value)
|
|
537
|
+
if _Utils._is_message_schema_class(value):
|
|
538
|
+
return "message_schema", _Utils._python_classname(value)
|
|
539
|
+
return "component", _Utils._python_classname(value)
|
|
540
|
+
|
|
541
|
+
if inspect.ismodule(value):
|
|
542
|
+
return "component", f"{value.__name__}.*"
|
|
543
|
+
|
|
544
|
+
if isinstance(value, dict):
|
|
545
|
+
if "path" in value and "module" in value and "class" in value:
|
|
546
|
+
cls = _Utils._try_import_class(
|
|
547
|
+
value["module"], value["class"], value["path"]
|
|
548
|
+
)
|
|
549
|
+
target = f"{value['module']}.{value['class']}"
|
|
550
|
+
if cls is not None:
|
|
551
|
+
if is_persistent_message_class(cls):
|
|
552
|
+
return "persistent_message", target
|
|
553
|
+
if _Utils._is_message_schema_class(cls):
|
|
554
|
+
return "message_schema", target
|
|
555
|
+
return "component", target
|
|
556
|
+
if "path" in value and "package" in value:
|
|
557
|
+
return "component", f"{value['package']} package"
|
|
558
|
+
if "path" in value and "file" in value:
|
|
559
|
+
return "component", value["file"]
|
|
560
|
+
if "path" in value:
|
|
561
|
+
return "component", value["path"]
|
|
562
|
+
|
|
563
|
+
raise ValueError(f"Invalid migration class entry: {value!r}.")
|
|
564
|
+
|
|
565
|
+
@staticmethod
|
|
566
|
+
def _validate_dtl_schema_class(cls, setting_name):
|
|
567
|
+
if is_persistent_message_class(cls):
|
|
568
|
+
raise ValueError(
|
|
569
|
+
f"{_Utils._python_classname(cls)} is a PersistentMessage. Register it "
|
|
570
|
+
"in CLASSES, not SCHEMAS."
|
|
571
|
+
)
|
|
572
|
+
if not _Utils._is_message_schema_class(cls):
|
|
573
|
+
raise ValueError(
|
|
574
|
+
f"{_Utils._python_classname(cls)} cannot be registered in "
|
|
575
|
+
f"{setting_name}. Use a Message or PydanticMessage subclass."
|
|
576
|
+
)
|
|
577
|
+
|
|
393
578
|
@staticmethod
|
|
394
579
|
def _register_settings_components(settings, path):
|
|
395
580
|
"""Register all components from settings (classes, productions, schemas).
|
|
@@ -402,24 +587,23 @@ class _Utils:
|
|
|
402
587
|
if not path:
|
|
403
588
|
path = os.path.dirname(inspect.getfile(settings))
|
|
404
589
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
_Utils.set_classes_settings(
|
|
408
|
-
except AttributeError:
|
|
409
|
-
print("No classes to register")
|
|
590
|
+
class_items = getattr(settings, "CLASSES", None)
|
|
591
|
+
if class_items is not None:
|
|
592
|
+
_Utils.set_classes_settings(class_items, path)
|
|
410
593
|
|
|
411
594
|
try:
|
|
412
595
|
# set the productions settings
|
|
413
596
|
_Utils.set_productions_settings(settings.PRODUCTIONS, path)
|
|
414
597
|
except AttributeError:
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
598
|
+
pass
|
|
599
|
+
|
|
600
|
+
schemas = getattr(settings, "SCHEMAS", None)
|
|
601
|
+
if schemas is not None:
|
|
602
|
+
if not isinstance(schemas, list):
|
|
603
|
+
raise ValueError("SCHEMAS must be a list of message classes.")
|
|
604
|
+
for cls in schemas:
|
|
605
|
+
_Utils._validate_dtl_schema_class(cls, "SCHEMAS")
|
|
420
606
|
_Utils.register_message_schema(cls)
|
|
421
|
-
except AttributeError:
|
|
422
|
-
print("No schemas to register")
|
|
423
607
|
|
|
424
608
|
@staticmethod
|
|
425
609
|
def _cleanup_sys_path(path):
|
|
@@ -456,11 +640,21 @@ class _Utils:
|
|
|
456
640
|
:param class_items: a dictionary of classes
|
|
457
641
|
:return: a dictionary of settings for each class
|
|
458
642
|
"""
|
|
643
|
+
if not isinstance(class_items, dict):
|
|
644
|
+
raise ValueError("CLASSES must be a dictionary.")
|
|
459
645
|
for key, value in class_items.items():
|
|
460
646
|
if inspect.isclass(value):
|
|
461
647
|
if is_persistent_message_class(value):
|
|
462
648
|
_Utils.register_persistent_message(value, key)
|
|
463
649
|
continue
|
|
650
|
+
if _Utils._is_message_schema_class(value):
|
|
651
|
+
raise ValueError(
|
|
652
|
+
f"{_Utils._python_classname(value)} is a Message/"
|
|
653
|
+
"PydanticMessage and cannot be registered in CLASSES. "
|
|
654
|
+
f"Use SCHEMAS = [{value.__name__}] if you need DTL "
|
|
655
|
+
"support. Otherwise, no migration is required for this "
|
|
656
|
+
"message."
|
|
657
|
+
)
|
|
464
658
|
path = None
|
|
465
659
|
if root_path:
|
|
466
660
|
path = root_path
|
|
@@ -486,6 +680,14 @@ class _Utils:
|
|
|
486
680
|
if msg_cls is not None and is_persistent_message_class(msg_cls):
|
|
487
681
|
_Utils.register_persistent_message(msg_cls, key)
|
|
488
682
|
continue
|
|
683
|
+
if msg_cls is not None and _Utils._is_message_schema_class(msg_cls):
|
|
684
|
+
raise ValueError(
|
|
685
|
+
f"{value['module']}.{value['class']} is a Message/"
|
|
686
|
+
"PydanticMessage and cannot be registered in CLASSES. "
|
|
687
|
+
"Use SCHEMAS if you need DTL "
|
|
688
|
+
"support. Otherwise, no migration is required for this "
|
|
689
|
+
"message."
|
|
690
|
+
)
|
|
489
691
|
# register the component
|
|
490
692
|
_Utils.register_component(
|
|
491
693
|
value["module"], value["class"], value["path"], 1, key
|
iop/cls/IOP/Utils.cls
CHANGED
|
@@ -352,12 +352,32 @@ ClassMethod GenerateProxyClass(
|
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
354
|
Set tCustomProp.Required = tPropInfo."__getitem__"(3)
|
|
355
|
+
Set tDesc = ""
|
|
356
|
+
If (builtins.len(tPropInfo)>5) {
|
|
357
|
+
Set tDesc = tPropInfo."__getitem__"(5)
|
|
358
|
+
}
|
|
359
|
+
If ""'=tDesc {
|
|
360
|
+
Set tCustomProp.Description = tDesc
|
|
361
|
+
}
|
|
355
362
|
|
|
356
363
|
Set tSC = tCOSClass.Properties.Insert(tCustomProp)
|
|
357
364
|
Quit:$$$ISERR(tSC)
|
|
358
365
|
|
|
359
|
-
Set tPropCat = "
|
|
366
|
+
Set tPropCat = ""
|
|
367
|
+
If (builtins.len(tPropInfo)>4) {
|
|
368
|
+
Set tPropCat = tPropInfo."__getitem__"(4)
|
|
369
|
+
}
|
|
370
|
+
If ""=tPropCat {
|
|
371
|
+
Set tPropCat = "Python Attributes $type"
|
|
372
|
+
}
|
|
373
|
+
Set tContext = ""
|
|
374
|
+
If (builtins.len(tPropInfo)>6) {
|
|
375
|
+
Set tContext = tPropInfo."__getitem__"(6)
|
|
376
|
+
}
|
|
360
377
|
Set tSETTINGSParamValue = tSETTINGSParamValue_","_tPropName_":"_tPropCat
|
|
378
|
+
If ""'=tContext {
|
|
379
|
+
Set tSETTINGSParamValue = tSETTINGSParamValue_":"_tContext
|
|
380
|
+
}
|
|
361
381
|
}
|
|
362
382
|
Quit:$$$ISERR(tSC)
|
|
363
383
|
|
{iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/RECORD
RENAMED
|
@@ -19,7 +19,7 @@ grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls,sha256=pcUgHgxX1pMH-wQ
|
|
|
19
19
|
grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls,sha256=T3jNoR8RjKr1InQ6SgqBYTgFwpSB0Q60WholjbvForg,433
|
|
20
20
|
grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls,sha256=zy30ZXXN4XcovPij-kOF3PuH1SkP1EUvlEJQRx2S9RU,431
|
|
21
21
|
grongier/cls/Grongier/Service/WSGI.cls,sha256=7u2SsFmnsubMfdazvaDchKCM3yesPRMfKBzMIkwQ9xc,77
|
|
22
|
-
grongier/pex/__init__.py,sha256=
|
|
22
|
+
grongier/pex/__init__.py,sha256=XxMw6cAaCEEtmFIAL5-FrRkM1u-aQbbYvzr1WE7zYMw,1698
|
|
23
23
|
grongier/pex/__main__.py,sha256=pQzVtkDhAeI6dpNRC632dVk2SGZZIEDwDufdgZe8VWs,98
|
|
24
24
|
grongier/pex/_business_host.py,sha256=dlV8CWJad8Pr2TNfD9OjcVKaq5gEYQACZla1FK6-bDM,44
|
|
25
25
|
grongier/pex/_cli.py,sha256=hOHz3n-aHtULuhdCkqZ_SSb3sv7M6j2WhRxgCTvgR9I,64
|
|
@@ -27,15 +27,15 @@ grongier/pex/_common.py,sha256=HZwG2C2-yB8yNN8kXhI6vxg8h-rROuEx38YOVFWIk1s,31
|
|
|
27
27
|
grongier/pex/_director.py,sha256=pCmoiJ-sxe24yQaDz6ZFBsAnqU6fh57_dlew98B7rtE,35
|
|
28
28
|
grongier/pex/_utils.py,sha256=gvsdr8WhWrE6smlsCxhoF14VUZfitrwqr5J57HkJhi4,29
|
|
29
29
|
grongier/pex/wsgi/handlers.py,sha256=NrFLo_YbAh-x_PlWhAiWkQnUUN2Ss9HoEm63dDWCBpQ,2947
|
|
30
|
-
iop/__init__.py,sha256=
|
|
30
|
+
iop/__init__.py,sha256=tb9Vcz2XzApqKWxit4WTEecyiPB9PRWG8MJdPN9J_wI,1853
|
|
31
31
|
iop/__main__.py,sha256=C0MZpXA8XFopuveMDbZgX1bttrb2DxarhaY1XYfbhsg,100
|
|
32
32
|
iop/_async_request.py,sha256=lW3vasdepKwLPuWRm1zDs3xlRWCoVL0RJZqVUj8gkJw,2409
|
|
33
33
|
iop/_business_host.py,sha256=l0X_2xiMArMQsvI99kXDuI6vVrJMvPHZtDnXHGqT7c4,11669
|
|
34
34
|
iop/_business_operation.py,sha256=AhKw-KKpOatXGqaMFwMcb774SF0a4ZIWeRCUGN-al_Q,2985
|
|
35
35
|
iop/_business_process.py,sha256=tDgZSb8JhwzUAbBXvm9qKzbdlhaeXfVLoUIGOXCoeZs,8821
|
|
36
36
|
iop/_business_service.py,sha256=3oSL4_Dam_WDD7J2BpYVd_WQKUPUnCcLH_bjwXvWqKc,3960
|
|
37
|
-
iop/_cli.py,sha256=
|
|
38
|
-
iop/_common.py,sha256=
|
|
37
|
+
iop/_cli.py,sha256=O9VMWBZnuubA5CZmvp7rMJfcBfQPi7FhNkxHBs7ncXk,17072
|
|
38
|
+
iop/_common.py,sha256=U10pvB1sSFhtJfJ7BzEo19XfNWAUDv54dqFFqp1Gl0g,19234
|
|
39
39
|
iop/_debugpy.py,sha256=0UOLkOjXkJ24GxxyEnPckafrAtfVVUDYIedmLIznYfM,6067
|
|
40
40
|
iop/_decorators.py,sha256=2UFV56sfopuBqgxTTj71XgAAwoQm1ijDi_3N-GIKbu8,2337
|
|
41
41
|
iop/_director.py,sha256=dN_SGyUDPH19kUt7_AR6vBrDlKUg0RRgYVkvJFjsYOM,11855
|
|
@@ -44,17 +44,19 @@ iop/_dispatch.py,sha256=UjrQuia4lSgC3It07m9BqnEBhmqjdd9Hp_b2QVaj4zc,5825
|
|
|
44
44
|
iop/_generator_request.py,sha256=2No4E2mjBr7bPwBljsKbWX3QxTrjgdyz683tynlg-OI,1339
|
|
45
45
|
iop/_inbound_adapter.py,sha256=WErDcXzHhYNN0QanmTay34Zh_uUxlEykJ4YmevTVOyY,1654
|
|
46
46
|
iop/_iris.py,sha256=Zc4IvMv3us3rrBNCba1AU8RSXvct2wZkCZVSWN84c-k,198
|
|
47
|
-
iop/_local.py,sha256=
|
|
47
|
+
iop/_local.py,sha256=bGTxgI83qsT5IxA-hZXhXEDAICeYc3Lku2MM5A8ApBs,3676
|
|
48
48
|
iop/_log_manager.py,sha256=Egrul1LCQlYrvIgcoF-LjXoeXaLLh_nD9bB4P-Y-q_E,3225
|
|
49
49
|
iop/_message.py,sha256=fTHxYHBq42QIDGrtVuw-7NJAQ7bLIWPdbl5EmwiDhG0,1465
|
|
50
50
|
iop/_message_validator.py,sha256=XzQ4qkHLYoai2_gPk3ItXHVgwz2WldiBcNE32yaxOVc,1540
|
|
51
51
|
iop/_outbound_adapter.py,sha256=GSsr6z0gvVygNyr3YicHBt7i2ZJu3wJgrCpPqod7Z_U,732
|
|
52
52
|
iop/_persistent_message.py,sha256=F1WsgNqSupyKPkldQNnY96cGtD2mRwR9qSVE8SI6nXU,16780
|
|
53
|
+
iop/_polling_business_service.py,sha256=uElSd77H7YhE3hi24Zzyfc9BMP8HSzGyo4fRzW3e0eM,199
|
|
53
54
|
iop/_private_session_duplex.py,sha256=SLqwnB4gLKqCt-DClIEFg_yWcQs16A4Va7lRyUg-18o,5289
|
|
54
55
|
iop/_private_session_process.py,sha256=J1HjRIphg0iHHEIa6Rqa68vA22ODMN6BfNqAN4Ybi1U,1723
|
|
55
56
|
iop/_remote.py,sha256=zE4eZtNuqQemtX2gBwu59n56ixBtwkV25GvZgqVKlMU,17395
|
|
56
57
|
iop/_serialization.py,sha256=5ajXh99QVFRXuwhR7xex3rHF87l07o8Fth2VOMRj-YM,8778
|
|
57
|
-
iop/
|
|
58
|
+
iop/_settings.py,sha256=ZoPbYllsJJ5uAwcg1z2Gp-PChOAnKwMLsFNXppBuUGM,5510
|
|
59
|
+
iop/_utils.py,sha256=46EO1ugcylkd4oLodvTyp2-byutgePjITHv0fXUjscI,35460
|
|
58
60
|
iop/cls/IOP/BusinessOperation.cls,sha256=NlvbNtm1ZFZmHaMX_9FMKoptY-hQMq5jYN1nLQwvYJw,936
|
|
59
61
|
iop/cls/IOP/BusinessProcess.cls,sha256=XJxzbiV0xokzRm-iI2Be5UIJLE3MlXr7W3WS_LkOCYs,3363
|
|
60
62
|
iop/cls/IOP/BusinessService.cls,sha256=fplKrbQgA7cQgjKIqDR2IK2iD1iNHmT-QvWrozhE4n4,1189
|
|
@@ -66,7 +68,7 @@ iop/cls/IOP/OutboundAdapter.cls,sha256=OQoGFHUy2qV_kcsShTlWGOngDrdH5dhwux4eopZyI
|
|
|
66
68
|
iop/cls/IOP/PickleMessage.cls,sha256=S3y7AClQ8mAILjxPuHdCjGosBZYzGbUQ5WTv4mYPNMQ,1673
|
|
67
69
|
iop/cls/IOP/Projection.cls,sha256=AZgbfpbEk02llhyIwrSw0M3QMcQNcjhjY3_vU_yx8FU,1315
|
|
68
70
|
iop/cls/IOP/Test.cls,sha256=zvlCZJfOCmSFdmi-ZQHWDGYmqZAgRspaJj1j0r_IxJQ,2017
|
|
69
|
-
iop/cls/IOP/Utils.cls,sha256=
|
|
71
|
+
iop/cls/IOP/Utils.cls,sha256=1ujVAaBAjFAbbyirD0aFzRQoQva6SR_qJJG_s03V1l8,19042
|
|
70
72
|
iop/cls/IOP/Wrapper.cls,sha256=37fUol-EcktdfGhpfi4o12p04975lKGaRYEFhw-fuaM,1614
|
|
71
73
|
iop/cls/IOP/Duplex/Operation.cls,sha256=K_fmgeLjPZQbHgNrc0kd6DUQoW0fDn1VHQjJxHo95Zk,525
|
|
72
74
|
iop/cls/IOP/Duplex/Process.cls,sha256=xbefZ4z84a_IUhavWN6P_gZBzqkdJ5XRTXxro6iDvAg,6986
|
|
@@ -86,9 +88,9 @@ iop/cls/IOP/Service/WSGI.cls,sha256=VLNCXEwmHW9dBnE51uGE1nvGX6T4HjhqePT3LVhsjAE,
|
|
|
86
88
|
iop/cls/IOP/Service/Remote/Handler.cls,sha256=JfsXse2jvoVvQfW8_rVEt2DCQJ9SVqReCcOUngOkpzE,938
|
|
87
89
|
iop/cls/IOP/Service/Remote/Rest/v1.cls,sha256=DRaYNsbFmczdVltb-HMZvviy5EcjcJx7__zmnKANNm8,14429
|
|
88
90
|
iop/wsgi/handlers.py,sha256=lcCZ1ixnYqdo9eNrBSsQbhS9ei2x11p9e4SHHb__zmY,2951
|
|
89
|
-
iris_pex_embedded_python-3.7.
|
|
90
|
-
iris_pex_embedded_python-3.7.
|
|
91
|
-
iris_pex_embedded_python-3.7.
|
|
92
|
-
iris_pex_embedded_python-3.7.
|
|
93
|
-
iris_pex_embedded_python-3.7.
|
|
94
|
-
iris_pex_embedded_python-3.7.
|
|
91
|
+
iris_pex_embedded_python-3.7.2b2.dist-info/licenses/LICENSE,sha256=rZSiBFId_sfbJ6RL0GjjPX-InNLkNS9ou7eQsikciI8,1089
|
|
92
|
+
iris_pex_embedded_python-3.7.2b2.dist-info/METADATA,sha256=9XMFl2HGKtXPzs9ATPRwuQmsuu_Na1hG9R9X_YdAhao,4310
|
|
93
|
+
iris_pex_embedded_python-3.7.2b2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
94
|
+
iris_pex_embedded_python-3.7.2b2.dist-info/entry_points.txt,sha256=pj-i4LSDyiSP6xpHlVjMCbg1Pik7dC3_sdGY3Yp9Vhk,38
|
|
95
|
+
iris_pex_embedded_python-3.7.2b2.dist-info/top_level.txt,sha256=4p0q6hCATmYIVMVi3I8hOUcJE1kwzyBeHygWv_rGvrU,13
|
|
96
|
+
iris_pex_embedded_python-3.7.2b2.dist-info/RECORD,,
|
{iris_pex_embedded_python-3.7.2b1.dist-info → iris_pex_embedded_python-3.7.2b2.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|