iris-pex-embedded-python 3.5.5b4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- grongier/__init__.py +0 -0
- grongier/cls/Grongier/PEX/BusinessOperation.cls +8 -0
- grongier/cls/Grongier/PEX/BusinessProcess.cls +13 -0
- grongier/cls/Grongier/PEX/BusinessService.cls +8 -0
- grongier/cls/Grongier/PEX/Common.cls +10 -0
- grongier/cls/Grongier/PEX/Director.cls +10 -0
- grongier/cls/Grongier/PEX/Duplex/Operation.cls +4 -0
- grongier/cls/Grongier/PEX/Duplex/Process.cls +13 -0
- grongier/cls/Grongier/PEX/Duplex/Service.cls +4 -0
- grongier/cls/Grongier/PEX/InboundAdapter.cls +8 -0
- grongier/cls/Grongier/PEX/Message.cls +13 -0
- grongier/cls/Grongier/PEX/OutboundAdapter.cls +8 -0
- grongier/cls/Grongier/PEX/PickleMessage.cls +13 -0
- grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +8 -0
- grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +14 -0
- grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +14 -0
- grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +14 -0
- grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +14 -0
- grongier/cls/Grongier/PEX/Test.cls +10 -0
- grongier/cls/Grongier/PEX/Utils.cls +10 -0
- grongier/cls/Grongier/Service/WSGI.cls +4 -0
- grongier/pex/__init__.py +24 -0
- grongier/pex/__main__.py +4 -0
- grongier/pex/_business_host.py +1 -0
- grongier/pex/_cli.py +4 -0
- grongier/pex/_common.py +1 -0
- grongier/pex/_director.py +1 -0
- grongier/pex/_utils.py +1 -0
- grongier/pex/wsgi/handlers.py +104 -0
- iop/__init__.py +25 -0
- iop/__main__.py +4 -0
- iop/_async_request.py +67 -0
- iop/_business_host.py +256 -0
- iop/_business_operation.py +75 -0
- iop/_business_process.py +224 -0
- iop/_business_service.py +63 -0
- iop/_cli.py +247 -0
- iop/_common.py +334 -0
- iop/_debugpy.py +187 -0
- iop/_decorators.py +49 -0
- iop/_director.py +301 -0
- iop/_dispatch.py +136 -0
- iop/_generator_request.py +30 -0
- iop/_inbound_adapter.py +34 -0
- iop/_iris.py +8 -0
- iop/_log_manager.py +100 -0
- iop/_message.py +40 -0
- iop/_message_validator.py +49 -0
- iop/_outbound_adapter.py +23 -0
- iop/_private_session_duplex.py +103 -0
- iop/_private_session_process.py +41 -0
- iop/_remote.py +91 -0
- iop/_serialization.py +199 -0
- iop/_utils.py +671 -0
- iop/cls/IOP/BusinessOperation.cls +35 -0
- iop/cls/IOP/BusinessProcess.cls +156 -0
- iop/cls/IOP/BusinessService.cls +40 -0
- iop/cls/IOP/Common.cls +569 -0
- iop/cls/IOP/Director.cls +70 -0
- iop/cls/IOP/Duplex/Operation.cls +29 -0
- iop/cls/IOP/Duplex/Process.cls +229 -0
- iop/cls/IOP/Duplex/Service.cls +9 -0
- iop/cls/IOP/Generator/Message/Ack.cls +31 -0
- iop/cls/IOP/Generator/Message/Poll.cls +31 -0
- iop/cls/IOP/Generator/Message/Start.cls +15 -0
- iop/cls/IOP/Generator/Message/StartPickle.cls +15 -0
- iop/cls/IOP/Generator/Message/Stop.cls +32 -0
- iop/cls/IOP/InboundAdapter.cls +22 -0
- iop/cls/IOP/Message/JSONSchema.cls +125 -0
- iop/cls/IOP/Message.cls +754 -0
- iop/cls/IOP/OutboundAdapter.cls +36 -0
- iop/cls/IOP/PickleMessage.cls +58 -0
- iop/cls/IOP/PrivateSession/Duplex.cls +260 -0
- iop/cls/IOP/PrivateSession/Message/Ack.cls +32 -0
- iop/cls/IOP/PrivateSession/Message/Poll.cls +32 -0
- iop/cls/IOP/PrivateSession/Message/Start.cls +31 -0
- iop/cls/IOP/PrivateSession/Message/Stop.cls +48 -0
- iop/cls/IOP/Projection.cls +49 -0
- iop/cls/IOP/Service/Remote/Handler.cls +30 -0
- iop/cls/IOP/Service/Remote/Rest/v1.cls +97 -0
- iop/cls/IOP/Service/WSGI.cls +310 -0
- iop/cls/IOP/Test.cls +85 -0
- iop/cls/IOP/Utils.cls +503 -0
- iop/cls/IOP/Wrapper.cls +58 -0
- iop/wsgi/handlers.py +104 -0
- iris_pex_embedded_python-3.5.5b4.dist-info/METADATA +91 -0
- iris_pex_embedded_python-3.5.5b4.dist-info/RECORD +91 -0
- iris_pex_embedded_python-3.5.5b4.dist-info/WHEEL +5 -0
- iris_pex_embedded_python-3.5.5b4.dist-info/entry_points.txt +2 -0
- iris_pex_embedded_python-3.5.5b4.dist-info/licenses/LICENSE +21 -0
- iris_pex_embedded_python-3.5.5b4.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Any, Optional, Union
|
|
2
|
+
|
|
3
|
+
from . import _iris
|
|
4
|
+
from ._dispatch import dispatch_serializer
|
|
5
|
+
|
|
6
|
+
class _GeneratorRequest:
|
|
7
|
+
"""Generator class to interetate over responses from a request.
|
|
8
|
+
This class is used to handle the responses from a request in a generator-like manner."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, host: Any, target: str, request: Any,
|
|
11
|
+
timeout: int = -1, description: Optional[str] = None) -> None:
|
|
12
|
+
self.host = host
|
|
13
|
+
self.target = target
|
|
14
|
+
self.request = request
|
|
15
|
+
|
|
16
|
+
ack_response = self.host.send_request_sync(self.target, dispatch_serializer(self.request, is_generator=True),
|
|
17
|
+
timeout=timeout, description=description)
|
|
18
|
+
|
|
19
|
+
if ack_response is None or not ack_response._IsA("IOP.Generator.Message.Ack"):
|
|
20
|
+
raise RuntimeError("Failed to send request, no acknowledgment received.")
|
|
21
|
+
|
|
22
|
+
def __iter__(self):
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
def __next__(self):
|
|
26
|
+
poll = _iris.get_iris().IOP.Generator.Message.Poll._New()
|
|
27
|
+
rsp = self.host.send_request_sync(self.target, poll)
|
|
28
|
+
if rsp is None or (hasattr(rsp, '_IsA') and rsp._IsA("IOP.Generator.Message.Stop")):
|
|
29
|
+
raise StopIteration("No more responses available.")
|
|
30
|
+
return rsp
|
iop/_inbound_adapter.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from ._common import _Common
|
|
2
|
+
|
|
3
|
+
class _InboundAdapter(_Common):
|
|
4
|
+
""" Responsible for receiving the data from the external system, validating the data,
|
|
5
|
+
and sending it to the business service by calling the BusinessHost.ProcessInput() method.
|
|
6
|
+
"""
|
|
7
|
+
BusinessHost = business_host = business_host_python = None
|
|
8
|
+
|
|
9
|
+
def on_task(self):
|
|
10
|
+
""" Called by the production framework at intervals determined by the business service CallInterval property.
|
|
11
|
+
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.
|
|
12
|
+
The message can have any structure agreed upon by the inbound adapter and the business service.
|
|
13
|
+
"""
|
|
14
|
+
return self.OnTask()
|
|
15
|
+
|
|
16
|
+
def _set_iris_handles(self, handle_current, handle_partner):
|
|
17
|
+
""" For internal use only. """
|
|
18
|
+
self.iris_handle = handle_current
|
|
19
|
+
self.BusinessHost = handle_partner
|
|
20
|
+
self.business_host = handle_partner
|
|
21
|
+
try:
|
|
22
|
+
self.business_host_python = handle_partner.GetClass()
|
|
23
|
+
except:
|
|
24
|
+
pass
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def OnTask(self):
|
|
29
|
+
""" DEPRECATED : use on_task
|
|
30
|
+
Called by the production framework at intervals determined by the business service CallInterval property.
|
|
31
|
+
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.
|
|
32
|
+
The message can have any structure agreed upon by the inbound adapter and the business service.
|
|
33
|
+
"""
|
|
34
|
+
return
|
iop/_iris.py
ADDED
iop/_log_manager.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from . import _iris
|
|
4
|
+
|
|
5
|
+
class LogManager:
|
|
6
|
+
"""Manages logging integration between Python's logging module and IRIS."""
|
|
7
|
+
|
|
8
|
+
@staticmethod
|
|
9
|
+
def get_logger(class_name: str, to_console: bool = False) -> logging.Logger:
|
|
10
|
+
"""Get a logger instance configured for IRIS integration.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
class_name: Name of the class logging the message
|
|
14
|
+
method_name: Optional name of the method logging the message
|
|
15
|
+
to_console: If True, log to the console instead of IRIS
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
Logger instance configured for IRIS integration
|
|
19
|
+
"""
|
|
20
|
+
logger = logging.Logger(f"{class_name}")
|
|
21
|
+
|
|
22
|
+
# Only add handler if none exists
|
|
23
|
+
if not logger.handlers:
|
|
24
|
+
handler = IRISLogHandler(to_console=to_console)
|
|
25
|
+
formatter = logging.Formatter('%(message)s')
|
|
26
|
+
handler.setFormatter(formatter)
|
|
27
|
+
logger.addHandler(handler)
|
|
28
|
+
# Set the log level to the lowest level to ensure all messages are sent to IRIS
|
|
29
|
+
logger.setLevel(logging.DEBUG)
|
|
30
|
+
|
|
31
|
+
return logger
|
|
32
|
+
|
|
33
|
+
class IRISLogHandler(logging.Handler):
|
|
34
|
+
"""Custom logging handler that routes Python logs to IRIS logging system."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, to_console: bool = False):
|
|
37
|
+
"""Initialize the IRIS logging handler."""
|
|
38
|
+
super().__init__()
|
|
39
|
+
self.to_console = to_console
|
|
40
|
+
|
|
41
|
+
# Map Python logging levels to IRIS logging methods
|
|
42
|
+
self.level_map = {
|
|
43
|
+
logging.DEBUG: 5,
|
|
44
|
+
logging.INFO: 4,
|
|
45
|
+
logging.WARNING: 3,
|
|
46
|
+
logging.ERROR: 2,
|
|
47
|
+
logging.CRITICAL: 6,
|
|
48
|
+
}
|
|
49
|
+
# Map Python logging levels to IRIS logging Console level
|
|
50
|
+
self.level_map_console = {
|
|
51
|
+
logging.DEBUG: -1,
|
|
52
|
+
logging.INFO: 0,
|
|
53
|
+
logging.WARNING: 1,
|
|
54
|
+
logging.ERROR: 2,
|
|
55
|
+
logging.CRITICAL: 3,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
59
|
+
"""Format the log record into a string.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
record: The logging record to format
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Formatted log message
|
|
66
|
+
"""
|
|
67
|
+
return record.getMessage()
|
|
68
|
+
|
|
69
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
70
|
+
"""Route the log record to appropriate IRIS logging method.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
record: The logging record to emit
|
|
74
|
+
"""
|
|
75
|
+
# Extract class and method names with fallbacks
|
|
76
|
+
class_name = getattr(record, "class_name", record.name)
|
|
77
|
+
method_name = getattr(record, "method_name", record.funcName)
|
|
78
|
+
|
|
79
|
+
# Format message and get full method path
|
|
80
|
+
message = self.format(record)
|
|
81
|
+
method_path = f"{class_name}.{method_name}"
|
|
82
|
+
|
|
83
|
+
# Determine if console logging should be used
|
|
84
|
+
use_console = self.to_console or getattr(record, "to_console", False)
|
|
85
|
+
|
|
86
|
+
if use_console:
|
|
87
|
+
_iris.get_iris().cls("%SYS.System").WriteToConsoleLog(
|
|
88
|
+
message,
|
|
89
|
+
0,
|
|
90
|
+
self.level_map_console.get(record.levelno, 0),
|
|
91
|
+
method_path
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
log_level = self.level_map.get(record.levelno, 4)
|
|
95
|
+
_iris.get_iris().cls("Ens.Util.Log").Log(
|
|
96
|
+
log_level,
|
|
97
|
+
class_name,
|
|
98
|
+
method_name,
|
|
99
|
+
message
|
|
100
|
+
)
|
iop/_message.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
class _Message:
|
|
6
|
+
""" The abstract class that is the superclass for persistent messages sent from one component to another.
|
|
7
|
+
This class has no properties or methods. Users subclass Message and add properties.
|
|
8
|
+
The IOP framework provides the persistence to objects derived from the Message class.
|
|
9
|
+
"""
|
|
10
|
+
_iris_id: Optional[str] = None
|
|
11
|
+
|
|
12
|
+
def get_iris_id(self) -> Optional[str]:
|
|
13
|
+
"""Get the IRIS ID of the message."""
|
|
14
|
+
return self._iris_id
|
|
15
|
+
|
|
16
|
+
class _PickleMessage(_Message):
|
|
17
|
+
""" The abstract class that is the superclass for persistent messages sent from one component to another.
|
|
18
|
+
This class has no properties or methods. Users subclass Message and add properties.
|
|
19
|
+
The IOP framework provides the persistence to objects derived from the Message class.
|
|
20
|
+
"""
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
class _PydanticMessage(BaseModel):
|
|
24
|
+
"""Base class for Pydantic-based messages that can be serialized to IRIS."""
|
|
25
|
+
|
|
26
|
+
_iris_id: Optional[str] = None
|
|
27
|
+
|
|
28
|
+
def __init__(self, **data: Any):
|
|
29
|
+
super().__init__(**data)
|
|
30
|
+
|
|
31
|
+
def get_iris_id(self) -> Optional[str]:
|
|
32
|
+
"""Get the IRIS ID of the message."""
|
|
33
|
+
return self._iris_id
|
|
34
|
+
|
|
35
|
+
class _PydanticPickleMessage(_PydanticMessage):
|
|
36
|
+
"""Base class for Pydantic-based messages that can be serialized to IRIS."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, **data: Any):
|
|
39
|
+
super().__init__(**data)
|
|
40
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from typing import Any, Type
|
|
3
|
+
|
|
4
|
+
from ._message import _Message, _PickleMessage, _PydanticPickleMessage, BaseModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def is_message_instance(obj: Any) -> bool:
|
|
8
|
+
"""Check if object is a valid Message instance."""
|
|
9
|
+
if isinstance(obj, BaseModel):
|
|
10
|
+
return True
|
|
11
|
+
if is_message_class(type(obj)):
|
|
12
|
+
if not dataclasses.is_dataclass(obj):
|
|
13
|
+
raise TypeError(f"{type(obj).__module__}.{type(obj).__qualname__} must be a dataclass")
|
|
14
|
+
return True
|
|
15
|
+
return False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def is_pickle_message_instance(obj: Any) -> bool:
|
|
19
|
+
"""Check if object is a PickleMessage instance."""
|
|
20
|
+
if isinstance(obj, _PydanticPickleMessage):
|
|
21
|
+
return True
|
|
22
|
+
if is_pickle_message_class(type(obj)):
|
|
23
|
+
return True
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def is_iris_object_instance(obj: Any) -> bool:
|
|
28
|
+
"""Check if object is an IRIS persistent object."""
|
|
29
|
+
return (obj is not None and
|
|
30
|
+
type(obj).__module__.startswith('iris') and
|
|
31
|
+
(obj._IsA("%Persistent") or obj._IsA("%Stream.Object")))
|
|
32
|
+
# Stream.Object are used for HTTP InboundAdapter/OutboundAdapter
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def is_message_class(klass: Type) -> bool:
|
|
36
|
+
"""Check if class is a Message type."""
|
|
37
|
+
if issubclass(klass, _Message):
|
|
38
|
+
return True
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def is_pickle_message_class(klass: Type) -> bool:
|
|
44
|
+
"""Check if class is a PickleMessage type."""
|
|
45
|
+
if issubclass(klass, _PickleMessage):
|
|
46
|
+
return True
|
|
47
|
+
if issubclass(klass, _PydanticPickleMessage):
|
|
48
|
+
return True
|
|
49
|
+
return False
|
iop/_outbound_adapter.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from ._common import _Common
|
|
2
|
+
|
|
3
|
+
class _OutboundAdapter(_Common):
|
|
4
|
+
""" Responsible for sending the data to the external system."""
|
|
5
|
+
BusinessHost = business_host = business_host_python = None
|
|
6
|
+
|
|
7
|
+
def on_keepalive(self):
|
|
8
|
+
"""
|
|
9
|
+
> This function is called when the server sends a keepalive message
|
|
10
|
+
"""
|
|
11
|
+
return
|
|
12
|
+
|
|
13
|
+
def _set_iris_handles(self, handle_current, handle_partner):
|
|
14
|
+
""" For internal use only. """
|
|
15
|
+
self.iris_handle = handle_current
|
|
16
|
+
self.BusinessHost = handle_partner
|
|
17
|
+
self.business_host = handle_partner
|
|
18
|
+
try:
|
|
19
|
+
self.business_host_python = handle_partner.GetClass()
|
|
20
|
+
except:
|
|
21
|
+
pass
|
|
22
|
+
return
|
|
23
|
+
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
|
|
3
|
+
from ._business_host import _BusinessHost
|
|
4
|
+
from ._decorators import input_deserializer, input_serializer_param, output_serializer, input_serializer, output_deserializer
|
|
5
|
+
from ._dispatch import create_dispatch, dispach_message
|
|
6
|
+
|
|
7
|
+
class _PrivateSessionDuplex(_BusinessHost):
|
|
8
|
+
|
|
9
|
+
Adapter = adapter = None
|
|
10
|
+
_wait_for_next_call_interval = False
|
|
11
|
+
DISPATCH = []
|
|
12
|
+
|
|
13
|
+
def on_message(self, request):
|
|
14
|
+
""" Called when the business operation receives a message from another production component.
|
|
15
|
+
Typically, the operation will either send the message to the external system or forward it to a business process or another business operation.
|
|
16
|
+
If the operation has an adapter, it uses the Adapter.invoke() method to call the method on the adapter that sends the message to the external system.
|
|
17
|
+
If the operation is forwarding the message to another production component, it uses the SendRequestAsync() or the SendRequestSync() method
|
|
18
|
+
|
|
19
|
+
Parameters:
|
|
20
|
+
request: An instance of either a subclass of Message or of IRISObject containing the incoming message for the business operation.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
The response object
|
|
24
|
+
"""
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@input_deserializer
|
|
28
|
+
@output_serializer
|
|
29
|
+
def _dispatch_on_message(self, request):
|
|
30
|
+
""" For internal use only. """
|
|
31
|
+
return dispach_message(self,request)
|
|
32
|
+
|
|
33
|
+
def _set_iris_handles(self, handle_current, handle_partner):
|
|
34
|
+
""" For internal use only. """
|
|
35
|
+
self.iris_handle = handle_current
|
|
36
|
+
if type(handle_partner).__module__.find('iris') == 0:
|
|
37
|
+
if (handle_partner._IsA("Grongier.PEX.InboundAdapter") or handle_partner._IsA("Grongier.PEX.OutboundAdapter")
|
|
38
|
+
or handle_partner._IsA("IOP.InboundAdapter") or handle_partner._IsA("IOP.OutboundAdapter")):
|
|
39
|
+
module = importlib.import_module(handle_partner.GetModule())
|
|
40
|
+
handle_partner = getattr(module, handle_partner.GetClassname())()
|
|
41
|
+
self.Adapter = self.adapter = handle_partner
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
@input_deserializer
|
|
45
|
+
@output_serializer
|
|
46
|
+
def _dispatch_on_process_input(self, request):
|
|
47
|
+
""" For internal use only. """
|
|
48
|
+
return self.on_process_input(request)
|
|
49
|
+
|
|
50
|
+
def on_process_input(self, message_input):
|
|
51
|
+
""" Receives the message from the inbond adapter via the PRocessInput method and is responsible for forwarding it to target business processes or operations.
|
|
52
|
+
If the business service does not specify an adapter, then the default adapter calls this method with no message
|
|
53
|
+
and the business service is responsible for receiving the data from the external system and validating it.
|
|
54
|
+
|
|
55
|
+
Parameters:
|
|
56
|
+
message_input: an instance of IRISObject or subclass of Message containing the data that the inbound adapter passes in.
|
|
57
|
+
The message can have any structure agreed upon by the inbound adapter and the business service.
|
|
58
|
+
"""
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
@input_serializer_param(0,'document')
|
|
62
|
+
@output_deserializer
|
|
63
|
+
def send_document_to_process(self, document):
|
|
64
|
+
""" Send the specified message to the target business process or business operation synchronously.
|
|
65
|
+
|
|
66
|
+
Parameters:
|
|
67
|
+
target: a string that specifies the name of the business process or operation to receive the request.
|
|
68
|
+
The target is the name of the component as specified in the Item Name property in the production definition, not the class name of the component.
|
|
69
|
+
request: specifies the message to send to the target. The request is either an instance of a class that is a subclass of Message class or of IRISObject class.
|
|
70
|
+
If the target is a build-in ObjectScript component, you should use the IRISObject class. The IRISObject class enables the PEX framework to convert the message to a class supported by the target.
|
|
71
|
+
timeout: an optional integer that specifies the number of seconds to wait before treating the send request as a failure. The default value is -1, which means wait forever.
|
|
72
|
+
description: an optional string parameter that sets a description property in the message header. The default is None.
|
|
73
|
+
Returns:
|
|
74
|
+
the response object from target.
|
|
75
|
+
Raises:
|
|
76
|
+
TypeError: if request is not of type Message or IRISObject.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
return self.iris_handle.dispatchSendDocumentToProcess(document)
|
|
80
|
+
|
|
81
|
+
@input_deserializer
|
|
82
|
+
@output_serializer
|
|
83
|
+
def _dispatch_on_private_session_started(self, source_config_name,self_generated):
|
|
84
|
+
""" For internal use only. """
|
|
85
|
+
|
|
86
|
+
return_object = self.on_private_session_started(source_config_name,self_generated)
|
|
87
|
+
|
|
88
|
+
return return_object
|
|
89
|
+
|
|
90
|
+
def on_private_session_started(self,source_config_name,self_generated):
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
@input_deserializer
|
|
94
|
+
@output_serializer
|
|
95
|
+
def _dispatch_on_private_session_stopped(self, source_config_name,self_generated,message):
|
|
96
|
+
""" For internal use only. """
|
|
97
|
+
|
|
98
|
+
return_object = self.on_private_session_stopped(source_config_name,self_generated,message)
|
|
99
|
+
|
|
100
|
+
return return_object
|
|
101
|
+
|
|
102
|
+
def on_private_session_stopped(self,source_config_name,self_generated,message):
|
|
103
|
+
pass
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from ._business_process import _BusinessProcess
|
|
2
|
+
from ._decorators import input_deserializer, output_serializer, input_serializer, output_deserializer
|
|
3
|
+
|
|
4
|
+
class _PrivateSessionProcess(_BusinessProcess):
|
|
5
|
+
|
|
6
|
+
@input_deserializer
|
|
7
|
+
@output_serializer
|
|
8
|
+
def _dispatch_on_document(self, host_object,source_config_name, request):
|
|
9
|
+
""" For internal use only. """
|
|
10
|
+
self._restore_persistent_properties(host_object)
|
|
11
|
+
return_object = self.on_document(source_config_name,request)
|
|
12
|
+
self._save_persistent_properties(host_object)
|
|
13
|
+
return return_object
|
|
14
|
+
|
|
15
|
+
def on_document(self,source_config_name,request):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@input_deserializer
|
|
20
|
+
@output_serializer
|
|
21
|
+
def _dispatch_on_private_session_started(self, host_object, source_config_name,self_generated):
|
|
22
|
+
""" For internal use only. """
|
|
23
|
+
self._restore_persistent_properties(host_object)
|
|
24
|
+
return_object = self.on_private_session_started(source_config_name,self_generated)
|
|
25
|
+
self._save_persistent_properties(host_object)
|
|
26
|
+
return return_object
|
|
27
|
+
|
|
28
|
+
def on_private_session_started(self,source_config_name,self_generated):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@input_deserializer
|
|
32
|
+
@output_serializer
|
|
33
|
+
def _dispatch_on_private_session_stopped(self, host_object, source_config_name,self_generated,message):
|
|
34
|
+
""" For internal use only. """
|
|
35
|
+
self._restore_persistent_properties(host_object)
|
|
36
|
+
return_object = self.on_private_session_stopped(source_config_name,self_generated,message)
|
|
37
|
+
self._save_persistent_properties(host_object)
|
|
38
|
+
return return_object
|
|
39
|
+
|
|
40
|
+
def on_private_session_stopped(self,source_config_name,self_generated,message):
|
|
41
|
+
pass
|
iop/_remote.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# This module provides a REST API for remote I/O operations
|
|
2
|
+
# It uses Flask to handle incoming requests and route them to the appropriate I/O functions
|
|
3
|
+
# It should be able to help the migrate command of IoP Cli to work remotely:
|
|
4
|
+
# this means copy all the .py files from the current directory of (settings.py) to the remote server
|
|
5
|
+
# and run the api migrate from the remote server
|
|
6
|
+
# the default folder is based on the NAMESPACE variable in settings.py
|
|
7
|
+
from flask import Flask, request, jsonify
|
|
8
|
+
|
|
9
|
+
@app.route('/remote_io', methods=['POST'])
|
|
10
|
+
def remote_io():
|
|
11
|
+
data = request.json
|
|
12
|
+
if not data or 'operation' not in data:
|
|
13
|
+
return jsonify({'error': 'Invalid request'}), 400
|
|
14
|
+
|
|
15
|
+
operation = data['operation']
|
|
16
|
+
# Here you would implement the logic to handle the operation
|
|
17
|
+
# For example, you could call a function that performs the I/O operation
|
|
18
|
+
# and return the result as JSON.
|
|
19
|
+
|
|
20
|
+
# Placeholder response for demonstration purposes
|
|
21
|
+
response = {'status': 'success', 'operation': operation}
|
|
22
|
+
return jsonify(response), 200
|
|
23
|
+
|
|
24
|
+
# ClassMethod UploadPackage(
|
|
25
|
+
# namespace As %String,
|
|
26
|
+
# body As %DynamicArray) As %DynamicObject
|
|
27
|
+
# {
|
|
28
|
+
# // check for namespace existence and user permissions against namespace
|
|
29
|
+
# If '..NamespaceCheck(namespace) {
|
|
30
|
+
# Return ""
|
|
31
|
+
# }
|
|
32
|
+
# New $NAMESPACE
|
|
33
|
+
# Set $NAMESPACE = namespace
|
|
34
|
+
|
|
35
|
+
# //Create directory for custom packages
|
|
36
|
+
# Do ##class(%ZHSLIB.HealthShareMgr).GetDBNSInfo(namespace,.out)
|
|
37
|
+
# Set customPackagesPath = ##class(%Library.File).NormalizeDirectory("fhir_packages", out.globalsDatabase.directory)
|
|
38
|
+
# If '##class(%Library.File).DirectoryExists(customPackagesPath) {
|
|
39
|
+
# If '##class(%Library.File).CreateDirectory(customPackagesPath) {
|
|
40
|
+
# $$$ThrowStatus($$$ERROR($$$DirectoryCannotCreate, customPackagesPath))
|
|
41
|
+
# }
|
|
42
|
+
# }
|
|
43
|
+
|
|
44
|
+
# //Find package name
|
|
45
|
+
# Set iterator = body.%GetIterator()
|
|
46
|
+
# Set packageName = ""
|
|
47
|
+
# While iterator.%GetNext(, .fileObject ) {
|
|
48
|
+
# If fileObject.name = "package.json" {
|
|
49
|
+
# Set packageName = fileObject.data.name_"@"_fileObject.data.version
|
|
50
|
+
# }
|
|
51
|
+
# }
|
|
52
|
+
# If packageName = "" {
|
|
53
|
+
# Do ..%ReportRESTError($$$HTTP400,$$$ERROR($$$HSFHIRErrPackageNotFound))
|
|
54
|
+
# Return ""
|
|
55
|
+
# }
|
|
56
|
+
|
|
57
|
+
# Set packagePath = ##class(%Library.File).NormalizeDirectory(packageName, customPackagesPath)
|
|
58
|
+
# // If the package already exists then we must be meaning to re-load it. Delete files/directory/metadata and recreate fresh.
|
|
59
|
+
# If ##class(%Library.File).DirectoryExists(packagePath) {
|
|
60
|
+
# If '##class(%Library.File).RemoveDirectoryTree(packagePath) {
|
|
61
|
+
# $$$ThrowStatus($$$ERROR($$$DirectoryPermission , packagePath))
|
|
62
|
+
# }
|
|
63
|
+
# }
|
|
64
|
+
# If '##class(%Library.File).CreateDirectory(packagePath) {
|
|
65
|
+
# $$$ThrowStatus($$$ERROR($$$DirectoryCannotCreate, customPackagesPath))
|
|
66
|
+
# }
|
|
67
|
+
# Set pkg = ##class(HS.FHIRMeta.Storage.Package).FindById(packageName)
|
|
68
|
+
# If $ISOBJECT(pkg) {
|
|
69
|
+
# // Will fail and throw if the package is in-use or has dependencies preventing it from being deleted.
|
|
70
|
+
# Do ##class(HS.FHIRServer.ServiceAdmin).DeleteMetadataPackage(packageName)
|
|
71
|
+
# }
|
|
72
|
+
# Kill pkg
|
|
73
|
+
|
|
74
|
+
# //Unpack JSON objects
|
|
75
|
+
# Set iterator = body.%GetIterator()
|
|
76
|
+
# While iterator.%GetNext(.key , .fileObject ) {
|
|
77
|
+
# Set fileName = ##class(%Library.File).NormalizeFilename(fileObject.name,packagePath)
|
|
78
|
+
# Set fileStream = ##class(%Stream.FileCharacter).%New()
|
|
79
|
+
# Set fileStream.TranslateTable = "UTF8"
|
|
80
|
+
# $$$ThrowOnError(fileStream.LinkToFile(fileName))
|
|
81
|
+
# Do fileObject.data.%ToJSON(.fileStream)
|
|
82
|
+
# $$$ThrowOnError(fileStream.%Save())
|
|
83
|
+
# }
|
|
84
|
+
|
|
85
|
+
# //Import package
|
|
86
|
+
# Do ##class(HS.FHIRMeta.Load.NpmLoader).importPackages(packagePath)
|
|
87
|
+
# Set pkg = ..GetOnePackage(packageName, namespace)
|
|
88
|
+
# Do ..%SetStatusCode($$$HTTP201)
|
|
89
|
+
# Do ..%SetHeader("location", %request.Application _ "packages/" _ packageName _ "?namespace=" _ namespace)
|
|
90
|
+
# Return pkg
|
|
91
|
+
# }
|