iris-pex-embedded-python 4.0.0b15__py3-none-any.whl → 4.0.1__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.
- iop/__init__.py +2 -2
- iop/components/business_service.py +12 -16
- iop/messages/dispatch.py +137 -16
- iop/migration/utils.py +43 -17
- iop/production/common.py +14 -1
- iop/production/component.py +40 -2
- iop/production/declarations.py +6 -4
- iop/production/model.py +77 -7
- iop/production/rendering.py +5 -6
- iop/production/types.py +10 -4
- iop/production/validation.py +70 -4
- iop/py.typed +1 -0
- {iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/METADATA +30 -6
- {iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/RECORD +18 -17
- {iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/WHEEL +0 -0
- {iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/entry_points.txt +0 -0
- {iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/licenses/LICENSE +0 -0
- {iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/top_level.txt +0 -0
iop/__init__.py
CHANGED
|
@@ -125,8 +125,8 @@ class BusinessService(_BusinessService):
|
|
|
125
125
|
production graph.
|
|
126
126
|
|
|
127
127
|
Lifecycle:
|
|
128
|
-
IRIS calls on_process_input(); the default implementation delegates
|
|
129
|
-
|
|
128
|
+
IRIS calls on_process_input(); the default implementation delegates the
|
|
129
|
+
incoming request to on_message(request).
|
|
130
130
|
|
|
131
131
|
Best practices:
|
|
132
132
|
Declare outbound routes with target() and wire them in a Production
|
|
@@ -20,16 +20,13 @@ def _call_process_input(method, request):
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class _BusinessService(_BusinessHost):
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
3) Nonpolling business service - The production framework does not initiate the business service. Instead custom code in either a long-running process
|
|
31
|
-
or one that is started at regular intervals initiates the business service through the Director API.
|
|
32
|
-
"""
|
|
23
|
+
"""Runtime base for inbound production entry points.
|
|
24
|
+
|
|
25
|
+
IRIS invokes on_process_input(...). By default, that hook delegates to
|
|
26
|
+
on_message(...). Application code should normally subclass iop.BusinessService
|
|
27
|
+
or iop.PollingBusinessService and wire outbound routes with target() in a
|
|
28
|
+
Production graph.
|
|
29
|
+
"""
|
|
33
30
|
|
|
34
31
|
Adapter = adapter = None
|
|
35
32
|
_wait_for_next_call_interval = False
|
|
@@ -79,13 +76,12 @@ class _BusinessService(_BusinessHost):
|
|
|
79
76
|
return None
|
|
80
77
|
|
|
81
78
|
def on_process_input(self, message_input=None):
|
|
82
|
-
"""
|
|
83
|
-
If the business service does not specify an adapter, then the default adapter calls this method with no message
|
|
84
|
-
and the business service is responsible for receiving the data from the external system and validating it.
|
|
79
|
+
"""Handle IRIS ProcessInput and delegate to on_message(message_input).
|
|
85
80
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
Override this low-level hook only when an inbound adapter or Director
|
|
82
|
+
call needs custom ProcessInput handling. For simple services, override
|
|
83
|
+
on_message(...); for scheduled polling, use PollingBusinessService and
|
|
84
|
+
override on_poll().
|
|
89
85
|
"""
|
|
90
86
|
return self.on_message(message_input)
|
|
91
87
|
|
iop/messages/dispatch.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ast
|
|
1
2
|
import logging
|
|
2
3
|
from collections.abc import Callable
|
|
3
4
|
from dataclasses import dataclass
|
|
@@ -36,6 +37,8 @@ _PICKLE_MESSAGE_CLASSES = {
|
|
|
36
37
|
"IOP.Generator.Message.StartPickle",
|
|
37
38
|
}
|
|
38
39
|
_HANDLER_ATTRIBUTE = "__iop_handler_message__"
|
|
40
|
+
_IRIS_MODULE_PREFIX = "iris."
|
|
41
|
+
_UNRESOLVED = object()
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
@dataclass(frozen=True)
|
|
@@ -60,7 +63,7 @@ def handler(message_type: Any) -> Callable[[Callable], Callable]:
|
|
|
60
63
|
message_type: The message class, fully qualified class name string, or
|
|
61
64
|
IRIS object instance this method handles.
|
|
62
65
|
"""
|
|
63
|
-
message =
|
|
66
|
+
message = _message_key_from_declared(message_type)
|
|
64
67
|
if message is None:
|
|
65
68
|
raise TypeError("handler() requires a message class or class name")
|
|
66
69
|
|
|
@@ -154,11 +157,10 @@ def dispatch_message(host: Any, request: Any) -> Any:
|
|
|
154
157
|
"""
|
|
155
158
|
call = "on_message"
|
|
156
159
|
|
|
157
|
-
|
|
158
|
-
classname = request.__class__.__name__
|
|
160
|
+
message_names = _message_keys_from_request(request)
|
|
159
161
|
|
|
160
162
|
for msg, method in host.DISPATCH:
|
|
161
|
-
if msg
|
|
163
|
+
if msg in message_names:
|
|
162
164
|
return getattr(host, method)(request)
|
|
163
165
|
|
|
164
166
|
return getattr(host, call)(request)
|
|
@@ -202,15 +204,24 @@ def create_dispatch(host: Any) -> None:
|
|
|
202
204
|
|
|
203
205
|
def _declared_dispatch(host: Any) -> list[tuple[str, str]]:
|
|
204
206
|
if "DISPATCH" in getattr(host, "__dict__", {}):
|
|
205
|
-
return
|
|
207
|
+
return _normalized_dispatch(host.__dict__["DISPATCH"])
|
|
206
208
|
|
|
207
209
|
class_dispatch = host.__class__.__dict__.get("DISPATCH")
|
|
208
210
|
if class_dispatch is not None:
|
|
209
|
-
return
|
|
211
|
+
return _normalized_dispatch(class_dispatch)
|
|
210
212
|
|
|
211
213
|
return []
|
|
212
214
|
|
|
213
215
|
|
|
216
|
+
def _normalized_dispatch(dispatch: Any) -> list[tuple[str, str]]:
|
|
217
|
+
entries = []
|
|
218
|
+
for message, method in dispatch:
|
|
219
|
+
key = _message_key_from_declared(message)
|
|
220
|
+
if key is not None:
|
|
221
|
+
entries.append((key, method))
|
|
222
|
+
return entries
|
|
223
|
+
|
|
224
|
+
|
|
214
225
|
def _decorated_dispatch(host: Any) -> list[tuple[str, str]]:
|
|
215
226
|
dispatch = []
|
|
216
227
|
for method_name in dir(host):
|
|
@@ -306,13 +317,9 @@ def get_handler_info(host: Any, method_name: str) -> tuple[str, str] | None:
|
|
|
306
317
|
if len(params) != 1:
|
|
307
318
|
return None
|
|
308
319
|
|
|
320
|
+
method = getattr(host, method_name)
|
|
309
321
|
param: Parameter = next(iter(params.values()))
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if annotation == Parameter.empty:
|
|
313
|
-
return None
|
|
314
|
-
|
|
315
|
-
message = _message_class_name(annotation)
|
|
322
|
+
message = _message_key_from_annotation(host, method, param.annotation)
|
|
316
323
|
if message is None:
|
|
317
324
|
return None
|
|
318
325
|
|
|
@@ -322,12 +329,63 @@ def get_handler_info(host: Any, method_name: str) -> tuple[str, str] | None:
|
|
|
322
329
|
return None
|
|
323
330
|
|
|
324
331
|
|
|
325
|
-
def
|
|
332
|
+
def _message_key_from_annotation(
|
|
333
|
+
host: Any, method: Callable, annotation: Any
|
|
334
|
+
) -> str | None:
|
|
335
|
+
if annotation == Parameter.empty:
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
if not isinstance(annotation, str):
|
|
339
|
+
return _message_key_from_declared(annotation, allow_bare_string=False)
|
|
340
|
+
|
|
341
|
+
value: Any = annotation
|
|
342
|
+
for _ in range(3):
|
|
343
|
+
if not isinstance(value, str):
|
|
344
|
+
return _message_key_from_declared(value, allow_bare_string=False)
|
|
345
|
+
|
|
346
|
+
key = _message_key_from_string(value, allow_bare=False)
|
|
347
|
+
if key is not None:
|
|
348
|
+
return key
|
|
349
|
+
|
|
350
|
+
unquoted = _unquote_string(value)
|
|
351
|
+
if unquoted is not None and unquoted != value:
|
|
352
|
+
value = unquoted
|
|
353
|
+
continue
|
|
354
|
+
|
|
355
|
+
value = _lookup_annotation_name(host, method, value)
|
|
356
|
+
if value is _UNRESOLVED:
|
|
357
|
+
return None
|
|
358
|
+
|
|
359
|
+
return None
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _message_keys_from_request(request: Any) -> tuple[str, ...]:
|
|
363
|
+
module = request.__class__.__module__
|
|
364
|
+
classname = request.__class__.__name__
|
|
365
|
+
names = [f"{module}.{classname}"]
|
|
366
|
+
|
|
367
|
+
if module.startswith("iris"):
|
|
368
|
+
native_name = _native_iris_message_key(request)
|
|
369
|
+
if native_name:
|
|
370
|
+
names.append(native_name)
|
|
371
|
+
names.append(f"{_IRIS_MODULE_PREFIX}{native_name}")
|
|
372
|
+
|
|
373
|
+
return tuple(dict.fromkeys(names))
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _message_key_from_declared(
|
|
377
|
+
message_type: Any, *, allow_bare_string: bool = True
|
|
378
|
+
) -> str | None:
|
|
326
379
|
if isinstance(message_type, str):
|
|
327
|
-
return
|
|
380
|
+
return _message_key_from_string(
|
|
381
|
+
message_type,
|
|
382
|
+
allow_bare=allow_bare_string,
|
|
383
|
+
)
|
|
328
384
|
|
|
329
385
|
if is_iris_object_instance(message_type):
|
|
330
|
-
return
|
|
386
|
+
return _native_iris_message_key(message_type) or _python_class_key(
|
|
387
|
+
type(message_type)
|
|
388
|
+
)
|
|
331
389
|
|
|
332
390
|
if message_type is Any or message_type is object:
|
|
333
391
|
return None
|
|
@@ -338,7 +396,70 @@ def _message_class_name(message_type: Any) -> str | None:
|
|
|
338
396
|
if not _is_dispatch_message_class(message_type):
|
|
339
397
|
return None
|
|
340
398
|
|
|
341
|
-
return
|
|
399
|
+
return _python_class_key(message_type)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def _message_key_from_string(value: str, *, allow_bare: bool) -> str | None:
|
|
403
|
+
if not value or _unquote_string(value) is not None:
|
|
404
|
+
return None
|
|
405
|
+
|
|
406
|
+
normalized = _strip_iris_prefix(value)
|
|
407
|
+
if "." in normalized:
|
|
408
|
+
return normalized if _looks_like_message_key(normalized) else None
|
|
409
|
+
|
|
410
|
+
return normalized if allow_bare else None
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _native_iris_message_key(message: Any) -> str | None:
|
|
414
|
+
iris_classname = get_iris_object_classname(message)
|
|
415
|
+
if not iris_classname:
|
|
416
|
+
return None
|
|
417
|
+
return _strip_iris_prefix(iris_classname)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _python_class_key(klass: type) -> str:
|
|
421
|
+
return f"{klass.__module__}.{klass.__name__}"
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _strip_iris_prefix(value: str) -> str:
|
|
425
|
+
if value.startswith(_IRIS_MODULE_PREFIX):
|
|
426
|
+
return value[len(_IRIS_MODULE_PREFIX) :]
|
|
427
|
+
return value
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def _looks_like_message_key(value: str) -> bool:
|
|
431
|
+
return not any(character in value for character in "'\"[](){} ,:")
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _unquote_string(value: str) -> str | None:
|
|
435
|
+
try:
|
|
436
|
+
literal = ast.literal_eval(value)
|
|
437
|
+
except (SyntaxError, ValueError):
|
|
438
|
+
return None
|
|
439
|
+
return literal if isinstance(literal, str) else None
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def _lookup_annotation_name(host: Any, method: Callable, name: str) -> Any:
|
|
443
|
+
if not name.isidentifier():
|
|
444
|
+
return _UNRESOLVED
|
|
445
|
+
|
|
446
|
+
localns = _annotation_localns(host)
|
|
447
|
+
if name in localns:
|
|
448
|
+
return localns[name]
|
|
449
|
+
|
|
450
|
+
return _annotation_globalns(method).get(name, _UNRESOLVED)
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def _annotation_globalns(method: Callable) -> dict[str, Any]:
|
|
454
|
+
function = getattr(method, "__func__", method)
|
|
455
|
+
return getattr(function, "__globals__", {})
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _annotation_localns(host: Any) -> dict[str, Any]:
|
|
459
|
+
namespace: dict[str, Any] = {}
|
|
460
|
+
for klass in reversed(type(host).__mro__):
|
|
461
|
+
namespace.update(vars(klass))
|
|
462
|
+
return namespace
|
|
342
463
|
|
|
343
464
|
|
|
344
465
|
def _is_dispatch_message_class(klass: type) -> bool:
|
iop/migration/utils.py
CHANGED
|
@@ -193,8 +193,11 @@ def register_component(
|
|
|
193
193
|
overwrite: int = 1,
|
|
194
194
|
iris_classname: str = "Python",
|
|
195
195
|
):
|
|
196
|
-
"""
|
|
197
|
-
|
|
196
|
+
"""Register a Python component as an IRIS proxy class.
|
|
197
|
+
|
|
198
|
+
Prefer a Python Production graph in PRODUCTIONS for new application
|
|
199
|
+
components. Use register_component() directly for standalone bindings,
|
|
200
|
+
legacy migration helpers, or manual proxy registration only.
|
|
198
201
|
|
|
199
202
|
:param module: The name of the module that contains the class
|
|
200
203
|
:type module: str
|
|
@@ -239,8 +242,11 @@ def bind_component(
|
|
|
239
242
|
overwrite: int = 1,
|
|
240
243
|
iris_classname: str = "Python",
|
|
241
244
|
):
|
|
242
|
-
"""
|
|
243
|
-
|
|
245
|
+
"""Public alias for register_component().
|
|
246
|
+
|
|
247
|
+
Prefer a Python Production graph in PRODUCTIONS for new application
|
|
248
|
+
components. Use bind_component() directly only for standalone bindings,
|
|
249
|
+
legacy migration helpers, or manual proxy registration.
|
|
244
250
|
"""
|
|
245
251
|
return register_component(module, classname, path, overwrite, iris_classname)
|
|
246
252
|
|
|
@@ -436,18 +442,12 @@ def migrate(
|
|
|
436
442
|
namespace: str | None = None,
|
|
437
443
|
strict_production_validation: bool = False,
|
|
438
444
|
):
|
|
439
|
-
"""
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
* PRODUCTIONS
|
|
446
|
-
list of dictionaries:
|
|
447
|
-
* key: the name of the production
|
|
448
|
-
* value: a dictionary containing the settings for the production
|
|
449
|
-
* SCHEMAS
|
|
450
|
-
List of classes
|
|
445
|
+
"""Read a migration file and apply its registrations to IRIS.
|
|
446
|
+
|
|
447
|
+
New Python-authored applications should normally export Production objects
|
|
448
|
+
through PRODUCTIONS. CLASSES remains available for standalone bindings,
|
|
449
|
+
native PersistentMessage classes, and legacy migration files. SCHEMAS
|
|
450
|
+
registers Message or PydanticMessage schemas for DTL support.
|
|
451
451
|
"""
|
|
452
452
|
settings, path = _load_settings(filename)
|
|
453
453
|
|
|
@@ -546,7 +546,19 @@ def _build_migration_manifest(
|
|
|
546
546
|
|
|
547
547
|
|
|
548
548
|
def _load_settings(filename):
|
|
549
|
-
"""Load settings module
|
|
549
|
+
"""Load a migration settings module.
|
|
550
|
+
|
|
551
|
+
Purpose:
|
|
552
|
+
Resolve settings.py as a file-based module and keep imports local to the
|
|
553
|
+
settings file directory for this process.
|
|
554
|
+
|
|
555
|
+
Best practices:
|
|
556
|
+
Keep modules imported by settings.py in the same project/package rooted
|
|
557
|
+
near the settings file. Let IoP manage temporary import path setup.
|
|
558
|
+
|
|
559
|
+
Common mistakes:
|
|
560
|
+
Do not require users to set PYTHONPATH. Do not mutate environment
|
|
561
|
+
variables to force imports when module/package layout should be fixed.
|
|
550
562
|
|
|
551
563
|
Returns:
|
|
552
564
|
tuple: (settings_module, path_added_to_sys)
|
|
@@ -723,6 +735,20 @@ def _cleanup_sys_path(path):
|
|
|
723
735
|
|
|
724
736
|
|
|
725
737
|
def import_module_from_path(module_name, file_path):
|
|
738
|
+
"""Import one module from an absolute file path.
|
|
739
|
+
|
|
740
|
+
Purpose:
|
|
741
|
+
Execute a specific settings or component module by file location
|
|
742
|
+
without relying on global PYTHONPATH configuration.
|
|
743
|
+
|
|
744
|
+
Best practices:
|
|
745
|
+
Use absolute paths and stable module/package layout so imports resolve
|
|
746
|
+
from the project directory containing settings.py.
|
|
747
|
+
|
|
748
|
+
Common mistakes:
|
|
749
|
+
Do not patch PYTHONPATH or sys.path globally to make imports pass.
|
|
750
|
+
Keep import fixes in project structure and import statements.
|
|
751
|
+
"""
|
|
726
752
|
if not os.path.isabs(file_path):
|
|
727
753
|
raise ValueError("The file path must be absolute")
|
|
728
754
|
|
iop/production/common.py
CHANGED
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import importlib
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
+
from ..components.settings import Setting
|
|
7
|
+
|
|
6
8
|
PRODUCTION_SETTING_FIELDS: dict[str, tuple[str, Any]] = {
|
|
7
9
|
"shutdown_timeout": ("ShutdownTimeout", 120),
|
|
8
10
|
"update_timeout": ("UpdateTimeout", 10),
|
|
@@ -83,11 +85,21 @@ def _adapter_type_from_class_name(class_name: str | None) -> str:
|
|
|
83
85
|
return _adapter_type_from_component_class(component_class)
|
|
84
86
|
|
|
85
87
|
|
|
88
|
+
def _setting_name(name: Any) -> str:
|
|
89
|
+
if isinstance(name, Setting) and name.name:
|
|
90
|
+
return name.name
|
|
91
|
+
return str(name)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _normalize_settings_mapping(values: Any) -> dict[str, Any]:
|
|
95
|
+
return {_setting_name(key): value for key, value in dict(values or {}).items()}
|
|
96
|
+
|
|
97
|
+
|
|
86
98
|
def _settings_to_iris(target_name: str, values: dict[str, Any]) -> list[dict[str, str]]:
|
|
87
99
|
return [
|
|
88
100
|
{
|
|
89
101
|
"@Target": target_name,
|
|
90
|
-
"@Name": name,
|
|
102
|
+
"@Name": _setting_name(name),
|
|
91
103
|
"#text": _text_value(value),
|
|
92
104
|
}
|
|
93
105
|
for name, value in values.items()
|
|
@@ -97,6 +109,7 @@ def _settings_to_iris(target_name: str, values: dict[str, Any]) -> list[dict[str
|
|
|
97
109
|
def _apply_settings_update(target: dict[str, Any], updates: Any) -> None:
|
|
98
110
|
"""Merge *updates* into *target*, treating ``None`` values as removals."""
|
|
99
111
|
for key, value in (updates or {}).items():
|
|
112
|
+
key = _setting_name(key)
|
|
100
113
|
if value is None:
|
|
101
114
|
target.pop(key, None)
|
|
102
115
|
else:
|
iop/production/component.py
CHANGED
|
@@ -66,6 +66,13 @@ class ComponentRef:
|
|
|
66
66
|
return self.target_setting(name)
|
|
67
67
|
raise AttributeError(name)
|
|
68
68
|
|
|
69
|
+
def __dir__(self) -> list[str]:
|
|
70
|
+
names = set(super().__dir__())
|
|
71
|
+
if self.component_class is not None:
|
|
72
|
+
names.update(_target_setting_names(self.component_class))
|
|
73
|
+
names.update(self.target_setting_names)
|
|
74
|
+
return sorted(names)
|
|
75
|
+
|
|
69
76
|
def target_setting(self, name: str) -> TargetSettingRef:
|
|
70
77
|
self.target_setting_names.add(name)
|
|
71
78
|
return TargetSettingRef(
|
|
@@ -161,7 +168,7 @@ class ComponentRef:
|
|
|
161
168
|
|
|
162
169
|
def connect(
|
|
163
170
|
self,
|
|
164
|
-
target_setting: str | TargetSettingRef,
|
|
171
|
+
target_setting: str | TargetSetting | TargetSettingRef,
|
|
165
172
|
target_component: ComponentRef | str | None = None,
|
|
166
173
|
**kwargs: Any,
|
|
167
174
|
) -> ComponentRef:
|
|
@@ -171,7 +178,7 @@ class ComponentRef:
|
|
|
171
178
|
|
|
172
179
|
def _coerce_target_setting_ref(
|
|
173
180
|
self,
|
|
174
|
-
target_setting: str | TargetSettingRef,
|
|
181
|
+
target_setting: str | TargetSetting | TargetSettingRef,
|
|
175
182
|
) -> TargetSettingRef:
|
|
176
183
|
if isinstance(target_setting, TargetSettingRef):
|
|
177
184
|
if target_setting.production is not self.production:
|
|
@@ -183,6 +190,28 @@ class ComponentRef:
|
|
|
183
190
|
"source target setting belongs to a different component"
|
|
184
191
|
)
|
|
185
192
|
return target_setting
|
|
193
|
+
if isinstance(target_setting, TargetSetting):
|
|
194
|
+
owner = target_setting.owner
|
|
195
|
+
if owner is None or not target_setting.name:
|
|
196
|
+
raise ValueError(
|
|
197
|
+
"target setting must be declared on a component class"
|
|
198
|
+
)
|
|
199
|
+
if self.component_class is None or not issubclass(
|
|
200
|
+
self.component_class,
|
|
201
|
+
owner,
|
|
202
|
+
):
|
|
203
|
+
owner_name = f"{owner.__module__}.{owner.__qualname__}"
|
|
204
|
+
component_name = (
|
|
205
|
+
f"{self.component_class.__module__}."
|
|
206
|
+
f"{self.component_class.__qualname__}"
|
|
207
|
+
if self.component_class is not None
|
|
208
|
+
else self.class_name
|
|
209
|
+
)
|
|
210
|
+
raise ValueError(
|
|
211
|
+
f"target setting {target_setting.name!r} belongs to "
|
|
212
|
+
f"{owner_name}, not {component_name}"
|
|
213
|
+
)
|
|
214
|
+
return self.target_setting(target_setting.name)
|
|
186
215
|
return self.target_setting(str(target_setting))
|
|
187
216
|
|
|
188
217
|
def inspect(self, *, refresh: bool = True) -> dict[str, Any]:
|
|
@@ -232,3 +261,12 @@ class ComponentRef:
|
|
|
232
261
|
item["Setting"] = settings
|
|
233
262
|
|
|
234
263
|
return item
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _target_setting_names(component_class: type) -> tuple[str, ...]:
|
|
267
|
+
names: dict[str, None] = {}
|
|
268
|
+
for base in reversed(component_class.__mro__):
|
|
269
|
+
for name, value in base.__dict__.items():
|
|
270
|
+
if isinstance(value, TargetSetting):
|
|
271
|
+
names[name] = None
|
|
272
|
+
return tuple(names)
|
iop/production/declarations.py
CHANGED
|
@@ -2,9 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Iterable, Mapping
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any, ClassVar, Protocol
|
|
5
|
+
from typing import Any, ClassVar, Protocol, cast
|
|
6
6
|
|
|
7
|
-
from .common import SETTING_NAME_ALIASES
|
|
7
|
+
from .common import SETTING_NAME_ALIASES, _normalize_settings_mapping
|
|
8
8
|
from .types import TargetSetting
|
|
9
9
|
|
|
10
10
|
|
|
@@ -36,7 +36,9 @@ class Route:
|
|
|
36
36
|
targets = (self.targets,)
|
|
37
37
|
else:
|
|
38
38
|
try:
|
|
39
|
-
targets = tuple(
|
|
39
|
+
targets = tuple(
|
|
40
|
+
cast(Iterable[str | _NamedRouteTarget], self.targets)
|
|
41
|
+
)
|
|
40
42
|
except TypeError as exc:
|
|
41
43
|
raise TypeError(
|
|
42
44
|
f"Route {self.target_setting_name!r} targets must be an item name, "
|
|
@@ -174,7 +176,7 @@ def _mapping(
|
|
|
174
176
|
item_name: str,
|
|
175
177
|
) -> dict[str, Any]:
|
|
176
178
|
try:
|
|
177
|
-
return
|
|
179
|
+
return _normalize_settings_mapping(values)
|
|
178
180
|
except (TypeError, ValueError) as exc:
|
|
179
181
|
raise TypeError(
|
|
180
182
|
f"Production item {item_name!r} {field_name} must be a mapping"
|
iop/production/model.py
CHANGED
|
@@ -9,6 +9,7 @@ from .common import (
|
|
|
9
9
|
_adapter_type_from_component_class,
|
|
10
10
|
_apply_settings_update,
|
|
11
11
|
_auto_proxy_class_name,
|
|
12
|
+
_normalize_settings_mapping,
|
|
12
13
|
)
|
|
13
14
|
from .component import ComponentRef
|
|
14
15
|
from .declarative import _DeclarativeProductionMixin
|
|
@@ -34,6 +35,7 @@ from .types import (
|
|
|
34
35
|
PersistentMessageRegistration,
|
|
35
36
|
ProductionDiff,
|
|
36
37
|
ProductionGraph,
|
|
38
|
+
TargetSetting,
|
|
37
39
|
TargetSettingRef,
|
|
38
40
|
_edge_identity,
|
|
39
41
|
)
|
|
@@ -218,10 +220,10 @@ class Production(_DeclarativeProductionMixin):
|
|
|
218
220
|
|
|
219
221
|
def _resolve_production_name(self, name: str | object) -> str:
|
|
220
222
|
if name is not _MISSING:
|
|
221
|
-
return name
|
|
223
|
+
return str(name)
|
|
222
224
|
class_name = getattr(type(self), "name", _MISSING)
|
|
223
225
|
if class_name is not _MISSING:
|
|
224
|
-
return class_name
|
|
226
|
+
return str(class_name)
|
|
225
227
|
return f"{type(self).__module__}.{type(self).__name__}"
|
|
226
228
|
|
|
227
229
|
def _production_default(
|
|
@@ -431,8 +433,8 @@ class Production(_DeclarativeProductionMixin):
|
|
|
431
433
|
comment=comment,
|
|
432
434
|
log_trace_events=log_trace_events,
|
|
433
435
|
schedule=schedule,
|
|
434
|
-
host_settings=
|
|
435
|
-
adapter_settings=
|
|
436
|
+
host_settings=_normalize_settings_mapping(settings),
|
|
437
|
+
adapter_settings=_normalize_settings_mapping(adapter_settings),
|
|
436
438
|
)
|
|
437
439
|
self._add_item(ref)
|
|
438
440
|
return ref
|
|
@@ -569,7 +571,12 @@ class Production(_DeclarativeProductionMixin):
|
|
|
569
571
|
)
|
|
570
572
|
]
|
|
571
573
|
|
|
572
|
-
def service(
|
|
574
|
+
def service(
|
|
575
|
+
self,
|
|
576
|
+
name_or_cls: str | type,
|
|
577
|
+
cls: type | None = None,
|
|
578
|
+
**kwargs: Any,
|
|
579
|
+
) -> ComponentRef:
|
|
573
580
|
"""Add a BusinessService item to the production graph.
|
|
574
581
|
|
|
575
582
|
See docs/cookbooks/hello-world-production.md and
|
|
@@ -577,14 +584,24 @@ class Production(_DeclarativeProductionMixin):
|
|
|
577
584
|
"""
|
|
578
585
|
return self.component(name_or_cls, cls, kind="service", **kwargs)
|
|
579
586
|
|
|
580
|
-
def process(
|
|
587
|
+
def process(
|
|
588
|
+
self,
|
|
589
|
+
name_or_cls: str | type,
|
|
590
|
+
cls: type | None = None,
|
|
591
|
+
**kwargs: Any,
|
|
592
|
+
) -> ComponentRef:
|
|
581
593
|
"""Add a BusinessProcess item to the production graph.
|
|
582
594
|
|
|
583
595
|
See docs/cookbooks/add-business-process.md.
|
|
584
596
|
"""
|
|
585
597
|
return self.component(name_or_cls, cls, kind="process", **kwargs)
|
|
586
598
|
|
|
587
|
-
def operation(
|
|
599
|
+
def operation(
|
|
600
|
+
self,
|
|
601
|
+
name_or_cls: str | type,
|
|
602
|
+
cls: type | None = None,
|
|
603
|
+
**kwargs: Any,
|
|
604
|
+
) -> ComponentRef:
|
|
588
605
|
"""Add a BusinessOperation item to the production graph.
|
|
589
606
|
|
|
590
607
|
See docs/cookbooks/add-business-operation.md.
|
|
@@ -649,6 +666,12 @@ class Production(_DeclarativeProductionMixin):
|
|
|
649
666
|
mode: str = "replace",
|
|
650
667
|
) -> None:
|
|
651
668
|
if not isinstance(source, TargetSettingRef):
|
|
669
|
+
if isinstance(source, TargetSetting):
|
|
670
|
+
raise TypeError(
|
|
671
|
+
"source must be bound to a production item. Use "
|
|
672
|
+
"component.connect(ComponentClass.Target, target_component) "
|
|
673
|
+
"or prod.connect(component.Target, target_component)."
|
|
674
|
+
)
|
|
652
675
|
raise TypeError(
|
|
653
676
|
"source must be a TargetSettingRef returned from a ComponentRef"
|
|
654
677
|
)
|
|
@@ -1055,6 +1078,35 @@ class Production(_DeclarativeProductionMixin):
|
|
|
1055
1078
|
)
|
|
1056
1079
|
self._items.append(ref)
|
|
1057
1080
|
self._items_by_name[ref.name] = ref
|
|
1081
|
+
self._apply_target_defaults()
|
|
1082
|
+
|
|
1083
|
+
def _apply_target_defaults(self) -> None:
|
|
1084
|
+
for ref in self._items:
|
|
1085
|
+
for setting_name, target_name in self._target_default_routes(ref):
|
|
1086
|
+
if setting_name not in ref.host_settings:
|
|
1087
|
+
if setting_name in ref.target_setting_names:
|
|
1088
|
+
continue
|
|
1089
|
+
ref.host_settings[setting_name] = target_name
|
|
1090
|
+
ref.target_setting_names.add(setting_name)
|
|
1091
|
+
if str(ref.host_settings[setting_name]) != target_name:
|
|
1092
|
+
continue
|
|
1093
|
+
if target_name not in self._items_by_name:
|
|
1094
|
+
continue
|
|
1095
|
+
self._register_connection(
|
|
1096
|
+
ref.name,
|
|
1097
|
+
setting_name,
|
|
1098
|
+
target_name,
|
|
1099
|
+
)
|
|
1100
|
+
|
|
1101
|
+
def _target_default_routes(self, ref: ComponentRef) -> tuple[tuple[str, str], ...]:
|
|
1102
|
+
if ref.component_class is None:
|
|
1103
|
+
return ()
|
|
1104
|
+
routes: list[tuple[str, str]] = []
|
|
1105
|
+
for setting_name, descriptor in _target_settings(ref.component_class):
|
|
1106
|
+
target_name = _target_default_name(descriptor.default)
|
|
1107
|
+
if target_name:
|
|
1108
|
+
routes.append((setting_name, target_name))
|
|
1109
|
+
return tuple(routes)
|
|
1058
1110
|
|
|
1059
1111
|
def _diff_current(
|
|
1060
1112
|
self,
|
|
@@ -1141,3 +1193,21 @@ def _connection_mode(mode: str) -> str:
|
|
|
1141
1193
|
"Unsupported connection mode: "
|
|
1142
1194
|
f"{mode!r}. Expected 'replace', 'add', or 'remove'."
|
|
1143
1195
|
)
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
def _target_settings(
|
|
1199
|
+
component_class: type,
|
|
1200
|
+
) -> tuple[tuple[str, TargetSetting], ...]:
|
|
1201
|
+
descriptors: dict[str, TargetSetting] = {}
|
|
1202
|
+
for base in reversed(component_class.__mro__):
|
|
1203
|
+
for name, value in base.__dict__.items():
|
|
1204
|
+
if isinstance(value, TargetSetting):
|
|
1205
|
+
descriptors[name] = value
|
|
1206
|
+
return tuple(descriptors.items())
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
def _target_default_name(value: Any) -> str:
|
|
1210
|
+
if value is None:
|
|
1211
|
+
return ""
|
|
1212
|
+
name = getattr(value, "name", value)
|
|
1213
|
+
return str(name).strip()
|
iop/production/rendering.py
CHANGED
|
@@ -465,9 +465,7 @@ def _connection_lines(production, variables: dict[str, str], item_names: set[str
|
|
|
465
465
|
for source_item, source_target_setting in sorted(grouped):
|
|
466
466
|
targets = grouped[(source_item, source_target_setting)]
|
|
467
467
|
source_var = variables[source_item]
|
|
468
|
-
source_expr = (
|
|
469
|
-
f"{source_var}.target_setting({_literal(source_target_setting)})"
|
|
470
|
-
)
|
|
468
|
+
source_expr = _literal(source_target_setting)
|
|
471
469
|
valid_targets = [target for target in targets if target in variables]
|
|
472
470
|
invalid_targets = [target for target in targets if target not in variables]
|
|
473
471
|
for target in invalid_targets:
|
|
@@ -476,15 +474,16 @@ def _connection_lines(production, variables: dict[str, str], item_names: set[str
|
|
|
476
474
|
continue
|
|
477
475
|
if len(valid_targets) == 1:
|
|
478
476
|
lines.append(
|
|
479
|
-
f"
|
|
477
|
+
f"{source_var}.connect({source_expr}, {variables[valid_targets[0]]})"
|
|
480
478
|
)
|
|
481
479
|
else:
|
|
482
480
|
lines.append(
|
|
483
|
-
f"
|
|
481
|
+
f"{source_var}.connect({source_expr}, {variables[valid_targets[0]]})"
|
|
484
482
|
)
|
|
485
483
|
for target in valid_targets[1:]:
|
|
486
484
|
lines.append(
|
|
487
|
-
f"
|
|
485
|
+
f"{source_var}.connect({source_expr}, {variables[target]}, "
|
|
486
|
+
"mode='add')"
|
|
488
487
|
)
|
|
489
488
|
|
|
490
489
|
for edge in production.edges:
|
iop/production/types.py
CHANGED
|
@@ -12,11 +12,11 @@ from ..components.settings import Category, Setting, controls
|
|
|
12
12
|
class TargetSetting(Setting):
|
|
13
13
|
"""Production target setting descriptor created by target()."""
|
|
14
14
|
|
|
15
|
-
def __init__(self, **kwargs: Any):
|
|
15
|
+
def __init__(self, default: str = "", **kwargs: Any):
|
|
16
16
|
kwargs.setdefault("iris_type", "Ens.DataType.ConfigName")
|
|
17
17
|
kwargs.setdefault("category", Category.BASIC)
|
|
18
18
|
kwargs.setdefault("control", controls.production_item())
|
|
19
|
-
super().__init__(
|
|
19
|
+
super().__init__(default, **kwargs)
|
|
20
20
|
|
|
21
21
|
@overload
|
|
22
22
|
def __get__(self, instance: None, owner: type | None = None) -> TargetSetting: ...
|
|
@@ -34,13 +34,16 @@ class TargetSetting(Setting):
|
|
|
34
34
|
return super().__get__(instance, owner)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def target(**kwargs: Any) -> TargetSetting:
|
|
37
|
+
def target(default: str = "", **kwargs: Any) -> TargetSetting:
|
|
38
38
|
"""Purpose:
|
|
39
39
|
Declare a configurable outbound target setting on a component class.
|
|
40
40
|
|
|
41
41
|
Use when:
|
|
42
42
|
A service or process sends messages to another production component.
|
|
43
43
|
|
|
44
|
+
Pass a target item name as the first argument when the route should have
|
|
45
|
+
a default target even without an explicit Production.connect(...) call.
|
|
46
|
+
|
|
44
47
|
Lifecycle:
|
|
45
48
|
The descriptor becomes an IRIS production setting. Production.connect(...)
|
|
46
49
|
binds it to a concrete target component.
|
|
@@ -59,11 +62,14 @@ def target(**kwargs: Any) -> TargetSetting:
|
|
|
59
62
|
|
|
60
63
|
prod.connect(router.Output, operation)
|
|
61
64
|
|
|
65
|
+
class DefaultRouter(BusinessProcess):
|
|
66
|
+
Output = target("DefaultOperation")
|
|
67
|
+
|
|
62
68
|
Related:
|
|
63
69
|
docs/cookbooks/production-settings-and-targets.md,
|
|
64
70
|
docs/production-graph.md
|
|
65
71
|
"""
|
|
66
|
-
return TargetSetting(**kwargs)
|
|
72
|
+
return TargetSetting(default, **kwargs)
|
|
67
73
|
|
|
68
74
|
|
|
69
75
|
@dataclass
|
iop/production/validation.py
CHANGED
|
@@ -8,8 +8,10 @@ from .common import (
|
|
|
8
8
|
PRODUCTION_SETTING_FIELDS_BY_IRIS,
|
|
9
9
|
PRODUCTION_SETTING_NAMES,
|
|
10
10
|
SETTING_NAME_ALIASES,
|
|
11
|
+
_normalize_settings_mapping,
|
|
11
12
|
)
|
|
12
13
|
from .import_ import _as_list, _production_payload, _split_settings
|
|
14
|
+
from .types import TargetSetting
|
|
13
15
|
|
|
14
16
|
_PRODUCTION_PUBLIC_FIELDS = {
|
|
15
17
|
"name",
|
|
@@ -151,6 +153,8 @@ def _build_production_object_report(production: Any) -> ProductionValidationRepo
|
|
|
151
153
|
for item in getattr(production, "items", ()):
|
|
152
154
|
issues.extend(_validate_component_ref(item))
|
|
153
155
|
|
|
156
|
+
issues.extend(_validate_target_setting_values(production))
|
|
157
|
+
|
|
154
158
|
return ProductionValidationReport(production_name, tuple(issues))
|
|
155
159
|
|
|
156
160
|
|
|
@@ -180,14 +184,18 @@ def _validate_component_ref(item: Any) -> list[ProductionValidationIssue]:
|
|
|
180
184
|
|
|
181
185
|
issues.extend(
|
|
182
186
|
_validate_settings(
|
|
183
|
-
settings=
|
|
187
|
+
settings=_normalize_settings_mapping(
|
|
188
|
+
getattr(item, "host_settings", {}) or {}
|
|
189
|
+
),
|
|
184
190
|
path_prefix=f"items.{item_name}.settings.Host",
|
|
185
191
|
local_class=component_class,
|
|
186
192
|
iris_class_name=class_name,
|
|
187
193
|
)
|
|
188
194
|
)
|
|
189
195
|
|
|
190
|
-
adapter_settings =
|
|
196
|
+
adapter_settings = _normalize_settings_mapping(
|
|
197
|
+
getattr(item, "adapter_settings", {}) or {}
|
|
198
|
+
)
|
|
191
199
|
if str(getattr(item, "kind", "")) == "process" and adapter_settings:
|
|
192
200
|
issues.append(
|
|
193
201
|
ProductionValidationIssue(
|
|
@@ -334,9 +342,67 @@ def _local_setting_names(cls: type) -> set[str] | None:
|
|
|
334
342
|
if not callable(getter):
|
|
335
343
|
return None
|
|
336
344
|
try:
|
|
337
|
-
|
|
345
|
+
properties = getter()
|
|
338
346
|
except Exception:
|
|
339
347
|
return None
|
|
348
|
+
if not isinstance(properties, (list, tuple)):
|
|
349
|
+
return None
|
|
350
|
+
names: set[str] = set()
|
|
351
|
+
for prop in properties:
|
|
352
|
+
if isinstance(prop, (list, tuple)) and prop:
|
|
353
|
+
names.add(str(prop[0]))
|
|
354
|
+
return names
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _validate_target_setting_values(production: Any) -> list[ProductionValidationIssue]:
|
|
358
|
+
items = tuple(getattr(production, "items", ()) or ())
|
|
359
|
+
item_names = {str(getattr(item, "name", "")) for item in items}
|
|
360
|
+
issues: list[ProductionValidationIssue] = []
|
|
361
|
+
for item in items:
|
|
362
|
+
item_name = str(getattr(item, "name", ""))
|
|
363
|
+
host_settings = _normalize_settings_mapping(
|
|
364
|
+
getattr(item, "host_settings", {}) or {}
|
|
365
|
+
)
|
|
366
|
+
for setting_name in _target_setting_names(item):
|
|
367
|
+
if setting_name not in host_settings:
|
|
368
|
+
continue
|
|
369
|
+
for target_name in _target_names(host_settings[setting_name]):
|
|
370
|
+
if target_name in item_names:
|
|
371
|
+
continue
|
|
372
|
+
issues.append(
|
|
373
|
+
ProductionValidationIssue(
|
|
374
|
+
kind="route",
|
|
375
|
+
path=f"items.{item_name}.settings.Host.{setting_name}",
|
|
376
|
+
message=(
|
|
377
|
+
f"Target setting references missing production item "
|
|
378
|
+
f"{target_name!r}."
|
|
379
|
+
),
|
|
380
|
+
suggestion=(
|
|
381
|
+
f"Add a production item named {target_name!r}, "
|
|
382
|
+
"or update/remove this target setting."
|
|
383
|
+
),
|
|
384
|
+
)
|
|
385
|
+
)
|
|
386
|
+
return issues
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def _target_setting_names(item: Any) -> set[str]:
|
|
390
|
+
names = {str(name) for name in getattr(item, "target_setting_names", set())}
|
|
391
|
+
component_class = getattr(item, "component_class", None)
|
|
392
|
+
if isinstance(component_class, type):
|
|
393
|
+
for base in reversed(component_class.__mro__):
|
|
394
|
+
for name, value in base.__dict__.items():
|
|
395
|
+
if isinstance(value, TargetSetting):
|
|
396
|
+
names.add(str(name))
|
|
397
|
+
return names
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def _target_names(value: Any) -> tuple[str, ...]:
|
|
401
|
+
return tuple(
|
|
402
|
+
target
|
|
403
|
+
for target in (part.strip() for part in str(value or "").split(","))
|
|
404
|
+
if target
|
|
405
|
+
)
|
|
340
406
|
|
|
341
407
|
|
|
342
408
|
def _validate_names_with_known_set(
|
|
@@ -394,7 +460,7 @@ def _adapter_class_name_from_host(host_class_name: str) -> str:
|
|
|
394
460
|
return ""
|
|
395
461
|
|
|
396
462
|
|
|
397
|
-
def _iris_module():
|
|
463
|
+
def _iris_module() -> Any:
|
|
398
464
|
try:
|
|
399
465
|
import iris # type: ignore
|
|
400
466
|
except Exception:
|
iop/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
{iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris_pex_embedded_python
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.1
|
|
4
4
|
Summary: Iris Interoperability based on Embedded Python
|
|
5
5
|
Author-email: grongier <guillaume.rongier@intersystems.com>
|
|
6
6
|
License: MIT License
|
|
@@ -69,14 +69,38 @@ For application repositories, start from the [reusable AGENTS.md template](https
|
|
|
69
69
|
|
|
70
70
|
## Example
|
|
71
71
|
|
|
72
|
-
Here's a
|
|
72
|
+
Here's a tiny Python-authored production:
|
|
73
73
|
|
|
74
74
|
```python
|
|
75
|
-
from
|
|
75
|
+
from dataclasses import dataclass
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
from iop import BusinessOperation, Message, PollingBusinessService, Production, target
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class HelloRequest(Message):
|
|
82
|
+
text: str = "Hello World"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class HelloService(PollingBusinessService):
|
|
86
|
+
Output = target()
|
|
87
|
+
|
|
88
|
+
def on_poll(self):
|
|
89
|
+
self.send_request_async(self.Output, HelloRequest())
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class HelloOperation(BusinessOperation):
|
|
93
|
+
def on_message(self, request: HelloRequest):
|
|
94
|
+
self.log_info(request.text)
|
|
95
|
+
return request
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
prod = Production("HelloWorld.Production", testing_enabled=True)
|
|
99
|
+
service = prod.service("HelloService", HelloService)
|
|
100
|
+
operation = prod.operation("HelloOperation", HelloOperation)
|
|
101
|
+
service.connect(HelloService.Output, operation)
|
|
102
|
+
|
|
103
|
+
PRODUCTIONS = [prod]
|
|
80
104
|
```
|
|
81
105
|
|
|
82
106
|
## Installation
|
{iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/RECORD
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
iop/__init__.py,sha256=
|
|
1
|
+
iop/__init__.py,sha256=bnhSiC7XcOIiS7e51uY8fr9Li7RYjhCnlCyVDzZI6-I,10636
|
|
2
2
|
iop/__main__.py,sha256=2rUNM7vaYK0W57Jj72rm7GORyIFLMXKwPq3QNLwYBmY,100
|
|
3
|
+
iop/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
4
|
iop/cli/__init__.py,sha256=Y78pBdA-ULzq1c_9xQZsFBlzm3x5xgxSzkvrH5DoM7I,31
|
|
4
5
|
iop/cli/formatting.py,sha256=OLgHA1d8_paAuINQyKkYgihWMLoBhPn7kSXW5whRlIs,1606
|
|
5
6
|
iop/cli/main.py,sha256=r3sLZniM4LCXP6u1kuQmUgMLLD0H04NC5gVXKMNY31M,18418
|
|
@@ -39,7 +40,7 @@ iop/components/async_request.py,sha256=AU36pf6NIQMM9ZYR5h6LeQry0EfXXqDaKAjsP16_h
|
|
|
39
40
|
iop/components/business_host.py,sha256=5EXwzZzfEVYLFlzi519GXKclTz2m5FMcqtl10lLzUyw,12089
|
|
40
41
|
iop/components/business_operation.py,sha256=KycRNz-zuyJs2VneTBVcppyd3rKLekrISjbubCbzHxY,2905
|
|
41
42
|
iop/components/business_process.py,sha256=1xTYwqhvJaXC-BvQ5WoGOud5QwxT9EPpvDPDX4zThXg,9839
|
|
42
|
-
iop/components/business_service.py,sha256=
|
|
43
|
+
iop/components/business_service.py,sha256=Bp47bJzTWHp66kp0Zo_D-blOKHzj4i6kXu-lCRMMzfg,3597
|
|
43
44
|
iop/components/common.py,sha256=tsP2APRBnks1hVazS9dX0Q8KCoANbUsnaFTlzqOIkVY,19063
|
|
44
45
|
iop/components/debugpy.py,sha256=sNFKaF9MtWBNAqxH4ubSIVqjsIpsHGjRK2jzBU-O59Y,6011
|
|
45
46
|
iop/components/generator_request.py,sha256=NOllwJnY06kk_eC7cQXDQ8NBFKfQakyz3A_AgYJ5f5Y,1351
|
|
@@ -53,7 +54,7 @@ iop/components/settings.py,sha256=USAKAisdersKlAEIk8HDu_TuYtkO-Sc3an3PXjPcDRA,62
|
|
|
53
54
|
iop/messages/__init__.py,sha256=k1AKplpjdqSxM5Gl7bpWAfw93xUgigovlI4SKhwKHRI,355
|
|
54
55
|
iop/messages/base.py,sha256=ZrVXEz7JrYHnt5b3M7avxcJCB0_OZxm1uWm9gQ4_eAw,1906
|
|
55
56
|
iop/messages/decorators.py,sha256=CWk08k8U2aTJv7Dx1n2jp8sjZZSCD8NJPoifKLB3W2g,2488
|
|
56
|
-
iop/messages/dispatch.py,sha256=
|
|
57
|
+
iop/messages/dispatch.py,sha256=l7FX-TAx5cLgjxoxNpL8ul3Lj4w4-taxTtyeZU3W85I,14001
|
|
57
58
|
iop/messages/persistent.py,sha256=ibRhRTqzwGcAqem744KZzHiouUlc8-J3ftB4zyzQYx4,16906
|
|
58
59
|
iop/messages/serialization.py,sha256=BW0o-7GaceMW7RMOzOJ8g9rKEv28NYnYFwtTLmAf7Yg,9255
|
|
59
60
|
iop/messages/validation.py,sha256=X6MSWsjLZDuyX1Tfx0TP3T6OI4nj1HZccwR2Z9PSubY,1606
|
|
@@ -61,24 +62,24 @@ iop/migration/__init__.py,sha256=wp-RvjLKYW_Pi2AJLfiWe1bACxENzEgjXtP9UMNiSVY,36
|
|
|
61
62
|
iop/migration/io.py,sha256=hAehtApFZFgGzjzgwBmDMxdA1xoRhE-okOcEzvgFdQ4,1822
|
|
62
63
|
iop/migration/manifest.py,sha256=Bs4eC1_i-ZnovlgSW9FKu5WBwy_6Zwy5ZAcsi5A1szU,19351
|
|
63
64
|
iop/migration/plans.py,sha256=5kx3aqQiPDJ3F8hU9pp9_mOO1_N6GA0Ps7--G1Iv6z8,2549
|
|
64
|
-
iop/migration/utils.py,sha256=
|
|
65
|
+
iop/migration/utils.py,sha256=pOojLPMZes05KXrGN2ap45ffppP5Z4tS4bjJ0gSD5Oc,38183
|
|
65
66
|
iop/production/__init__.py,sha256=95VmJgC3lWtHpUJijLqyKKxFZa65OcRni8803kb4aHE,2148
|
|
66
67
|
iop/production/actions.py,sha256=TLVAjPTPq21oLj9c-IG10qMNJ2hvPzueviMy_c1a0ZU,17199
|
|
67
|
-
iop/production/common.py,sha256=
|
|
68
|
-
iop/production/component.py,sha256=
|
|
69
|
-
iop/production/declarations.py,sha256=
|
|
68
|
+
iop/production/common.py,sha256=L2QyvE2nC1J333sbebYx_6dyoaFL-89ouMO3Kfe4-D8,3465
|
|
69
|
+
iop/production/component.py,sha256=XalzNEWhCC1RVSZlQZRBpZM3BdRC2TDU-ko3Zn8-Kzo,9475
|
|
70
|
+
iop/production/declarations.py,sha256=u1hzgbDchr55R3dEXEIi9-P5JkfMG7C3aiSWhfhifG8,5952
|
|
70
71
|
iop/production/declarative.py,sha256=IpHYO46mu7k9wnq3DpFreoALPoX1Vi8DrJb-85O_-bQ,7853
|
|
71
72
|
iop/production/diff.py,sha256=NYpcSVklaGpaZOyl933W8eLsDWcwjlf6Upbp4pVGSMU,9975
|
|
72
73
|
iop/production/import_.py,sha256=twBra6j2peolFadv8WyDwZZOd9NznzAkPsk2RbOfZQM,10833
|
|
73
74
|
iop/production/inspection.py,sha256=PPv9DiDS4OrnKROqV7JPbuY8Y0JR-m8syPhap3GgE4g,3363
|
|
74
|
-
iop/production/model.py,sha256=
|
|
75
|
+
iop/production/model.py,sha256=bEtDo-IwECuCrkKDXJXm1hB5Bmme4srB6l9isc8n3KI,44088
|
|
75
76
|
iop/production/planning.py,sha256=nCYrXLKlHBlUaQZPzPfqtIERIv62F2sg4gJ0b8mtcKk,23375
|
|
76
77
|
iop/production/reconstruction.py,sha256=5vVteTEM6IOiQUfpe4AUQg6Nt4oaaIDR61-1l6Vu8hk,12532
|
|
77
|
-
iop/production/rendering.py,sha256=
|
|
78
|
+
iop/production/rendering.py,sha256=gyJyUcWwvgwRWvlvddZbCIhkjJ1DcMZfbL2brIa_k8U,20229
|
|
78
79
|
iop/production/runtime.py,sha256=6grX1u20OhHnvhzC3yPDTFEoDs_TN4mfs5MxzFzZMls,2637
|
|
79
80
|
iop/production/source_inference.py,sha256=Wl3E9-1hWb4qxD1jwrrZTLSgqN-0vGhOrJtmzDWPCao,21613
|
|
80
|
-
iop/production/types.py,sha256=
|
|
81
|
-
iop/production/validation.py,sha256=
|
|
81
|
+
iop/production/types.py,sha256=hzO8rj73z16WqFQBI7YBAznY-1fD8ENyJqzTY-ydFXI,16889
|
|
82
|
+
iop/production/validation.py,sha256=gzRFLCTPGiNMIot1yG1FXG5ab9inpq4rqYYQpefhBYs,16217
|
|
82
83
|
iop/runtime/__init__.py,sha256=wcyWMRuPCYE_CLd1NmgmI1M-IbFs2Gz2yIj2-EW_2AA,70
|
|
83
84
|
iop/runtime/director.py,sha256=KW8BvkATK8XuIUPNBD9rMww9r3Zg4K3H54868eOgvl0,12867
|
|
84
85
|
iop/runtime/environment.py,sha256=0KZ4EoW6NUEbF7FW471emxQ-9FbaiX6ngUHVGihgZXU,1564
|
|
@@ -91,9 +92,9 @@ iop/runtime/remote/director.py,sha256=bkie751GrYLgGs7ApRCowHpSnJA8KupxCOrFDQmjyO
|
|
|
91
92
|
iop/runtime/remote/migration.py,sha256=Iboz-Ye7i9xif9bn433GazCF-gtD-HJW3wiUwWS5P6w,1831
|
|
92
93
|
iop/runtime/remote/settings.py,sha256=P1Hsgld5o57HpSZgPVZzobyjlUmxJj6bstiWvR0JXnc,2144
|
|
93
94
|
iop/runtime/remote/setup.py,sha256=Tr80F3JJTy7oSUso2jyx0iA_KZayd4MYt9vL0BvPpMA,2600
|
|
94
|
-
iris_pex_embedded_python-4.0.
|
|
95
|
-
iris_pex_embedded_python-4.0.
|
|
96
|
-
iris_pex_embedded_python-4.0.
|
|
97
|
-
iris_pex_embedded_python-4.0.
|
|
98
|
-
iris_pex_embedded_python-4.0.
|
|
99
|
-
iris_pex_embedded_python-4.0.
|
|
95
|
+
iris_pex_embedded_python-4.0.1.dist-info/licenses/LICENSE,sha256=rZSiBFId_sfbJ6RL0GjjPX-InNLkNS9ou7eQsikciI8,1089
|
|
96
|
+
iris_pex_embedded_python-4.0.1.dist-info/METADATA,sha256=hf-w2SSbyHHLLX_SIr41V2hKx3CQ2mVjnbZmJ2Oczic,5852
|
|
97
|
+
iris_pex_embedded_python-4.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
98
|
+
iris_pex_embedded_python-4.0.1.dist-info/entry_points.txt,sha256=fzS8ZFsPe8cnpEx208X60DNugCPQmuSloPeg4pyyJDY,42
|
|
99
|
+
iris_pex_embedded_python-4.0.1.dist-info/top_level.txt,sha256=BM54-OXQ6l2BDtmesWNXckh033s9gcjoO7bfjbwZbxU,4
|
|
100
|
+
iris_pex_embedded_python-4.0.1.dist-info/RECORD,,
|
{iris_pex_embedded_python-4.0.0b15.dist-info → iris_pex_embedded_python-4.0.1.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|