iris-pex-embedded-python 3.2.1b3__py3-none-any.whl → 3.3.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iris-pex-embedded-python might be problematic. Click here for more details.
- iop/_async_request.py +62 -0
- iop/_business_host.py +16 -451
- iop/_business_operation.py +6 -4
- iop/_business_process.py +12 -10
- iop/_business_service.py +3 -2
- iop/_common.py +12 -75
- iop/_decorators.py +48 -0
- iop/_director.py +3 -2
- iop/_dispatch.py +219 -0
- iop/_log_manager.py +20 -12
- iop/_message_validator.py +41 -0
- iop/_private_session_duplex.py +11 -10
- iop/_private_session_process.py +7 -7
- iop/_serialization.py +196 -0
- iop/_utils.py +27 -19
- {iris_pex_embedded_python-3.2.1b3.dist-info → iris_pex_embedded_python-3.3.0b2.dist-info}/METADATA +1 -1
- {iris_pex_embedded_python-3.2.1b3.dist-info → iris_pex_embedded_python-3.3.0b2.dist-info}/RECORD +21 -16
- {iris_pex_embedded_python-3.2.1b3.dist-info → iris_pex_embedded_python-3.3.0b2.dist-info}/LICENSE +0 -0
- {iris_pex_embedded_python-3.2.1b3.dist-info → iris_pex_embedded_python-3.3.0b2.dist-info}/WHEEL +0 -0
- {iris_pex_embedded_python-3.2.1b3.dist-info → iris_pex_embedded_python-3.3.0b2.dist-info}/entry_points.txt +0 -0
- {iris_pex_embedded_python-3.2.1b3.dist-info → iris_pex_embedded_python-3.3.0b2.dist-info}/top_level.txt +0 -0
iop/_common.py
CHANGED
|
@@ -7,6 +7,8 @@ from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type
|
|
|
7
7
|
from iop._log_manager import LogManager
|
|
8
8
|
import logging
|
|
9
9
|
|
|
10
|
+
from iop._message_validator import is_iris_object_instance, is_message_instance, is_pickle_message_instance
|
|
11
|
+
|
|
10
12
|
class _Common(metaclass=abc.ABCMeta):
|
|
11
13
|
"""Base class that defines common methods for all component types.
|
|
12
14
|
|
|
@@ -19,100 +21,34 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
19
21
|
iris_handle: Any = None
|
|
20
22
|
log_to_console: bool = False
|
|
21
23
|
|
|
24
|
+
# Lifecycle methods
|
|
22
25
|
def on_init(self) -> None:
|
|
23
|
-
"""Initialize component when started.
|
|
24
|
-
|
|
25
|
-
Called when component starts. Use to initialize required structures.
|
|
26
|
-
"""
|
|
27
|
-
return self.OnInit()
|
|
26
|
+
"""Initialize component when started."""
|
|
27
|
+
pass
|
|
28
28
|
|
|
29
29
|
def on_tear_down(self) -> None:
|
|
30
|
-
"""Clean up component before termination.
|
|
31
|
-
|
|
32
|
-
Called before component terminates. Use to free resources.
|
|
33
|
-
"""
|
|
34
|
-
return self.OnTearDown()
|
|
30
|
+
"""Clean up component before termination."""
|
|
31
|
+
pass
|
|
35
32
|
|
|
36
33
|
def on_connected(self) -> None:
|
|
37
|
-
"""Handle component connection/reconnection.
|
|
38
|
-
|
|
39
|
-
Called when component connects or reconnects after disconnection.
|
|
40
|
-
Use to initialize connection-dependent structures.
|
|
41
|
-
"""
|
|
42
|
-
return self.OnConnected()
|
|
34
|
+
"""Handle component connection/reconnection."""
|
|
35
|
+
pass
|
|
43
36
|
|
|
37
|
+
# Internal dispatch methods
|
|
44
38
|
def _dispatch_on_connected(self, host_object: Any) -> None:
|
|
45
|
-
"""Internal dispatch for connection handling."""
|
|
46
39
|
self.on_connected()
|
|
47
|
-
return
|
|
48
40
|
|
|
49
41
|
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
50
|
-
"""Internal dispatch for initialization."""
|
|
51
42
|
self.on_init()
|
|
52
|
-
return
|
|
53
43
|
|
|
54
44
|
def _dispatch_on_tear_down(self, host_object: Any) -> None:
|
|
55
|
-
"""Internal dispatch for teardown."""
|
|
56
45
|
self.on_tear_down()
|
|
57
|
-
return
|
|
58
46
|
|
|
59
47
|
def _set_iris_handles(self, handle_current: Any, handle_partner: Any) -> None:
|
|
60
48
|
"""Internal method to set IRIS handles."""
|
|
61
49
|
pass
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
def _is_message_instance(cls, obj: Any) -> bool:
|
|
65
|
-
"""Check if object is a valid Message instance.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
obj: Object to check
|
|
69
|
-
|
|
70
|
-
Returns:
|
|
71
|
-
True if object is a Message instance
|
|
72
|
-
|
|
73
|
-
Raises:
|
|
74
|
-
TypeError: If object is Message class but not a dataclass
|
|
75
|
-
"""
|
|
76
|
-
if cls._is_message_class(type(obj)):
|
|
77
|
-
if not dataclasses.is_dataclass(obj):
|
|
78
|
-
raise TypeError(f"{type(obj).__module__}.{type(obj).__qualname__} must be a dataclass")
|
|
79
|
-
return True
|
|
80
|
-
return False
|
|
81
|
-
|
|
82
|
-
@classmethod
|
|
83
|
-
def _is_pickle_message_instance(cls, obj: Any) -> bool:
|
|
84
|
-
"""Check if object is a PickleMessage instance."""
|
|
85
|
-
if cls._is_pickel_message_class(type(obj)):
|
|
86
|
-
return True
|
|
87
|
-
return False
|
|
88
|
-
|
|
89
|
-
@classmethod
|
|
90
|
-
def _is_iris_object_instance(cls, obj: Any) -> bool:
|
|
91
|
-
"""Check if object is an IRIS persistent object."""
|
|
92
|
-
if (obj is not None and type(obj).__module__.find('iris') == 0) and obj._IsA("%Persistent"):
|
|
93
|
-
return True
|
|
94
|
-
return False
|
|
95
|
-
|
|
96
|
-
@classmethod
|
|
97
|
-
def _is_message_class(cls, klass: Type) -> bool:
|
|
98
|
-
name = klass.__module__ + '.' + klass.__qualname__
|
|
99
|
-
if name == "iop.Message" or name == "grongier.pex.Message":
|
|
100
|
-
return True
|
|
101
|
-
for c in klass.__bases__:
|
|
102
|
-
if cls._is_message_class(c):
|
|
103
|
-
return True
|
|
104
|
-
return False
|
|
105
|
-
|
|
106
|
-
@classmethod
|
|
107
|
-
def _is_pickel_message_class(cls, klass: Type) -> bool:
|
|
108
|
-
name = klass.__module__ + '.' + klass.__qualname__
|
|
109
|
-
if name == "iop.PickleMessage" or name == "grongier.pex.PickleMessage":
|
|
110
|
-
return True
|
|
111
|
-
for c in klass.__bases__:
|
|
112
|
-
if cls._is_pickel_message_class(c):
|
|
113
|
-
return True
|
|
114
|
-
return False
|
|
115
|
-
|
|
51
|
+
# Component information methods
|
|
116
52
|
@classmethod
|
|
117
53
|
def _get_info(cls) -> List[str]:
|
|
118
54
|
"""Get component configuration information.
|
|
@@ -239,6 +175,7 @@ class _Common(metaclass=abc.ABCMeta):
|
|
|
239
175
|
pass
|
|
240
176
|
return ret
|
|
241
177
|
|
|
178
|
+
# Logging methods
|
|
242
179
|
def _log(self) -> Tuple[str, Optional[str]]:
|
|
243
180
|
"""Get class and method name for logging.
|
|
244
181
|
|
iop/_decorators.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
from typing import Any, Callable
|
|
3
|
+
from iop._dispatch import dispatch_deserializer, dispatch_serializer
|
|
4
|
+
|
|
5
|
+
def input_serializer(fonction: Callable) -> Callable:
|
|
6
|
+
"""Decorator that serializes all input arguments."""
|
|
7
|
+
def _dispatch_serializer(self, *params: Any, **param2: Any) -> Any:
|
|
8
|
+
serialized = [dispatch_serializer(param) for param in params]
|
|
9
|
+
param2 = {key: dispatch_serializer(value) for key, value in param2.items()}
|
|
10
|
+
return fonction(self, *serialized, **param2)
|
|
11
|
+
return _dispatch_serializer
|
|
12
|
+
|
|
13
|
+
def input_serializer_param(position: int, name: str) -> Callable:
|
|
14
|
+
"""Decorator that serializes specific parameter by position or name."""
|
|
15
|
+
def _input_serializer_param(fonction: Callable) -> Callable:
|
|
16
|
+
@wraps(fonction)
|
|
17
|
+
def _dispatch_serializer(self, *params: Any, **param2: Any) -> Any:
|
|
18
|
+
serialized = [
|
|
19
|
+
dispatch_serializer(param) if i == position else param
|
|
20
|
+
for i, param in enumerate(params)
|
|
21
|
+
]
|
|
22
|
+
param2 = {
|
|
23
|
+
key: dispatch_serializer(value) if key == name else value
|
|
24
|
+
for key, value in param2.items()
|
|
25
|
+
}
|
|
26
|
+
return fonction(self, *serialized, **param2)
|
|
27
|
+
return _dispatch_serializer
|
|
28
|
+
return _input_serializer_param
|
|
29
|
+
|
|
30
|
+
def output_deserializer(fonction: Callable) -> Callable:
|
|
31
|
+
"""Decorator that deserializes function output."""
|
|
32
|
+
def _dispatch_deserializer(self, *params: Any, **param2: Any) -> Any:
|
|
33
|
+
return dispatch_deserializer(fonction(self, *params, **param2))
|
|
34
|
+
return _dispatch_deserializer
|
|
35
|
+
|
|
36
|
+
def input_deserializer(fonction: Callable) -> Callable:
|
|
37
|
+
"""Decorator that deserializes all input arguments."""
|
|
38
|
+
def _dispatch_deserializer(self, *params: Any, **param2: Any) -> Any:
|
|
39
|
+
serialized = [dispatch_deserializer(param) for param in params]
|
|
40
|
+
param2 = {key: dispatch_deserializer(value) for key, value in param2.items()}
|
|
41
|
+
return fonction(self, *serialized, **param2)
|
|
42
|
+
return _dispatch_deserializer
|
|
43
|
+
|
|
44
|
+
def output_serializer(fonction: Callable) -> Callable:
|
|
45
|
+
"""Decorator that serializes function output."""
|
|
46
|
+
def _dispatch_serializer(self, *params: Any, **param2: Any) -> Any:
|
|
47
|
+
return dispatch_serializer(fonction(self, *params, **param2))
|
|
48
|
+
return _dispatch_serializer
|
iop/_director.py
CHANGED
|
@@ -7,6 +7,7 @@ import signal
|
|
|
7
7
|
from dataclasses import dataclass
|
|
8
8
|
|
|
9
9
|
from iop._business_host import _BusinessHost
|
|
10
|
+
from iop._dispatch import dispatch_deserializer, dispatch_serializer
|
|
10
11
|
from iop._utils import _Utils
|
|
11
12
|
|
|
12
13
|
class _Director():
|
|
@@ -278,10 +279,10 @@ class _Director():
|
|
|
278
279
|
message.json = _Utils.string_to_stream("{}")
|
|
279
280
|
# serialize the message
|
|
280
281
|
business_host = _BusinessHost()
|
|
281
|
-
serial_message =
|
|
282
|
+
serial_message = dispatch_serializer(message)
|
|
282
283
|
response = iris.cls('IOP.Utils').dispatchTestComponent(target,serial_message)
|
|
283
284
|
try:
|
|
284
|
-
deserialized_response =
|
|
285
|
+
deserialized_response = dispatch_deserializer(response)
|
|
285
286
|
except ImportError as e:
|
|
286
287
|
# can't import the class, return the string
|
|
287
288
|
deserialized_response = f'{response.classname} : {_Utils.stream_to_string(response.jstr)}'
|
iop/_dispatch.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import codecs
|
|
2
|
+
import importlib
|
|
3
|
+
from inspect import signature
|
|
4
|
+
import json
|
|
5
|
+
import pickle
|
|
6
|
+
from typing import Any, Dict, List, Type
|
|
7
|
+
|
|
8
|
+
import iris
|
|
9
|
+
from dacite import Config, from_dict
|
|
10
|
+
|
|
11
|
+
from iop._utils import _Utils
|
|
12
|
+
from iop._serialization import IrisJSONEncoder, IrisJSONDecoder
|
|
13
|
+
from iop._message_validator import is_message_instance, is_pickle_message_instance, is_iris_object_instance
|
|
14
|
+
|
|
15
|
+
def serialize_pickle_message(message: Any) -> iris.cls:
|
|
16
|
+
"""Converts a python dataclass message into an iris iop.message.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
message: The message to serialize, an instance of a class that is a subclass of Message.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
The message in json format.
|
|
23
|
+
"""
|
|
24
|
+
pickle_string = codecs.encode(pickle.dumps(message), "base64").decode()
|
|
25
|
+
module = message.__class__.__module__
|
|
26
|
+
classname = message.__class__.__name__
|
|
27
|
+
|
|
28
|
+
msg = iris.cls('IOP.PickleMessage')._New()
|
|
29
|
+
msg.classname = module + "." + classname
|
|
30
|
+
|
|
31
|
+
stream = _Utils.string_to_stream(pickle_string)
|
|
32
|
+
msg.jstr = stream
|
|
33
|
+
|
|
34
|
+
return msg
|
|
35
|
+
|
|
36
|
+
def dispatch_serializer(message: Any) -> Any:
|
|
37
|
+
"""Serializes the message based on its type.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
message: The message to serialize
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The serialized message
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
TypeError: If message is invalid type
|
|
47
|
+
"""
|
|
48
|
+
if message is not None:
|
|
49
|
+
if is_message_instance(message):
|
|
50
|
+
return serialize_message(message)
|
|
51
|
+
elif is_pickle_message_instance(message):
|
|
52
|
+
return serialize_pickle_message(message)
|
|
53
|
+
elif is_iris_object_instance(message):
|
|
54
|
+
return message
|
|
55
|
+
|
|
56
|
+
if message == "" or message is None:
|
|
57
|
+
return message
|
|
58
|
+
|
|
59
|
+
raise TypeError("The message must be an instance of a class that is a subclass of Message or IRISObject %Persistent class.")
|
|
60
|
+
|
|
61
|
+
def serialize_message(message: Any) -> iris.cls:
|
|
62
|
+
"""Converts a python dataclass message into an iris iop.message.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
message: The message to serialize, an instance of a class that is a subclass of Message.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
The message in json format.
|
|
69
|
+
"""
|
|
70
|
+
json_string = json.dumps(message, cls=IrisJSONEncoder, ensure_ascii=False)
|
|
71
|
+
module = message.__class__.__module__
|
|
72
|
+
classname = message.__class__.__name__
|
|
73
|
+
|
|
74
|
+
msg = iris.cls('IOP.Message')._New()
|
|
75
|
+
msg.classname = module + "." + classname
|
|
76
|
+
|
|
77
|
+
if hasattr(msg, 'buffer') and len(json_string) > msg.buffer:
|
|
78
|
+
msg.json = _Utils.string_to_stream(json_string, msg.buffer)
|
|
79
|
+
else:
|
|
80
|
+
msg.json = json_string
|
|
81
|
+
|
|
82
|
+
return msg
|
|
83
|
+
|
|
84
|
+
def deserialize_pickle_message(serial: iris.cls) -> Any:
|
|
85
|
+
"""Converts an iris iop.message into a python dataclass message.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
serial: The serialized message
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
The deserialized message
|
|
92
|
+
"""
|
|
93
|
+
string = _Utils.stream_to_string(serial.jstr)
|
|
94
|
+
msg = pickle.loads(codecs.decode(string.encode(), "base64"))
|
|
95
|
+
return msg
|
|
96
|
+
|
|
97
|
+
def dispatch_deserializer(serial: Any) -> Any:
|
|
98
|
+
"""Deserializes the message based on its type.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
serial: The serialized message
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
The deserialized message
|
|
105
|
+
"""
|
|
106
|
+
if (
|
|
107
|
+
serial is not None
|
|
108
|
+
and type(serial).__module__.startswith('iris')
|
|
109
|
+
and (
|
|
110
|
+
serial._IsA("IOP.Message")
|
|
111
|
+
or serial._IsA("Grongier.PEX.Message")
|
|
112
|
+
)
|
|
113
|
+
):
|
|
114
|
+
return deserialize_message(serial)
|
|
115
|
+
elif (
|
|
116
|
+
serial is not None
|
|
117
|
+
and type(serial).__module__.startswith('iris')
|
|
118
|
+
and (
|
|
119
|
+
serial._IsA("IOP.PickleMessage")
|
|
120
|
+
or serial._IsA("Grongier.PEX.PickleMessage")
|
|
121
|
+
)
|
|
122
|
+
):
|
|
123
|
+
return deserialize_pickle_message(serial)
|
|
124
|
+
else:
|
|
125
|
+
return serial
|
|
126
|
+
|
|
127
|
+
def deserialize_message(serial: iris.cls) -> Any:
|
|
128
|
+
"""Converts an iris iop.message into a python dataclass message.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
serial: The serialized message
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
The deserialized message
|
|
135
|
+
"""
|
|
136
|
+
if (serial.classname is None):
|
|
137
|
+
raise ValueError("JSON message malformed, must include classname")
|
|
138
|
+
classname = serial.classname
|
|
139
|
+
|
|
140
|
+
j = classname.rindex(".")
|
|
141
|
+
if (j <= 0):
|
|
142
|
+
raise ValueError("Classname must include a module: " + classname)
|
|
143
|
+
try:
|
|
144
|
+
module = importlib.import_module(classname[:j])
|
|
145
|
+
msg = getattr(module, classname[j+1:])
|
|
146
|
+
except Exception:
|
|
147
|
+
raise ImportError("Class not found: " + classname)
|
|
148
|
+
|
|
149
|
+
string = ""
|
|
150
|
+
if (serial.type == 'Stream'):
|
|
151
|
+
string = _Utils.stream_to_string(serial.json)
|
|
152
|
+
else:
|
|
153
|
+
string = serial.json
|
|
154
|
+
|
|
155
|
+
jdict = json.loads(string, cls=IrisJSONDecoder)
|
|
156
|
+
return dataclass_from_dict(msg, jdict)
|
|
157
|
+
|
|
158
|
+
def dataclass_from_dict(klass: Type, dikt: Dict) -> Any:
|
|
159
|
+
"""Converts a dictionary to a dataclass instance.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
klass: The dataclass to convert to
|
|
163
|
+
dikt: The dictionary to convert to a dataclass
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
A dataclass object with the fields of the dataclass and the fields of the dictionary.
|
|
167
|
+
"""
|
|
168
|
+
ret = from_dict(klass, dikt, Config(check_types=False))
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
fieldtypes = klass.__annotations__
|
|
172
|
+
except Exception as e:
|
|
173
|
+
fieldtypes = []
|
|
174
|
+
|
|
175
|
+
for key, val in dikt.items():
|
|
176
|
+
if key not in fieldtypes:
|
|
177
|
+
setattr(ret, key, val)
|
|
178
|
+
return ret
|
|
179
|
+
|
|
180
|
+
def dispach_message(host, request: Any) -> Any:
|
|
181
|
+
"""Dispatches the message to the appropriate method.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
request: The request object
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
The response object
|
|
188
|
+
"""
|
|
189
|
+
call = 'on_message'
|
|
190
|
+
|
|
191
|
+
module = request.__class__.__module__
|
|
192
|
+
classname = request.__class__.__name__
|
|
193
|
+
|
|
194
|
+
for msg, method in host.DISPATCH:
|
|
195
|
+
if msg == module + "." + classname:
|
|
196
|
+
call = method
|
|
197
|
+
|
|
198
|
+
return getattr(host, call)(request)
|
|
199
|
+
|
|
200
|
+
def create_dispatch(host) -> None:
|
|
201
|
+
"""Creates a list of tuples, where each tuple contains the name of a class and the name of a method
|
|
202
|
+
that takes an instance of that class as its only argument.
|
|
203
|
+
"""
|
|
204
|
+
if len(host.DISPATCH) == 0:
|
|
205
|
+
method_list = [func for func in dir(host) if callable(getattr(host, func)) and not func.startswith("_")]
|
|
206
|
+
for method in method_list:
|
|
207
|
+
try:
|
|
208
|
+
param = signature(getattr(host, method)).parameters
|
|
209
|
+
except ValueError as e:
|
|
210
|
+
param = ''
|
|
211
|
+
if (len(param) == 1):
|
|
212
|
+
annotation = str(param[list(param)[0]].annotation)
|
|
213
|
+
i = annotation.find("'")
|
|
214
|
+
j = annotation.rfind("'")
|
|
215
|
+
if j == -1:
|
|
216
|
+
j = None
|
|
217
|
+
classname = annotation[i+1:j]
|
|
218
|
+
host.DISPATCH.append((classname, method))
|
|
219
|
+
return
|
iop/_log_manager.py
CHANGED
|
@@ -46,6 +46,23 @@ class IRISLogHandler(logging.Handler):
|
|
|
46
46
|
self.method_name = method_name
|
|
47
47
|
self.to_console = to_console
|
|
48
48
|
|
|
49
|
+
# Map Python logging levels to IRIS logging methods
|
|
50
|
+
self.level_map = {
|
|
51
|
+
logging.DEBUG: iris.cls("Ens.Util.Log").LogTrace,
|
|
52
|
+
logging.INFO: iris.cls("Ens.Util.Log").LogInfo,
|
|
53
|
+
logging.WARNING: iris.cls("Ens.Util.Log").LogWarning,
|
|
54
|
+
logging.ERROR: iris.cls("Ens.Util.Log").LogError,
|
|
55
|
+
logging.CRITICAL: iris.cls("Ens.Util.Log").LogAlert,
|
|
56
|
+
}
|
|
57
|
+
# Map Python logging levels to IRIS logging Console level
|
|
58
|
+
self.level_map_console = {
|
|
59
|
+
logging.DEBUG: -1,
|
|
60
|
+
logging.INFO: 0,
|
|
61
|
+
logging.WARNING: 1,
|
|
62
|
+
logging.ERROR: 2,
|
|
63
|
+
logging.CRITICAL: 3,
|
|
64
|
+
}
|
|
65
|
+
|
|
49
66
|
def format(self, record: logging.LogRecord) -> str:
|
|
50
67
|
"""Format the log record into a string.
|
|
51
68
|
|
|
@@ -55,8 +72,6 @@ class IRISLogHandler(logging.Handler):
|
|
|
55
72
|
Returns:
|
|
56
73
|
Formatted log message
|
|
57
74
|
"""
|
|
58
|
-
if self.to_console:
|
|
59
|
-
return f"{record}"
|
|
60
75
|
return record.getMessage()
|
|
61
76
|
|
|
62
77
|
def emit(self, record: logging.LogRecord) -> None:
|
|
@@ -65,17 +80,10 @@ class IRISLogHandler(logging.Handler):
|
|
|
65
80
|
Args:
|
|
66
81
|
record: The logging record to emit
|
|
67
82
|
"""
|
|
68
|
-
# Map Python logging levels to IRIS logging methods
|
|
69
|
-
level_map = {
|
|
70
|
-
logging.DEBUG: iris.cls("Ens.Util.Log").LogTrace,
|
|
71
|
-
logging.INFO: iris.cls("Ens.Util.Log").LogInfo,
|
|
72
|
-
logging.WARNING: iris.cls("Ens.Util.Log").LogWarning,
|
|
73
|
-
logging.ERROR: iris.cls("Ens.Util.Log").LogError,
|
|
74
|
-
logging.CRITICAL: iris.cls("Ens.Util.Log").LogAlert,
|
|
75
|
-
}
|
|
76
83
|
|
|
77
|
-
log_func = level_map.get(record.levelno, iris.cls("Ens.Util.Log").LogInfo)
|
|
84
|
+
log_func = self.level_map.get(record.levelno, iris.cls("Ens.Util.Log").LogInfo)
|
|
78
85
|
if self.to_console or (hasattr(record, "to_console") and record.to_console):
|
|
79
|
-
iris.cls("%SYS.System").WriteToConsoleLog(self.format(record),
|
|
86
|
+
iris.cls("%SYS.System").WriteToConsoleLog(self.format(record),
|
|
87
|
+
0,self.level_map_console.get(record.levelno, 0),record.name)
|
|
80
88
|
else:
|
|
81
89
|
log_func(self.class_name, self.method_name, self.format(record))
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from typing import Any, Type
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def is_message_instance(obj: Any) -> bool:
|
|
6
|
+
"""Check if object is a valid Message instance."""
|
|
7
|
+
if is_message_class(type(obj)):
|
|
8
|
+
if not dataclasses.is_dataclass(obj):
|
|
9
|
+
raise TypeError(f"{type(obj).__module__}.{type(obj).__qualname__} must be a dataclass")
|
|
10
|
+
return True
|
|
11
|
+
return False
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def is_pickle_message_instance(obj: Any) -> bool:
|
|
15
|
+
"""Check if object is a PickleMessage instance."""
|
|
16
|
+
if is_pickle_message_class(type(obj)):
|
|
17
|
+
return True
|
|
18
|
+
return False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_iris_object_instance(obj: Any) -> bool:
|
|
22
|
+
"""Check if object is an IRIS persistent object."""
|
|
23
|
+
return (obj is not None and
|
|
24
|
+
type(obj).__module__.startswith('iris') and
|
|
25
|
+
obj._IsA("%Persistent"))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def is_message_class(klass: Type) -> bool:
|
|
29
|
+
"""Check if class is a Message type."""
|
|
30
|
+
name = f"{klass.__module__}.{klass.__qualname__}"
|
|
31
|
+
if name in ("iop.Message", "grongier.pex.Message"):
|
|
32
|
+
return True
|
|
33
|
+
return any(is_message_class(c) for c in klass.__bases__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def is_pickle_message_class(klass: Type) -> bool:
|
|
37
|
+
"""Check if class is a PickleMessage type."""
|
|
38
|
+
name = f"{klass.__module__}.{klass.__qualname__}"
|
|
39
|
+
if name in ("iop.PickleMessage", "grongier.pex.PickleMessage"):
|
|
40
|
+
return True
|
|
41
|
+
return any(is_pickle_message_class(c) for c in klass.__bases__)
|
iop/_private_session_duplex.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
from iop._business_host import _BusinessHost
|
|
3
|
+
from iop._decorators import input_deserializer, input_serializer_param, output_serializer, input_serializer, output_deserializer
|
|
3
4
|
|
|
4
5
|
class _PrivateSessionDuplex(_BusinessHost):
|
|
5
6
|
|
|
@@ -21,8 +22,8 @@ class _PrivateSessionDuplex(_BusinessHost):
|
|
|
21
22
|
"""
|
|
22
23
|
pass
|
|
23
24
|
|
|
24
|
-
@
|
|
25
|
-
@
|
|
25
|
+
@input_deserializer
|
|
26
|
+
@output_serializer
|
|
26
27
|
def _dispatch_on_message(self, request):
|
|
27
28
|
""" For internal use only. """
|
|
28
29
|
return self._dispach_message(request)
|
|
@@ -38,8 +39,8 @@ class _PrivateSessionDuplex(_BusinessHost):
|
|
|
38
39
|
self.Adapter = self.adapter = handle_partner
|
|
39
40
|
return
|
|
40
41
|
|
|
41
|
-
@
|
|
42
|
-
@
|
|
42
|
+
@input_deserializer
|
|
43
|
+
@output_serializer
|
|
43
44
|
def _dispatch_on_process_input(self, request):
|
|
44
45
|
""" For internal use only. """
|
|
45
46
|
return self.on_process_input(request)
|
|
@@ -55,8 +56,8 @@ class _PrivateSessionDuplex(_BusinessHost):
|
|
|
55
56
|
"""
|
|
56
57
|
return
|
|
57
58
|
|
|
58
|
-
@
|
|
59
|
-
@
|
|
59
|
+
@input_serializer_param(0,'document')
|
|
60
|
+
@output_deserializer
|
|
60
61
|
def send_document_to_process(self, document):
|
|
61
62
|
""" Send the specified message to the target business process or business operation synchronously.
|
|
62
63
|
|
|
@@ -75,8 +76,8 @@ class _PrivateSessionDuplex(_BusinessHost):
|
|
|
75
76
|
|
|
76
77
|
return self.iris_handle.dispatchSendDocumentToProcess(document)
|
|
77
78
|
|
|
78
|
-
@
|
|
79
|
-
@
|
|
79
|
+
@input_deserializer
|
|
80
|
+
@output_serializer
|
|
80
81
|
def _dispatch_on_private_session_started(self, source_config_name,self_generated):
|
|
81
82
|
""" For internal use only. """
|
|
82
83
|
|
|
@@ -87,8 +88,8 @@ class _PrivateSessionDuplex(_BusinessHost):
|
|
|
87
88
|
def on_private_session_started(self,source_config_name,self_generated):
|
|
88
89
|
pass
|
|
89
90
|
|
|
90
|
-
@
|
|
91
|
-
@
|
|
91
|
+
@input_deserializer
|
|
92
|
+
@output_serializer
|
|
92
93
|
def _dispatch_on_private_session_stopped(self, source_config_name,self_generated,message):
|
|
93
94
|
""" For internal use only. """
|
|
94
95
|
|
iop/_private_session_process.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from iop._business_process import _BusinessProcess
|
|
2
|
-
from iop.
|
|
2
|
+
from iop._decorators import input_deserializer, output_serializer, input_serializer, output_deserializer
|
|
3
3
|
|
|
4
4
|
class _PrivateSessionProcess(_BusinessProcess):
|
|
5
5
|
|
|
6
|
-
@
|
|
7
|
-
@
|
|
6
|
+
@input_deserializer
|
|
7
|
+
@output_serializer
|
|
8
8
|
def _dispatch_on_document(self, host_object,source_config_name, request):
|
|
9
9
|
""" For internal use only. """
|
|
10
10
|
self._restore_persistent_properties(host_object)
|
|
@@ -16,8 +16,8 @@ class _PrivateSessionProcess(_BusinessProcess):
|
|
|
16
16
|
pass
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
@
|
|
20
|
-
@
|
|
19
|
+
@input_deserializer
|
|
20
|
+
@output_serializer
|
|
21
21
|
def _dispatch_on_private_session_started(self, host_object, source_config_name,self_generated):
|
|
22
22
|
""" For internal use only. """
|
|
23
23
|
self._restore_persistent_properties(host_object)
|
|
@@ -28,8 +28,8 @@ class _PrivateSessionProcess(_BusinessProcess):
|
|
|
28
28
|
def on_private_session_started(self,source_config_name,self_generated):
|
|
29
29
|
pass
|
|
30
30
|
|
|
31
|
-
@
|
|
32
|
-
@
|
|
31
|
+
@input_deserializer
|
|
32
|
+
@output_serializer
|
|
33
33
|
def _dispatch_on_private_session_stopped(self, host_object, source_config_name,self_generated,message):
|
|
34
34
|
""" For internal use only. """
|
|
35
35
|
self._restore_persistent_properties(host_object)
|