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.
- iop/__init__.py +276 -18
- iop/__main__.py +3 -3
- iop/cli/__init__.py +1 -0
- iop/cli/formatting.py +45 -0
- iop/{_cli.py → cli/main.py} +238 -216
- iop/cli/parser.py +165 -0
- iop/cli/types.py +73 -0
- iop/cls/IOP/Common.cls +11 -2
- iop/cls/IOP/PrivateSession/Duplex.cls +1 -1
- iop/cls/IOP/Service/Remote/Rest/v1.cls +152 -5
- iop/cls/IOP/Utils.cls +814 -7
- iop/cls/IOP/Wrapper.cls +1 -1
- iop/components/__init__.py +16 -0
- iop/{_async_request.py → components/async_request.py} +7 -7
- iop/components/business_host.py +363 -0
- iop/components/business_operation.py +84 -0
- iop/{_business_process.py → components/business_process.py} +145 -125
- iop/components/business_service.py +106 -0
- iop/{_common.py → components/common.py} +160 -164
- iop/{_debugpy.py → components/debugpy.py} +11 -11
- iop/{_generator_request.py → components/generator_request.py} +4 -4
- iop/{_inbound_adapter.py → components/inbound_adapter.py} +10 -18
- iop/{_log_manager.py → components/log_manager.py} +1 -1
- iop/{_outbound_adapter.py → components/outbound_adapter.py} +1 -1
- iop/components/polling_business_service.py +48 -0
- iop/{_private_session_duplex.py → components/private_session_duplex.py} +7 -9
- iop/{_private_session_process.py → components/private_session_process.py} +2 -2
- iop/{_settings.py → components/settings.py} +23 -3
- iop/messages/__init__.py +7 -0
- iop/messages/base.py +61 -0
- iop/{_decorators.py → messages/decorators.py} +8 -2
- iop/messages/dispatch.py +351 -0
- iop/{_persistent_message.py → messages/persistent.py} +24 -19
- iop/{_serialization.py → messages/serialization.py} +34 -21
- iop/{_message_validator.py → messages/validation.py} +15 -13
- iop/migration/__init__.py +1 -0
- iop/migration/io.py +61 -0
- iop/migration/manifest.py +534 -0
- iop/migration/plans.py +80 -0
- iop/migration/utils.py +1126 -0
- iop/production/__init__.py +55 -0
- iop/production/actions.py +525 -0
- iop/production/common.py +103 -0
- iop/production/component.py +234 -0
- iop/production/declarations.py +190 -0
- iop/production/declarative.py +214 -0
- iop/production/diff.py +327 -0
- iop/production/import_.py +296 -0
- iop/production/inspection.py +92 -0
- iop/production/model.py +1143 -0
- iop/production/planning.py +678 -0
- iop/production/reconstruction.py +341 -0
- iop/production/rendering.py +610 -0
- iop/production/runtime.py +91 -0
- iop/production/source_inference.py +729 -0
- iop/production/types.py +546 -0
- iop/production/validation.py +452 -0
- iop/runtime/__init__.py +1 -0
- iop/runtime/director.py +415 -0
- iop/runtime/environment.py +59 -0
- iop/{_iris.py → runtime/iris.py} +2 -2
- iop/runtime/local.py +145 -0
- iop/{_director_protocol.py → runtime/protocol.py} +25 -8
- iop/runtime/remote/__init__.py +12 -0
- iop/runtime/remote/client.py +90 -0
- iop/runtime/remote/director.py +283 -0
- iop/runtime/remote/migration.py +57 -0
- iop/runtime/remote/settings.py +69 -0
- iop/runtime/remote/setup.py +72 -0
- {iris_pex_embedded_python-3.7.2b2.dist-info → iris_pex_embedded_python-4.0.0.dist-info}/METADATA +11 -2
- iris_pex_embedded_python-4.0.0.dist-info/RECORD +99 -0
- iris_pex_embedded_python-4.0.0.dist-info/entry_points.txt +2 -0
- iris_pex_embedded_python-4.0.0.dist-info/top_level.txt +1 -0
- grongier/__init__.py +0 -0
- grongier/cls/Grongier/PEX/BusinessOperation.cls +0 -8
- grongier/cls/Grongier/PEX/BusinessProcess.cls +0 -13
- grongier/cls/Grongier/PEX/BusinessService.cls +0 -8
- grongier/cls/Grongier/PEX/Common.cls +0 -10
- grongier/cls/Grongier/PEX/Director.cls +0 -10
- grongier/cls/Grongier/PEX/Duplex/Operation.cls +0 -4
- grongier/cls/Grongier/PEX/Duplex/Process.cls +0 -13
- grongier/cls/Grongier/PEX/Duplex/Service.cls +0 -4
- grongier/cls/Grongier/PEX/InboundAdapter.cls +0 -8
- grongier/cls/Grongier/PEX/Message.cls +0 -13
- grongier/cls/Grongier/PEX/OutboundAdapter.cls +0 -8
- grongier/cls/Grongier/PEX/PickleMessage.cls +0 -13
- grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +0 -8
- grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +0 -14
- grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +0 -14
- grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +0 -14
- grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +0 -14
- grongier/cls/Grongier/PEX/Test.cls +0 -10
- grongier/cls/Grongier/PEX/Utils.cls +0 -10
- grongier/cls/Grongier/Service/WSGI.cls +0 -4
- grongier/pex/__init__.py +0 -75
- grongier/pex/__main__.py +0 -4
- grongier/pex/_business_host.py +0 -1
- grongier/pex/_cli.py +0 -4
- grongier/pex/_common.py +0 -1
- grongier/pex/_director.py +0 -1
- grongier/pex/_utils.py +0 -1
- grongier/pex/wsgi/handlers.py +0 -104
- iop/_business_host.py +0 -322
- iop/_business_operation.py +0 -77
- iop/_business_service.py +0 -67
- iop/_director.py +0 -333
- iop/_dispatch.py +0 -194
- iop/_local.py +0 -106
- iop/_message.py +0 -45
- iop/_polling_business_service.py +0 -6
- iop/_remote.py +0 -473
- iop/_utils.py +0 -912
- iop/cls/IOP/Service/WSGI.cls +0 -310
- iop/wsgi/handlers.py +0 -112
- iris_pex_embedded_python-3.7.2b2.dist-info/RECORD +0 -96
- iris_pex_embedded_python-3.7.2b2.dist-info/entry_points.txt +0 -2
- iris_pex_embedded_python-3.7.2b2.dist-info/top_level.txt +0 -2
- {iris_pex_embedded_python-3.7.2b2.dist-info → iris_pex_embedded_python-4.0.0.dist-info}/WHEEL +0 -0
- {iris_pex_embedded_python-3.7.2b2.dist-info → iris_pex_embedded_python-4.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,27 +1,23 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import inspect
|
|
2
|
+
import traceback
|
|
3
|
+
import warnings
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from types import UnionType
|
|
6
|
-
from typing import (
|
|
7
|
-
Annotated,
|
|
8
|
-
Any,
|
|
9
|
-
ClassVar,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
from . import
|
|
20
|
-
|
|
21
|
-
from ._log_manager import LogManager, logging
|
|
22
|
-
from ._settings import Setting
|
|
23
|
-
|
|
24
|
-
|
|
6
|
+
from typing import (
|
|
7
|
+
Annotated,
|
|
8
|
+
Any,
|
|
9
|
+
ClassVar,
|
|
10
|
+
Union,
|
|
11
|
+
get_args,
|
|
12
|
+
get_origin,
|
|
13
|
+
get_type_hints,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from ..runtime import iris as _iris
|
|
17
|
+
from .debugpy import debugpython
|
|
18
|
+
from .log_manager import LogManager, logging
|
|
19
|
+
from .settings import Setting
|
|
20
|
+
|
|
25
21
|
_NO_VALUE = object()
|
|
26
22
|
|
|
27
23
|
_EXCLUDED_SETTING_NAMES = {
|
|
@@ -88,7 +84,7 @@ def _unwrap_annotated(data_type: Any) -> tuple[Any, tuple[Any, ...]]:
|
|
|
88
84
|
return data_type, ()
|
|
89
85
|
|
|
90
86
|
|
|
91
|
-
def _setting_from_annotation(data_type: Any) -> tuple[Any,
|
|
87
|
+
def _setting_from_annotation(data_type: Any) -> tuple[Any, Setting | None]:
|
|
92
88
|
data_type, metadata = _unwrap_annotated(data_type)
|
|
93
89
|
setting = None
|
|
94
90
|
for item in metadata:
|
|
@@ -106,7 +102,7 @@ def _unwrap_optional(data_type: Any) -> Any:
|
|
|
106
102
|
return data_type
|
|
107
103
|
|
|
108
104
|
|
|
109
|
-
def _iris_data_type(data_type: Any) ->
|
|
105
|
+
def _iris_data_type(data_type: Any) -> str | None:
|
|
110
106
|
if data_type is None or data_type == "":
|
|
111
107
|
return None
|
|
112
108
|
|
|
@@ -138,9 +134,18 @@ def _is_setting_member(name: str, value: Any) -> bool:
|
|
|
138
134
|
return not (
|
|
139
135
|
inspect.ismethod(value) or inspect.isfunction(value) or inspect.isclass(value)
|
|
140
136
|
)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _custom_init_owner(cls: type) -> type | None:
|
|
140
|
+
for base in inspect.getmro(cls):
|
|
141
|
+
init = base.__dict__.get("__init__", _NO_VALUE)
|
|
142
|
+
if init is _NO_VALUE or init is object.__init__:
|
|
143
|
+
continue
|
|
144
|
+
return base
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class _Common:
|
|
144
149
|
"""Base class that defines common methods for all component types.
|
|
145
150
|
|
|
146
151
|
Provides core functionality like initialization, teardown, connection handling
|
|
@@ -149,13 +154,52 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
149
154
|
|
|
150
155
|
INFO_URL: ClassVar[str]
|
|
151
156
|
ICON_URL: ClassVar[str]
|
|
152
|
-
iris_handle: Any = None
|
|
153
|
-
_log_to_console: bool = False
|
|
154
|
-
_logger:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
iris_handle: Any = None
|
|
158
|
+
_log_to_console: bool = False
|
|
159
|
+
_logger: logging.Logger | None = None
|
|
160
|
+
|
|
161
|
+
def __init_subclass__(cls, **kwargs: Any) -> None:
|
|
162
|
+
super().__init_subclass__(**kwargs)
|
|
163
|
+
cls._warn_if_custom_init_defined(stacklevel=2)
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def _custom_init_warning_message(cls) -> str | None:
|
|
167
|
+
if _custom_init_owner(cls) is None:
|
|
168
|
+
return None
|
|
169
|
+
classname = f"{cls.__module__}.{cls.__qualname__}"
|
|
170
|
+
return (
|
|
171
|
+
f"{classname} defines or inherits __init__(), but IoP/IRIS "
|
|
172
|
+
"instantiates components with __new__() and does not call "
|
|
173
|
+
"__init__(). Move startup logic to on_init(); use class attributes "
|
|
174
|
+
"or iop.Setting for configurable defaults."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
@classmethod
|
|
178
|
+
def _warn_if_custom_init_defined(cls, stacklevel: int = 2) -> None:
|
|
179
|
+
message = cls._custom_init_warning_message()
|
|
180
|
+
if message is None:
|
|
181
|
+
return
|
|
182
|
+
warnings.warn(message, RuntimeWarning, stacklevel=stacklevel)
|
|
183
|
+
|
|
184
|
+
def _log_custom_init_warning(self) -> None:
|
|
185
|
+
message = self.__class__._custom_init_warning_message()
|
|
186
|
+
if message is None:
|
|
187
|
+
return
|
|
188
|
+
try:
|
|
189
|
+
self.log_warning(message)
|
|
190
|
+
except Exception:
|
|
191
|
+
try:
|
|
192
|
+
warnings.warn(message, RuntimeWarning, stacklevel=2)
|
|
193
|
+
except Exception:
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
def _warn_if_custom_init(self) -> None:
|
|
197
|
+
"""Metadata-safe warning hook for ObjectScript __new__ allocations."""
|
|
198
|
+
self._log_custom_init_warning()
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def get_adapter_type() -> str | None:
|
|
202
|
+
"""Get the adapter type for this component. Override in subclasses."""
|
|
159
203
|
return None
|
|
160
204
|
|
|
161
205
|
@property
|
|
@@ -179,10 +223,36 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
179
223
|
self._log_to_console = value
|
|
180
224
|
self.logger = LogManager.get_logger(self.__class__.__name__, value)
|
|
181
225
|
|
|
182
|
-
# Lifecycle methods
|
|
183
|
-
def on_init(self) -> None:
|
|
184
|
-
"""
|
|
185
|
-
|
|
226
|
+
# Lifecycle methods
|
|
227
|
+
def on_init(self) -> None:
|
|
228
|
+
"""Purpose:
|
|
229
|
+
Component startup hook.
|
|
230
|
+
|
|
231
|
+
Use when:
|
|
232
|
+
A component needs to initialize clients, caches, credentials,
|
|
233
|
+
counters, or other runtime state after IRIS creates the host.
|
|
234
|
+
|
|
235
|
+
Lifecycle:
|
|
236
|
+
IoP calls on_init() from the internal dispatch startup path. IRIS
|
|
237
|
+
may allocate the Python object without calling __init__().
|
|
238
|
+
|
|
239
|
+
Best practices:
|
|
240
|
+
Keep initialization idempotent and quick. Read production settings
|
|
241
|
+
from self inside this method.
|
|
242
|
+
|
|
243
|
+
Common mistakes:
|
|
244
|
+
Do not put component startup work in __init__(); it may not run in
|
|
245
|
+
the IRIS component lifecycle.
|
|
246
|
+
|
|
247
|
+
Minimal example:
|
|
248
|
+
def on_init(self):
|
|
249
|
+
self.client = make_client(self.Endpoint)
|
|
250
|
+
|
|
251
|
+
Related:
|
|
252
|
+
docs/ai-coding.md,
|
|
253
|
+
docs/cookbooks/index.md
|
|
254
|
+
"""
|
|
255
|
+
pass
|
|
186
256
|
|
|
187
257
|
def on_tear_down(self) -> None:
|
|
188
258
|
"""Clean up component before termination."""
|
|
@@ -196,9 +266,10 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
196
266
|
def _dispatch_on_connected(self, host_object: Any) -> None:
|
|
197
267
|
self.on_connected()
|
|
198
268
|
|
|
199
|
-
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
200
|
-
"""Initialize component when started."""
|
|
201
|
-
self.
|
|
269
|
+
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
270
|
+
"""Initialize component when started."""
|
|
271
|
+
self._log_custom_init_warning()
|
|
272
|
+
self.on_init()
|
|
202
273
|
|
|
203
274
|
def _dispatch_on_tear_down(self, host_object: Any) -> None:
|
|
204
275
|
self.on_tear_down()
|
|
@@ -214,7 +285,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
214
285
|
|
|
215
286
|
# Component information methods
|
|
216
287
|
@classmethod
|
|
217
|
-
def _get_info(cls) ->
|
|
288
|
+
def _get_info(cls) -> list[str]:
|
|
218
289
|
"""Get component configuration information.
|
|
219
290
|
|
|
220
291
|
Returns information used to display in Production config UI including:
|
|
@@ -231,37 +302,26 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
231
302
|
super_class = ""
|
|
232
303
|
adapter = ""
|
|
233
304
|
try:
|
|
234
|
-
# Get tuple of the class's base classes and loop through them until we find one of the
|
|
235
|
-
classes = inspect.getmro(cls)
|
|
236
|
-
for cl in classes:
|
|
237
|
-
classname = str(cl)[7:-1]
|
|
305
|
+
# Get tuple of the class's base classes and loop through them until we find one of the public component classes.
|
|
306
|
+
classes = inspect.getmro(cls)
|
|
307
|
+
for cl in classes:
|
|
308
|
+
classname = str(cl)[7:-1]
|
|
238
309
|
if classname in [
|
|
239
310
|
"'iop.BusinessService'",
|
|
240
|
-
"'iop.BusinessOperation'",
|
|
241
|
-
"'iop.DuplexOperation'",
|
|
242
|
-
"'iop.DuplexService'",
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
break
|
|
255
|
-
elif classname in [
|
|
256
|
-
"'iop.BusinessProcess'",
|
|
257
|
-
"'iop.DuplexProcess'",
|
|
258
|
-
"'iop.InboundAdapter'",
|
|
259
|
-
"'iop.OutboundAdapter'",
|
|
260
|
-
"'grongier.pex.BusinessProcess'",
|
|
261
|
-
"'grongier.pex.DuplexProcess'",
|
|
262
|
-
"'grongier.pex.InboundAdapter'",
|
|
263
|
-
"'grongier.pex.OutboundAdapter'",
|
|
264
|
-
]:
|
|
311
|
+
"'iop.BusinessOperation'",
|
|
312
|
+
"'iop.DuplexOperation'",
|
|
313
|
+
"'iop.DuplexService'",
|
|
314
|
+
]:
|
|
315
|
+
# Remove the apostrophes and set as super_class, then find if it uses an adapter
|
|
316
|
+
super_class = classname[1:-1]
|
|
317
|
+
adapter = cls.get_adapter_type() or ""
|
|
318
|
+
break
|
|
319
|
+
elif classname in [
|
|
320
|
+
"'iop.BusinessProcess'",
|
|
321
|
+
"'iop.DuplexProcess'",
|
|
322
|
+
"'iop.InboundAdapter'",
|
|
323
|
+
"'iop.OutboundAdapter'",
|
|
324
|
+
]:
|
|
265
325
|
# Remove the apostrophes and set as super_class
|
|
266
326
|
super_class = classname[1:-1]
|
|
267
327
|
break
|
|
@@ -290,7 +350,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
290
350
|
return ret
|
|
291
351
|
|
|
292
352
|
@classmethod
|
|
293
|
-
def _get_properties(cls) ->
|
|
353
|
+
def _get_properties(cls) -> list[list[Any]]:
|
|
294
354
|
"""Get component properties for Production configuration.
|
|
295
355
|
|
|
296
356
|
Returns list of property definitions containing:
|
|
@@ -304,8 +364,8 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
304
364
|
|
|
305
365
|
Only includes non-private class attributes and properties.
|
|
306
366
|
"""
|
|
307
|
-
ret = []
|
|
308
|
-
try:
|
|
367
|
+
ret = []
|
|
368
|
+
try:
|
|
309
369
|
annotations = _type_hints_with_extras(cls)
|
|
310
370
|
members = dict(inspect.getmembers(cls))
|
|
311
371
|
|
|
@@ -411,12 +471,15 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
411
471
|
_string_metadata(control), # Control/editor context
|
|
412
472
|
]
|
|
413
473
|
)
|
|
414
|
-
except Exception:
|
|
415
|
-
|
|
416
|
-
|
|
474
|
+
except Exception as exc:
|
|
475
|
+
raise RuntimeError(
|
|
476
|
+
f"Failed to build settings metadata for "
|
|
477
|
+
f"{cls.__module__}.{cls.__qualname__}"
|
|
478
|
+
) from exc
|
|
479
|
+
return ret
|
|
417
480
|
|
|
418
481
|
# Logging methods
|
|
419
|
-
def _log(self) ->
|
|
482
|
+
def _log(self) -> tuple[str, str | None]:
|
|
420
483
|
"""Get class and method name for logging.
|
|
421
484
|
|
|
422
485
|
Returns:
|
|
@@ -432,7 +495,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
432
495
|
return current_class, current_method
|
|
433
496
|
|
|
434
497
|
def _logging(
|
|
435
|
-
self, message: str, level: int, to_console:
|
|
498
|
+
self, message: str, level: int, to_console: bool | None = None
|
|
436
499
|
) -> None:
|
|
437
500
|
"""Write log entry.
|
|
438
501
|
|
|
@@ -441,56 +504,20 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
441
504
|
level: Log level
|
|
442
505
|
to_console: If True, log to console instead of IRIS
|
|
443
506
|
"""
|
|
444
|
-
current_class, current_method = self._log()
|
|
445
|
-
if to_console is None:
|
|
446
|
-
to_console = self.log_to_console
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
message,
|
|
459
|
-
extra={
|
|
460
|
-
"to_console": to_console,
|
|
461
|
-
"class_name": current_class,
|
|
462
|
-
"method_name": current_method,
|
|
463
|
-
},
|
|
464
|
-
)
|
|
465
|
-
elif level == logging.CRITICAL:
|
|
466
|
-
self.logger.critical(
|
|
467
|
-
message,
|
|
468
|
-
extra={
|
|
469
|
-
"to_console": to_console,
|
|
470
|
-
"class_name": current_class,
|
|
471
|
-
"method_name": current_method,
|
|
472
|
-
},
|
|
473
|
-
)
|
|
474
|
-
elif level == logging.WARNING:
|
|
475
|
-
self.logger.warning(
|
|
476
|
-
message,
|
|
477
|
-
extra={
|
|
478
|
-
"to_console": to_console,
|
|
479
|
-
"class_name": current_class,
|
|
480
|
-
"method_name": current_method,
|
|
481
|
-
},
|
|
482
|
-
)
|
|
483
|
-
elif level == logging.ERROR:
|
|
484
|
-
self.logger.error(
|
|
485
|
-
message,
|
|
486
|
-
extra={
|
|
487
|
-
"to_console": to_console,
|
|
488
|
-
"class_name": current_class,
|
|
489
|
-
"method_name": current_method,
|
|
490
|
-
},
|
|
491
|
-
)
|
|
492
|
-
|
|
493
|
-
def trace(self, message: str, to_console: Optional[bool] = None) -> None:
|
|
507
|
+
current_class, current_method = self._log()
|
|
508
|
+
if to_console is None:
|
|
509
|
+
to_console = self.log_to_console
|
|
510
|
+
self.logger.log(
|
|
511
|
+
level,
|
|
512
|
+
message,
|
|
513
|
+
extra={
|
|
514
|
+
"to_console": to_console,
|
|
515
|
+
"class_name": current_class,
|
|
516
|
+
"method_name": current_method,
|
|
517
|
+
},
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
def trace(self, message: str, to_console: bool | None = None) -> None:
|
|
494
521
|
"""Write trace log entry.
|
|
495
522
|
|
|
496
523
|
Args:
|
|
@@ -499,7 +526,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
499
526
|
"""
|
|
500
527
|
self._logging(message, logging.DEBUG, to_console)
|
|
501
528
|
|
|
502
|
-
def log_info(self, message: str, to_console:
|
|
529
|
+
def log_info(self, message: str, to_console: bool | None = None) -> None:
|
|
503
530
|
"""Write info log entry.
|
|
504
531
|
|
|
505
532
|
Args:
|
|
@@ -508,7 +535,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
508
535
|
"""
|
|
509
536
|
self._logging(message, logging.INFO, to_console)
|
|
510
537
|
|
|
511
|
-
def log_alert(self, message: str, to_console:
|
|
538
|
+
def log_alert(self, message: str, to_console: bool | None = None) -> None:
|
|
512
539
|
"""Write alert log entry.
|
|
513
540
|
|
|
514
541
|
Args:
|
|
@@ -517,7 +544,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
517
544
|
"""
|
|
518
545
|
self._logging(message, logging.CRITICAL, to_console)
|
|
519
546
|
|
|
520
|
-
def log_warning(self, message: str, to_console:
|
|
547
|
+
def log_warning(self, message: str, to_console: bool | None = None) -> None:
|
|
521
548
|
"""Write warning log entry.
|
|
522
549
|
|
|
523
550
|
Args:
|
|
@@ -526,7 +553,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
526
553
|
"""
|
|
527
554
|
self._logging(message, logging.WARNING, to_console)
|
|
528
555
|
|
|
529
|
-
def log_error(self, message: str, to_console:
|
|
556
|
+
def log_error(self, message: str, to_console: bool | None = None) -> None:
|
|
530
557
|
"""Write error log entry.
|
|
531
558
|
|
|
532
559
|
Args:
|
|
@@ -545,34 +572,3 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
545
572
|
current_class, current_method = self._log()
|
|
546
573
|
iris.cls("Ens.Util.Log").LogAssert(current_class, current_method, message)
|
|
547
574
|
|
|
548
|
-
def LOGINFO(self, message: str) -> None:
|
|
549
|
-
"""DEPRECATED: Use log_info."""
|
|
550
|
-
return self.log_info(message=message)
|
|
551
|
-
|
|
552
|
-
def LOGALERT(self, message: str) -> None:
|
|
553
|
-
"""DEPRECATED: Use log_alert."""
|
|
554
|
-
return self.log_alert(message)
|
|
555
|
-
|
|
556
|
-
def LOGWARNING(self, message: str) -> None:
|
|
557
|
-
"""DEPRECATED: Use log_warning."""
|
|
558
|
-
return self.log_warning(message)
|
|
559
|
-
|
|
560
|
-
def LOGERROR(self, message: str) -> None:
|
|
561
|
-
"""DEPRECATED: Use log_error."""
|
|
562
|
-
return self.log_error(message)
|
|
563
|
-
|
|
564
|
-
def LOGASSERT(self, message: str) -> None:
|
|
565
|
-
"""DEPRECATED: Use log_assert."""
|
|
566
|
-
return self.log_assert(message)
|
|
567
|
-
|
|
568
|
-
def OnInit(self) -> None:
|
|
569
|
-
"""DEPRECATED: Use on_init."""
|
|
570
|
-
return
|
|
571
|
-
|
|
572
|
-
def OnTearDown(self) -> None:
|
|
573
|
-
"""DEPRECATED: Use on_tear_down."""
|
|
574
|
-
return
|
|
575
|
-
|
|
576
|
-
def OnConnected(self) -> None:
|
|
577
|
-
"""DEPRECATED: Use on_connected."""
|
|
578
|
-
return
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import threading
|
|
2
|
-
import time
|
|
3
1
|
import contextlib
|
|
4
|
-
import socket
|
|
5
2
|
import os
|
|
3
|
+
import socket
|
|
6
4
|
import sys
|
|
5
|
+
import threading
|
|
6
|
+
import time
|
|
7
7
|
from contextlib import closing
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import Any, cast
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def find_free_port(start:
|
|
11
|
+
def find_free_port(start: int | None = None, end: int | None = None) -> int:
|
|
12
12
|
port = start
|
|
13
13
|
if port is None:
|
|
14
14
|
port = 0
|
|
@@ -42,7 +42,7 @@ def is_debugpy_installed() -> bool:
|
|
|
42
42
|
return False
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def _get_python_interpreter_path(install_dir:
|
|
45
|
+
def _get_python_interpreter_path(install_dir: str | None) -> str | None:
|
|
46
46
|
"""Get the path to the Python interpreter."""
|
|
47
47
|
if not install_dir:
|
|
48
48
|
return None
|
|
@@ -53,12 +53,12 @@ def _get_python_interpreter_path(install_dir: Optional[str]) -> Optional[str]:
|
|
|
53
53
|
return python_path if os.path.exists(python_path) else None
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
def _get_debugpy_config(python_path: str) ->
|
|
56
|
+
def _get_debugpy_config(python_path: str) -> dict[str, str]:
|
|
57
57
|
"""Get the debugpy configuration."""
|
|
58
58
|
return {"python": python_path}
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
def configure_debugpy(self, python_path:
|
|
61
|
+
def configure_debugpy(self, python_path: str | None = None) -> bool:
|
|
62
62
|
"""Configure debugpy with the appropriate Python interpreter."""
|
|
63
63
|
import debugpy
|
|
64
64
|
|
|
@@ -116,7 +116,7 @@ def debugpython(self, host_object: Any) -> None:
|
|
|
116
116
|
# hack to set __file__ for os module in debugpy
|
|
117
117
|
# This is a workaround for the issue where debugpy cannot find the __file__ attribute of the os module.
|
|
118
118
|
if not hasattr(os, "__file__"):
|
|
119
|
-
|
|
119
|
+
os.__file__ = __file__
|
|
120
120
|
|
|
121
121
|
if host_object is None:
|
|
122
122
|
self.log_alert("No host object found, cannot enable debugpy.")
|
|
@@ -164,7 +164,7 @@ def debugpython(self, host_object: Any) -> None:
|
|
|
164
164
|
def debugpy_in_iris(iris_dir, port) -> bool:
|
|
165
165
|
|
|
166
166
|
if not hasattr(os, "__file__"):
|
|
167
|
-
|
|
167
|
+
os.__file__ = __file__
|
|
168
168
|
|
|
169
169
|
if not is_debugpy_installed():
|
|
170
170
|
print("debugpy is not installed.")
|
|
@@ -195,7 +195,7 @@ def debugpy_in_iris(iris_dir, port) -> bool:
|
|
|
195
195
|
return False
|
|
196
196
|
|
|
197
197
|
|
|
198
|
-
def mgr_dir_to_install_dir(mgr_dir: str) ->
|
|
198
|
+
def mgr_dir_to_install_dir(mgr_dir: str) -> str | None:
|
|
199
199
|
"""Convert manager directory to install directory."""
|
|
200
200
|
import os
|
|
201
201
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any
|
|
2
2
|
|
|
3
|
-
from . import
|
|
4
|
-
from
|
|
3
|
+
from ..messages.dispatch import dispatch_serializer
|
|
4
|
+
from ..runtime import iris as _iris
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class _GeneratorRequest:
|
|
@@ -14,7 +14,7 @@ class _GeneratorRequest:
|
|
|
14
14
|
target: str,
|
|
15
15
|
request: Any,
|
|
16
16
|
timeout: int = -1,
|
|
17
|
-
description:
|
|
17
|
+
description: str | None = None,
|
|
18
18
|
) -> None:
|
|
19
19
|
self.host = host
|
|
20
20
|
self.target = target
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .
|
|
1
|
+
from .common import _Common
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class _InboundAdapter(_Common):
|
|
@@ -8,12 +8,12 @@ class _InboundAdapter(_Common):
|
|
|
8
8
|
|
|
9
9
|
BusinessHost = business_host = business_host_python = None
|
|
10
10
|
|
|
11
|
-
def on_task(self):
|
|
12
|
-
"""Called by the production framework at intervals determined by the business service CallInterval property.
|
|
13
|
-
It is responsible for receiving the data from the external system, validating the data, and sending it in a message to the business service
|
|
14
|
-
The message can have any structure agreed upon by the inbound adapter and the business service.
|
|
15
|
-
"""
|
|
16
|
-
return
|
|
11
|
+
def on_task(self):
|
|
12
|
+
"""Called by the production framework at intervals determined by the business service CallInterval property.
|
|
13
|
+
It is responsible for receiving the data from the external system, validating the data, and sending it in a message to the business service.
|
|
14
|
+
The message can have any structure agreed upon by the inbound adapter and the business service.
|
|
15
|
+
"""
|
|
16
|
+
return None
|
|
17
17
|
|
|
18
18
|
def _set_iris_handles(self, handle_current, handle_partner):
|
|
19
19
|
"""For internal use only."""
|
|
@@ -22,14 +22,6 @@ class _InboundAdapter(_Common):
|
|
|
22
22
|
self.business_host = handle_partner
|
|
23
23
|
try:
|
|
24
24
|
self.business_host_python = handle_partner.GetClass()
|
|
25
|
-
except Exception:
|
|
26
|
-
pass
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
def OnTask(self):
|
|
30
|
-
"""DEPRECATED : use on_task
|
|
31
|
-
Called by the production framework at intervals determined by the business service CallInterval property.
|
|
32
|
-
It is responsible for receiving the data from the external system, validating the data, and sending it in a message to the business service OnProcessInput method.
|
|
33
|
-
The message can have any structure agreed upon by the inbound adapter and the business service.
|
|
34
|
-
"""
|
|
35
|
-
return
|
|
25
|
+
except Exception:
|
|
26
|
+
pass
|
|
27
|
+
return
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class _PollingBusinessServiceMixin:
|
|
5
|
+
"""Mixin for services polled by the default IRIS inbound adapter."""
|
|
6
|
+
|
|
7
|
+
@staticmethod
|
|
8
|
+
def get_adapter_type() -> str:
|
|
9
|
+
return "Ens.InboundAdapter"
|
|
10
|
+
|
|
11
|
+
def on_poll(self):
|
|
12
|
+
"""Purpose:
|
|
13
|
+
Run one scheduled polling cycle.
|
|
14
|
+
|
|
15
|
+
Use when:
|
|
16
|
+
A PollingBusinessService fetches or discovers new work from Python.
|
|
17
|
+
|
|
18
|
+
Lifecycle:
|
|
19
|
+
The default IRIS inbound adapter calls on_process_input(), and this
|
|
20
|
+
mixin delegates that call to on_poll().
|
|
21
|
+
|
|
22
|
+
Best practices:
|
|
23
|
+
Do a bounded unit of work, then return. Send produced messages with
|
|
24
|
+
send_request_async(self.Output, message).
|
|
25
|
+
|
|
26
|
+
Common mistakes:
|
|
27
|
+
Do not create an infinite loop inside on_poll(); use the production
|
|
28
|
+
schedule or call interval for repeated execution.
|
|
29
|
+
|
|
30
|
+
Minimal example:
|
|
31
|
+
def on_poll(self):
|
|
32
|
+
self.send_request_async(self.Output, PollRequest())
|
|
33
|
+
|
|
34
|
+
Related:
|
|
35
|
+
docs/cookbooks/add-polling-service.md
|
|
36
|
+
"""
|
|
37
|
+
warnings.warn(
|
|
38
|
+
f"{self.__class__.__name__} did not override on_poll() or "
|
|
39
|
+
"on_process_input(); the scheduled poll was ignored. "
|
|
40
|
+
"This default no-op handler will raise NotImplementedError in v5.0.",
|
|
41
|
+
RuntimeWarning,
|
|
42
|
+
stacklevel=2,
|
|
43
|
+
)
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
def on_process_input(self, message_input=None):
|
|
47
|
+
"""Compatibility hook called by IRIS ProcessInput."""
|
|
48
|
+
return self.on_poll()
|