iris-pex-embedded-python 3.6.1b1__tar.gz → 3.7.1b1__tar.gz
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.
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/PKG-INFO +3 -5
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/pyproject.toml +5 -7
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/__init__.py +10 -7
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/__init__.py +13 -10
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_dispatch.py +11 -2
- iris_pex_embedded_python-3.7.1b1/src/iop/_persistent_message.py +513 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_utils.py +48 -1
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iris_pex_embedded_python.egg-info/PKG-INFO +3 -5
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iris_pex_embedded_python.egg-info/SOURCES.txt +1 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iris_pex_embedded_python.egg-info/requires.txt +1 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/LICENSE +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/README.md +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/setup.cfg +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/setup.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/__init__.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/BusinessOperation.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/BusinessProcess.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/BusinessService.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Common.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Director.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Duplex/Operation.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Duplex/Process.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Duplex/Service.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/InboundAdapter.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Message.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/OutboundAdapter.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/PickleMessage.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Test.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/PEX/Utils.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/cls/Grongier/Service/WSGI.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/__main__.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_business_host.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_cli.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_common.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_director.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_utils.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/wsgi/handlers.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/__main__.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_async_request.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_host.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_operation.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_process.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_service.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_cli.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_common.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_debugpy.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_decorators.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_director.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_director_protocol.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_generator_request.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_inbound_adapter.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_iris.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_local.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_log_manager.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_message.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_message_validator.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_outbound_adapter.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_private_session_duplex.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_private_session_process.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_remote.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_serialization.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/BusinessOperation.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/BusinessProcess.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/BusinessService.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Common.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Director.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Duplex/Operation.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Duplex/Process.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Duplex/Service.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Generator/Message/Ack.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Generator/Message/Poll.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Generator/Message/Start.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Generator/Message/StartPickle.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Generator/Message/Stop.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/InboundAdapter.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Message/JSONSchema.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Message.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/OutboundAdapter.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/PickleMessage.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/PrivateSession/Duplex.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/PrivateSession/Message/Ack.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/PrivateSession/Message/Poll.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/PrivateSession/Message/Start.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/PrivateSession/Message/Stop.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Projection.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Service/Remote/Handler.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Service/Remote/Rest/v1.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Service/WSGI.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Test.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Utils.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Wrapper.cls +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/wsgi/handlers.py +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iris_pex_embedded_python.egg-info/dependency_links.txt +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iris_pex_embedded_python.egg-info/entry_points.txt +0 -0
- {iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iris_pex_embedded_python.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris_pex_embedded_python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.1b1
|
|
4
4
|
Summary: Iris Interoperability based on Embedded Python
|
|
5
5
|
Author-email: grongier <guillaume.rongier@intersystems.com>
|
|
6
6
|
License: MIT License
|
|
@@ -34,19 +34,17 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
34
34
|
Classifier: Intended Audience :: Developers
|
|
35
35
|
Classifier: License :: OSI Approved :: MIT License
|
|
36
36
|
Classifier: Operating System :: OS Independent
|
|
37
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
38
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
39
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
40
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
41
37
|
Classifier: Programming Language :: Python :: 3.10
|
|
42
38
|
Classifier: Programming Language :: Python :: 3.11
|
|
43
39
|
Classifier: Programming Language :: Python :: 3.12
|
|
44
40
|
Classifier: Topic :: Utilities
|
|
41
|
+
Requires-Python: >=3.10
|
|
45
42
|
Description-Content-Type: text/markdown
|
|
46
43
|
License-File: LICENSE
|
|
47
44
|
Requires-Dist: pydantic>=2.0.0
|
|
48
45
|
Requires-Dist: xmltodict>=0.12.0
|
|
49
46
|
Requires-Dist: iris-embedded-python-wrapper>=0.0.6
|
|
47
|
+
Requires-Dist: iris-persistence>=0.1.0
|
|
50
48
|
Requires-Dist: jsonpath-ng>=1.7.0
|
|
51
49
|
Requires-Dist: debugpy>=1.8.0
|
|
52
50
|
Requires-Dist: requests>=2.24.0
|
|
@@ -3,9 +3,10 @@ requires = ["setuptools", "wheel"]
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "iris_pex_embedded_python"
|
|
6
|
-
version = "3.
|
|
6
|
+
version = "3.7.1b1"
|
|
7
7
|
description = "Iris Interoperability based on Embedded Python"
|
|
8
8
|
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.10"
|
|
9
10
|
authors = [
|
|
10
11
|
{ name = "grongier", email = "guillaume.rongier@intersystems.com" },
|
|
11
12
|
]
|
|
@@ -16,10 +17,6 @@ classifiers = [
|
|
|
16
17
|
"Intended Audience :: Developers",
|
|
17
18
|
"License :: OSI Approved :: MIT License",
|
|
18
19
|
"Operating System :: OS Independent",
|
|
19
|
-
"Programming Language :: Python :: 3.6",
|
|
20
|
-
"Programming Language :: Python :: 3.7",
|
|
21
|
-
"Programming Language :: Python :: 3.8",
|
|
22
|
-
"Programming Language :: Python :: 3.9",
|
|
23
20
|
"Programming Language :: Python :: 3.10",
|
|
24
21
|
"Programming Language :: Python :: 3.11",
|
|
25
22
|
"Programming Language :: Python :: 3.12",
|
|
@@ -30,6 +27,7 @@ dependencies = [
|
|
|
30
27
|
"pydantic>=2.0.0",
|
|
31
28
|
"xmltodict>=0.12.0",
|
|
32
29
|
"iris-embedded-python-wrapper>=0.0.6",
|
|
30
|
+
"iris-persistence>=0.1.0",
|
|
33
31
|
"jsonpath-ng>=1.7.0",
|
|
34
32
|
"debugpy>=1.8.0",
|
|
35
33
|
"requests>=2.24.0"
|
|
@@ -51,7 +49,7 @@ where = ["src"]
|
|
|
51
49
|
exclude = ["tests*"]
|
|
52
50
|
|
|
53
51
|
[tool.setuptools.package-data]
|
|
54
|
-
"*" = ["*.cls"]
|
|
52
|
+
"*" = ["*.cls", "cls/**/*.cls"]
|
|
55
53
|
|
|
56
54
|
[tool.pytest.ini_options]
|
|
57
55
|
asyncio_default_fixture_loop_scope = "class"
|
|
@@ -60,4 +58,4 @@ markers = [
|
|
|
60
58
|
"unit: pure unit test - no IRIS instance required (all IRIS calls mocked)",
|
|
61
59
|
"e2e_local: end-to-end test requiring a local IRIS instance",
|
|
62
60
|
"e2e_remote: end-to-end test requiring a remote IRIS instance via REST API",
|
|
63
|
-
]
|
|
61
|
+
]
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/__init__.py
RENAMED
|
@@ -5,10 +5,11 @@ from iop._private_session_process import _PrivateSessionProcess
|
|
|
5
5
|
from iop._business_operation import _BusinessOperation
|
|
6
6
|
from iop._inbound_adapter import _InboundAdapter
|
|
7
7
|
from iop._outbound_adapter import _OutboundAdapter
|
|
8
|
-
from iop._message import _Message
|
|
9
|
-
from iop._message import _PickleMessage
|
|
10
|
-
from iop.
|
|
11
|
-
from iop.
|
|
8
|
+
from iop._message import _Message
|
|
9
|
+
from iop._message import _PickleMessage
|
|
10
|
+
from iop._persistent_message import Field, Model, _PersistentMessage
|
|
11
|
+
from iop._director import _Director
|
|
12
|
+
from iop._utils import _Utils
|
|
12
13
|
|
|
13
14
|
class Utils(_Utils): pass
|
|
14
15
|
class InboundAdapter(_InboundAdapter): pass
|
|
@@ -19,6 +20,8 @@ class BusinessProcess(_BusinessProcess): pass
|
|
|
19
20
|
class DuplexService(_PrivateSessionDuplex): pass
|
|
20
21
|
class DuplexOperation(_PrivateSessionDuplex): pass
|
|
21
22
|
class DuplexProcess(_PrivateSessionProcess): pass
|
|
22
|
-
class Message(_Message): pass
|
|
23
|
-
class PickleMessage(_PickleMessage): pass
|
|
24
|
-
class
|
|
23
|
+
class Message(_Message): pass
|
|
24
|
+
class PickleMessage(_PickleMessage): pass
|
|
25
|
+
class PersistentMessage(_PersistentMessage):
|
|
26
|
+
_iop_persistent_message_abstract = True
|
|
27
|
+
class Director(_Director): pass
|
|
@@ -2,12 +2,13 @@ from iop._business_operation import _BusinessOperation
|
|
|
2
2
|
from iop._business_process import _BusinessProcess
|
|
3
3
|
from iop._business_service import _BusinessService
|
|
4
4
|
from iop._director import _Director
|
|
5
|
-
from iop._inbound_adapter import _InboundAdapter
|
|
6
|
-
from iop._message import _Message, _PickleMessage, _PydanticMessage, _PydanticPickleMessage
|
|
7
|
-
from iop._outbound_adapter import _OutboundAdapter
|
|
8
|
-
from iop.
|
|
9
|
-
from iop.
|
|
10
|
-
from iop.
|
|
5
|
+
from iop._inbound_adapter import _InboundAdapter
|
|
6
|
+
from iop._message import _Message, _PickleMessage, _PydanticMessage, _PydanticPickleMessage
|
|
7
|
+
from iop._outbound_adapter import _OutboundAdapter
|
|
8
|
+
from iop._persistent_message import Field, Model, _PersistentMessage
|
|
9
|
+
from iop._private_session_duplex import _PrivateSessionDuplex
|
|
10
|
+
from iop._private_session_process import _PrivateSessionProcess
|
|
11
|
+
from iop._utils import _Utils
|
|
11
12
|
|
|
12
13
|
class Utils(_Utils): pass
|
|
13
14
|
class InboundAdapter(_InboundAdapter): pass
|
|
@@ -19,7 +20,9 @@ class DuplexService(_PrivateSessionDuplex): pass
|
|
|
19
20
|
class DuplexOperation(_PrivateSessionDuplex): pass
|
|
20
21
|
class DuplexProcess(_PrivateSessionProcess): pass
|
|
21
22
|
class Message(_Message): pass
|
|
22
|
-
class PickleMessage(_PickleMessage): pass
|
|
23
|
-
class PydanticMessage(_PydanticMessage): pass
|
|
24
|
-
class PydanticPickleMessage(_PydanticPickleMessage): pass
|
|
25
|
-
class
|
|
23
|
+
class PickleMessage(_PickleMessage): pass
|
|
24
|
+
class PydanticMessage(_PydanticMessage): pass
|
|
25
|
+
class PydanticPickleMessage(_PydanticPickleMessage): pass
|
|
26
|
+
class PersistentMessage(_PersistentMessage):
|
|
27
|
+
_iop_persistent_message_abstract = True
|
|
28
|
+
class Director(_Director): pass
|
|
@@ -3,6 +3,11 @@ from typing import Any, List, Tuple, Callable
|
|
|
3
3
|
|
|
4
4
|
from ._serialization import serialize_message, serialize_pickle_message, deserialize_message, deserialize_pickle_message, serialize_message_generator, serialize_pickle_message_generator
|
|
5
5
|
from ._message_validator import is_message_instance, is_pickle_message_instance, is_iris_object_instance
|
|
6
|
+
from ._persistent_message import (
|
|
7
|
+
deserialize_persistent_message,
|
|
8
|
+
is_persistent_message_instance,
|
|
9
|
+
serialize_persistent_message,
|
|
10
|
+
)
|
|
6
11
|
|
|
7
12
|
def dispatch_serializer(message: Any, is_generator: bool = False) -> Any:
|
|
8
13
|
"""Serializes the message based on its type.
|
|
@@ -17,7 +22,9 @@ def dispatch_serializer(message: Any, is_generator: bool = False) -> Any:
|
|
|
17
22
|
TypeError: If message is invalid type
|
|
18
23
|
"""
|
|
19
24
|
if message is not None:
|
|
20
|
-
if
|
|
25
|
+
if is_persistent_message_instance(message):
|
|
26
|
+
return serialize_persistent_message(message, is_generator=is_generator)
|
|
27
|
+
elif is_message_instance(message):
|
|
21
28
|
if is_generator:
|
|
22
29
|
return serialize_message_generator(message)
|
|
23
30
|
return serialize_message(message)
|
|
@@ -63,6 +70,8 @@ def dispatch_deserializer(serial: Any) -> Any:
|
|
|
63
70
|
)
|
|
64
71
|
):
|
|
65
72
|
return deserialize_pickle_message(serial)
|
|
73
|
+
elif is_iris_object_instance(serial):
|
|
74
|
+
return deserialize_persistent_message(serial)
|
|
66
75
|
else:
|
|
67
76
|
return serial
|
|
68
77
|
|
|
@@ -133,4 +142,4 @@ def get_handler_info(host: Any, method_name: str) -> Tuple[str, str] | None:
|
|
|
133
142
|
return f"{annotation.__module__}.{annotation.__name__}", method_name
|
|
134
143
|
|
|
135
144
|
except ValueError:
|
|
136
|
-
return None
|
|
145
|
+
return None
|
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import inspect
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
from iris_persistence import Field, Model
|
|
10
|
+
from iris_persistence.models import ModelMeta
|
|
11
|
+
from iris_persistence.query import _build_model_from_iris_obj, _materialize_related_value
|
|
12
|
+
from iris_persistence.runtime import get_runtime
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
DEFAULT_SUPERCLASS = "Ens.MessageBody"
|
|
16
|
+
DEFAULT_SYNC_MODE = "extend"
|
|
17
|
+
MESSAGE_KIND_PARAMETER = "IOP_MESSAGE_KIND"
|
|
18
|
+
MESSAGE_KIND_VALUE = "PersistentMessage"
|
|
19
|
+
PYTHON_CLASS_PARAMETER = "IOP_PYTHON_CLASS"
|
|
20
|
+
PYTHON_CLASSPATH_PARAMETER = "IOP_PYTHON_CLASSPATH"
|
|
21
|
+
|
|
22
|
+
_PYTHON_TO_IRIS_CACHE: dict[str, str] = {}
|
|
23
|
+
_IRIS_TO_PYTHON_CACHE: dict[str, str] = {}
|
|
24
|
+
_IRIS_TO_PYTHON_CLASSPATH_CACHE: dict[str, str] = {}
|
|
25
|
+
_IRIS_TO_PYTHON_STRICT_CACHE: dict[str, bool] = {}
|
|
26
|
+
_IRIS_PARAMETER_CACHE: dict[tuple[str, str], Optional[str]] = {}
|
|
27
|
+
_AUTO_SYNCED: set[tuple[type, str]] = set()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PersistentMessageError(Exception):
|
|
31
|
+
"""Raised when a native persistent message cannot be materialized."""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class _PersistentMessageMeta(ModelMeta):
|
|
35
|
+
def __init__(cls, name: str, bases: tuple, namespace: dict, **kwargs: Any):
|
|
36
|
+
super().__init__(name, bases, namespace, **kwargs)
|
|
37
|
+
|
|
38
|
+
if namespace.get("_iop_persistent_message_abstract", False):
|
|
39
|
+
cls._iop_persistent_message_base = True
|
|
40
|
+
cls._iop_persistent_message_abstract = True
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
if not any(getattr(base, "_iop_persistent_message_base", False) for base in bases):
|
|
44
|
+
cls._iop_persistent_message_base = True
|
|
45
|
+
cls._iop_persistent_message_abstract = True
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
_apply_persistent_message_defaults(cls, namespace, kwargs)
|
|
49
|
+
cls._iop_persistent_message_base = True
|
|
50
|
+
cls._iop_persistent_message_abstract = False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _explicit_meta_classname(cls: type) -> Optional[str]:
|
|
54
|
+
meta = cls.__dict__.get("Meta")
|
|
55
|
+
if meta is None or not hasattr(meta, "classname"):
|
|
56
|
+
return None
|
|
57
|
+
value = getattr(meta, "classname")
|
|
58
|
+
return str(value) if value else None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _apply_persistent_message_defaults(
|
|
62
|
+
cls: type,
|
|
63
|
+
namespace: Optional[dict] = None,
|
|
64
|
+
kwargs: Optional[dict] = None,
|
|
65
|
+
) -> None:
|
|
66
|
+
namespace = namespace or {}
|
|
67
|
+
kwargs = kwargs or {}
|
|
68
|
+
meta = namespace.get("Meta") or cls.__dict__.get("Meta")
|
|
69
|
+
|
|
70
|
+
has_superclasses = "superclasses" in kwargs or (
|
|
71
|
+
meta is not None and hasattr(meta, "superclasses")
|
|
72
|
+
)
|
|
73
|
+
has_classname = meta is not None and hasattr(meta, "classname")
|
|
74
|
+
has_mode = meta is not None and hasattr(meta, "mode")
|
|
75
|
+
has_auto_sync = meta is not None and hasattr(meta, "auto_sync")
|
|
76
|
+
|
|
77
|
+
if not has_superclasses:
|
|
78
|
+
cls._superclasses = DEFAULT_SUPERCLASS
|
|
79
|
+
if not has_classname and not getattr(cls, "_iop_registered_classname", None):
|
|
80
|
+
cls._classname = python_classname_to_iris_classname(get_python_classname(cls))
|
|
81
|
+
if not has_mode:
|
|
82
|
+
cls._sync_mode = DEFAULT_SYNC_MODE
|
|
83
|
+
if not has_auto_sync:
|
|
84
|
+
cls._auto_sync = True
|
|
85
|
+
_set_message_parameters(cls)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class _PersistentMessage(Model, metaclass=_PersistentMessageMeta):
|
|
89
|
+
_iop_persistent_message_abstract = True
|
|
90
|
+
|
|
91
|
+
def get_iris_id(self) -> Optional[str]:
|
|
92
|
+
if self.pk:
|
|
93
|
+
return self.pk
|
|
94
|
+
|
|
95
|
+
iris_obj = self.__dict__.get("_iris_obj")
|
|
96
|
+
if iris_obj is None:
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
obj_id = get_runtime().get_object_id(iris_obj)
|
|
101
|
+
if obj_id:
|
|
102
|
+
return str(obj_id)
|
|
103
|
+
except Exception:
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
for method_name in ("_Id", "Id", "%Id"):
|
|
107
|
+
try:
|
|
108
|
+
method = getattr(iris_obj, method_name)
|
|
109
|
+
obj_id = method()
|
|
110
|
+
if obj_id:
|
|
111
|
+
return str(obj_id)
|
|
112
|
+
except Exception:
|
|
113
|
+
pass
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def is_persistent_message_class(klass: Any) -> bool:
|
|
118
|
+
try:
|
|
119
|
+
return (
|
|
120
|
+
isinstance(klass, type)
|
|
121
|
+
and issubclass(klass, _PersistentMessage)
|
|
122
|
+
and not getattr(klass, "_iop_persistent_message_abstract", False)
|
|
123
|
+
)
|
|
124
|
+
except TypeError:
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def is_persistent_message_instance(obj: Any) -> bool:
|
|
129
|
+
return is_persistent_message_class(type(obj))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def get_python_classname(klass: type) -> str:
|
|
133
|
+
return f"{klass.__module__}.{klass.__name__}"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def python_classname_to_iris_classname(python_classname: str) -> str:
|
|
137
|
+
"""Encode a Python FQCN as an IRIS-safe classname."""
|
|
138
|
+
if not python_classname:
|
|
139
|
+
raise ValueError("Python classname cannot be empty")
|
|
140
|
+
return ".".join(_encode_iris_identifier(part) for part in python_classname.split("."))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def iris_classname_to_python_classname(iris_classname: str) -> str:
|
|
144
|
+
"""Decode an IRIS classname produced by python_classname_to_iris_classname."""
|
|
145
|
+
if not iris_classname:
|
|
146
|
+
raise ValueError("IRIS classname cannot be empty")
|
|
147
|
+
return ".".join(_decode_iris_identifier(part) for part in iris_classname.split("."))
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def register_persistent_message_class(
|
|
151
|
+
msg_cls: type,
|
|
152
|
+
iris_classname: str,
|
|
153
|
+
*,
|
|
154
|
+
sync_schema: bool = True,
|
|
155
|
+
) -> None:
|
|
156
|
+
if not is_persistent_message_class(msg_cls):
|
|
157
|
+
raise TypeError("The class must be a subclass of PersistentMessage")
|
|
158
|
+
if not iris_classname:
|
|
159
|
+
raise ValueError("PersistentMessage IRIS classname cannot be empty")
|
|
160
|
+
|
|
161
|
+
explicit_classname = _explicit_meta_classname(msg_cls)
|
|
162
|
+
if explicit_classname and explicit_classname != iris_classname:
|
|
163
|
+
raise ValueError(
|
|
164
|
+
f"{get_python_classname(msg_cls)} declares Meta.classname={explicit_classname!r}, "
|
|
165
|
+
f"but CLASSES registers it as {iris_classname!r}"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
_prepare_message_class(msg_cls, iris_classname, registered=True)
|
|
169
|
+
|
|
170
|
+
if sync_schema:
|
|
171
|
+
msg_cls.sync_schema()
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def serialize_persistent_message(message: _PersistentMessage, is_generator: bool = False) -> Any:
|
|
175
|
+
if is_generator:
|
|
176
|
+
raise TypeError("PersistentMessage cannot be used as a generator start message.")
|
|
177
|
+
|
|
178
|
+
msg_cls = type(message)
|
|
179
|
+
iris_classname = resolve_iris_classname(msg_cls)
|
|
180
|
+
_ensure_schema(msg_cls, iris_classname)
|
|
181
|
+
|
|
182
|
+
runtime = get_runtime()
|
|
183
|
+
iris_obj = message.__dict__.get("_iris_obj")
|
|
184
|
+
if iris_obj is None:
|
|
185
|
+
iris_obj = runtime.create_object(iris_classname)
|
|
186
|
+
|
|
187
|
+
for field_name, model_field in msg_cls.__model_fields__.items():
|
|
188
|
+
if field_name not in message.__dict__:
|
|
189
|
+
continue
|
|
190
|
+
value = getattr(message, field_name)
|
|
191
|
+
materialized = _materialize_related_value(runtime, model_field.declared_type, value)
|
|
192
|
+
runtime.inject_iris_value(
|
|
193
|
+
iris_obj,
|
|
194
|
+
field_name,
|
|
195
|
+
materialized,
|
|
196
|
+
field_meta=model_field.field_info,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
message._iris_obj = iris_obj
|
|
200
|
+
try:
|
|
201
|
+
obj_id = runtime.get_object_id(iris_obj)
|
|
202
|
+
if obj_id:
|
|
203
|
+
message._pk = str(obj_id)
|
|
204
|
+
except Exception:
|
|
205
|
+
pass
|
|
206
|
+
return iris_obj
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def deserialize_persistent_message(serial: Any) -> Any:
|
|
210
|
+
iris_classname = get_iris_object_classname(serial)
|
|
211
|
+
if not iris_classname:
|
|
212
|
+
return serial
|
|
213
|
+
|
|
214
|
+
python_classname, python_classpath, strict = _resolve_python_message_metadata(
|
|
215
|
+
iris_classname
|
|
216
|
+
)
|
|
217
|
+
if not python_classname:
|
|
218
|
+
return serial
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
msg_cls = load_python_class(python_classname, python_classpath)
|
|
222
|
+
except (AttributeError, ModuleNotFoundError, PersistentMessageError) as exc:
|
|
223
|
+
if strict:
|
|
224
|
+
raise PersistentMessageError(
|
|
225
|
+
f"IRIS class {iris_classname!r} is marked as a PersistentMessage for "
|
|
226
|
+
f"Python class {python_classname!r}, but that Python class could not "
|
|
227
|
+
"be imported. Ensure the message class is importable, or register it "
|
|
228
|
+
"through CLASSES so migration writes IOP_PYTHON_CLASSPATH."
|
|
229
|
+
) from exc
|
|
230
|
+
return serial
|
|
231
|
+
|
|
232
|
+
if not is_persistent_message_class(msg_cls):
|
|
233
|
+
if strict:
|
|
234
|
+
raise PersistentMessageError(
|
|
235
|
+
f"IRIS class {iris_classname!r} maps to {python_classname!r}, "
|
|
236
|
+
"but that class is not a PersistentMessage subclass."
|
|
237
|
+
)
|
|
238
|
+
return serial
|
|
239
|
+
|
|
240
|
+
_prepare_message_class(msg_cls, iris_classname, registered=False)
|
|
241
|
+
|
|
242
|
+
known_pk = _safe_get_object_id(serial)
|
|
243
|
+
return _build_model_from_iris_obj(msg_cls, serial, known_pk=known_pk or "")
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def resolve_iris_classname(msg_cls: type) -> str:
|
|
247
|
+
python_classname = get_python_classname(msg_cls)
|
|
248
|
+
|
|
249
|
+
cached = _PYTHON_TO_IRIS_CACHE.get(python_classname)
|
|
250
|
+
if cached:
|
|
251
|
+
return cached
|
|
252
|
+
|
|
253
|
+
registered = getattr(msg_cls, "_iop_registered_classname", None)
|
|
254
|
+
if registered:
|
|
255
|
+
_cache_mapping(python_classname, registered)
|
|
256
|
+
return registered
|
|
257
|
+
|
|
258
|
+
explicit_classname = _explicit_meta_classname(msg_cls)
|
|
259
|
+
if explicit_classname:
|
|
260
|
+
_prepare_message_class(msg_cls, explicit_classname, registered=False)
|
|
261
|
+
return explicit_classname
|
|
262
|
+
|
|
263
|
+
iris_classname = python_classname_to_iris_classname(python_classname)
|
|
264
|
+
_prepare_message_class(msg_cls, iris_classname, registered=False)
|
|
265
|
+
return iris_classname
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def resolve_python_classname(iris_classname: str) -> Optional[str]:
|
|
269
|
+
python_classname, _python_classpath, _strict = _resolve_python_message_metadata(
|
|
270
|
+
iris_classname
|
|
271
|
+
)
|
|
272
|
+
return python_classname
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def load_python_class(python_classname: str, python_classpath: Optional[str] = None) -> type:
|
|
276
|
+
module_name, _, class_name = python_classname.rpartition(".")
|
|
277
|
+
if not module_name:
|
|
278
|
+
raise PersistentMessageError(
|
|
279
|
+
f"PersistentMessage Python classname {python_classname!r} is not fully qualified"
|
|
280
|
+
)
|
|
281
|
+
try:
|
|
282
|
+
module = importlib.import_module(module_name)
|
|
283
|
+
except ModuleNotFoundError as exc:
|
|
284
|
+
if not python_classpath or not _is_missing_target_module(exc, module_name):
|
|
285
|
+
raise
|
|
286
|
+
_prepend_sys_path(python_classpath)
|
|
287
|
+
module = importlib.import_module(module_name)
|
|
288
|
+
return getattr(module, class_name)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def get_python_classpath(klass: type) -> str:
|
|
292
|
+
try:
|
|
293
|
+
class_file = inspect.getfile(klass)
|
|
294
|
+
except TypeError:
|
|
295
|
+
return ""
|
|
296
|
+
|
|
297
|
+
if not class_file:
|
|
298
|
+
return ""
|
|
299
|
+
|
|
300
|
+
classpath = os.path.abspath(os.path.dirname(class_file))
|
|
301
|
+
module_parts = klass.__module__.split(".")
|
|
302
|
+
for _ in module_parts[:-1]:
|
|
303
|
+
classpath = os.path.dirname(classpath)
|
|
304
|
+
return classpath
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def get_iris_object_classname(obj: Any) -> Optional[str]:
|
|
308
|
+
for method_name in ("%ClassName", "_ClassName"):
|
|
309
|
+
try:
|
|
310
|
+
method = getattr(obj, method_name)
|
|
311
|
+
value = method(1)
|
|
312
|
+
if value:
|
|
313
|
+
return str(value)
|
|
314
|
+
except Exception:
|
|
315
|
+
pass
|
|
316
|
+
try:
|
|
317
|
+
value = obj.__class__.__name__
|
|
318
|
+
return str(value) if value else None
|
|
319
|
+
except Exception:
|
|
320
|
+
return None
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _safe_get_object_id(obj: Any) -> Optional[str]:
|
|
324
|
+
for method_name in ("_Id", "Id", "%Id"):
|
|
325
|
+
try:
|
|
326
|
+
method = getattr(obj, method_name)
|
|
327
|
+
obj_id = method()
|
|
328
|
+
if obj_id:
|
|
329
|
+
return str(obj_id)
|
|
330
|
+
except Exception:
|
|
331
|
+
pass
|
|
332
|
+
return None
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _ensure_schema(msg_cls: type, iris_classname: str) -> None:
|
|
336
|
+
if not getattr(msg_cls, "_auto_sync", False):
|
|
337
|
+
return
|
|
338
|
+
if getattr(msg_cls, "_sync_mode", DEFAULT_SYNC_MODE) != DEFAULT_SYNC_MODE:
|
|
339
|
+
raise PersistentMessageError(
|
|
340
|
+
f"{get_python_classname(msg_cls)} has auto_sync=True but mode="
|
|
341
|
+
f"{getattr(msg_cls, '_sync_mode', None)!r}. Runtime auto-sync is only allowed "
|
|
342
|
+
"with mode='extend'."
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
key = (msg_cls, iris_classname)
|
|
346
|
+
if key in _AUTO_SYNCED:
|
|
347
|
+
return
|
|
348
|
+
|
|
349
|
+
_prepare_message_class(msg_cls, iris_classname, registered=False)
|
|
350
|
+
msg_cls.sync_schema()
|
|
351
|
+
_AUTO_SYNCED.add(key)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _prepare_message_class(
|
|
355
|
+
msg_cls: type,
|
|
356
|
+
iris_classname: str,
|
|
357
|
+
*,
|
|
358
|
+
registered: bool,
|
|
359
|
+
) -> None:
|
|
360
|
+
_apply_persistent_message_defaults(msg_cls)
|
|
361
|
+
msg_cls._classname = iris_classname
|
|
362
|
+
if registered:
|
|
363
|
+
msg_cls._iop_registered_classname = iris_classname
|
|
364
|
+
_set_message_parameters(msg_cls)
|
|
365
|
+
_cache_mapping(get_python_classname(msg_cls), iris_classname)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _set_message_parameters(msg_cls: type) -> None:
|
|
369
|
+
parameters = dict(getattr(msg_cls, "_parameters", {}) or {})
|
|
370
|
+
parameters.update(
|
|
371
|
+
{
|
|
372
|
+
MESSAGE_KIND_PARAMETER: MESSAGE_KIND_VALUE,
|
|
373
|
+
PYTHON_CLASS_PARAMETER: get_python_classname(msg_cls),
|
|
374
|
+
PYTHON_CLASSPATH_PARAMETER: get_python_classpath(msg_cls),
|
|
375
|
+
}
|
|
376
|
+
)
|
|
377
|
+
msg_cls._parameters = parameters
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _cache_mapping(python_classname: str, iris_classname: str) -> None:
|
|
381
|
+
_PYTHON_TO_IRIS_CACHE[python_classname] = iris_classname
|
|
382
|
+
_IRIS_TO_PYTHON_CACHE[iris_classname] = python_classname
|
|
383
|
+
_IRIS_TO_PYTHON_STRICT_CACHE[iris_classname] = True
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _resolve_python_message_metadata(
|
|
387
|
+
iris_classname: str,
|
|
388
|
+
) -> tuple[Optional[str], Optional[str], bool]:
|
|
389
|
+
cached = _IRIS_TO_PYTHON_CACHE.get(iris_classname)
|
|
390
|
+
if cached:
|
|
391
|
+
return (
|
|
392
|
+
cached,
|
|
393
|
+
_IRIS_TO_PYTHON_CLASSPATH_CACHE.get(iris_classname),
|
|
394
|
+
_IRIS_TO_PYTHON_STRICT_CACHE.get(iris_classname, True),
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
kind = get_iris_class_parameter(iris_classname, MESSAGE_KIND_PARAMETER)
|
|
398
|
+
python_classname = get_iris_class_parameter(iris_classname, PYTHON_CLASS_PARAMETER)
|
|
399
|
+
python_classpath = get_iris_class_parameter(iris_classname, PYTHON_CLASSPATH_PARAMETER)
|
|
400
|
+
strict = kind == MESSAGE_KIND_VALUE or bool(python_classname)
|
|
401
|
+
|
|
402
|
+
if not python_classname:
|
|
403
|
+
python_classname = iris_classname_to_python_classname(iris_classname)
|
|
404
|
+
|
|
405
|
+
if python_classname and strict:
|
|
406
|
+
_cache_mapping(python_classname, iris_classname)
|
|
407
|
+
if python_classpath:
|
|
408
|
+
_IRIS_TO_PYTHON_CLASSPATH_CACHE[iris_classname] = python_classpath
|
|
409
|
+
|
|
410
|
+
return python_classname, python_classpath, strict
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def get_iris_class_parameter(
|
|
414
|
+
iris_classname: str,
|
|
415
|
+
parameter_name: str,
|
|
416
|
+
) -> Optional[str]:
|
|
417
|
+
key = (iris_classname, parameter_name)
|
|
418
|
+
if key in _IRIS_PARAMETER_CACHE:
|
|
419
|
+
return _IRIS_PARAMETER_CACHE[key]
|
|
420
|
+
|
|
421
|
+
value = None
|
|
422
|
+
runtime = get_runtime()
|
|
423
|
+
for method_name in ("_GetParameter", "%GetParameter"):
|
|
424
|
+
try:
|
|
425
|
+
raw_value = runtime.call_classmethod(
|
|
426
|
+
iris_classname,
|
|
427
|
+
method_name,
|
|
428
|
+
parameter_name,
|
|
429
|
+
)
|
|
430
|
+
except Exception:
|
|
431
|
+
continue
|
|
432
|
+
if raw_value:
|
|
433
|
+
value = str(raw_value)
|
|
434
|
+
break
|
|
435
|
+
|
|
436
|
+
if value is not None:
|
|
437
|
+
_IRIS_PARAMETER_CACHE[key] = value
|
|
438
|
+
return value
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def _is_missing_target_module(exc: ModuleNotFoundError, module_name: str) -> bool:
|
|
442
|
+
missing_name = getattr(exc, "name", None)
|
|
443
|
+
return bool(
|
|
444
|
+
missing_name
|
|
445
|
+
and (module_name == missing_name or module_name.startswith(f"{missing_name}."))
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def _encode_iris_identifier(value: str) -> str:
|
|
450
|
+
if not value:
|
|
451
|
+
raise ValueError("IRIS classname parts cannot be empty")
|
|
452
|
+
|
|
453
|
+
encoded: list[str] = []
|
|
454
|
+
for char in value:
|
|
455
|
+
if char == "z":
|
|
456
|
+
encoded.append("zz")
|
|
457
|
+
elif char == "_":
|
|
458
|
+
encoded.append("zU")
|
|
459
|
+
elif char.isascii() and char.isalnum():
|
|
460
|
+
encoded.append(char)
|
|
461
|
+
else:
|
|
462
|
+
encoded.append(f"zX{ord(char):X}z")
|
|
463
|
+
|
|
464
|
+
return "".join(encoded)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def _decode_iris_identifier(value: str) -> str:
|
|
468
|
+
decoded: list[str] = []
|
|
469
|
+
index = 0
|
|
470
|
+
while index < len(value):
|
|
471
|
+
char = value[index]
|
|
472
|
+
if char != "z":
|
|
473
|
+
decoded.append(char)
|
|
474
|
+
index += 1
|
|
475
|
+
continue
|
|
476
|
+
|
|
477
|
+
if index + 1 >= len(value):
|
|
478
|
+
decoded.append(char)
|
|
479
|
+
index += 1
|
|
480
|
+
continue
|
|
481
|
+
|
|
482
|
+
marker = value[index + 1]
|
|
483
|
+
if marker == "z":
|
|
484
|
+
decoded.append("z")
|
|
485
|
+
index += 2
|
|
486
|
+
elif marker == "U":
|
|
487
|
+
decoded.append("_")
|
|
488
|
+
index += 2
|
|
489
|
+
elif marker == "X":
|
|
490
|
+
end = value.find("z", index + 2)
|
|
491
|
+
if end == -1:
|
|
492
|
+
decoded.append(char)
|
|
493
|
+
index += 1
|
|
494
|
+
continue
|
|
495
|
+
try:
|
|
496
|
+
decoded.append(chr(int(value[index + 2 : end], 16)))
|
|
497
|
+
except ValueError:
|
|
498
|
+
decoded.append(char)
|
|
499
|
+
index += 1
|
|
500
|
+
continue
|
|
501
|
+
index = end + 1
|
|
502
|
+
else:
|
|
503
|
+
decoded.append(char)
|
|
504
|
+
index += 1
|
|
505
|
+
|
|
506
|
+
return "".join(decoded)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def _prepend_sys_path(path: str) -> None:
|
|
510
|
+
normalized_path = os.path.abspath(os.path.normpath(path))
|
|
511
|
+
while normalized_path in sys.path:
|
|
512
|
+
sys.path.remove(normalized_path)
|
|
513
|
+
sys.path.insert(0, normalized_path)
|
|
@@ -13,6 +13,10 @@ from pydantic import TypeAdapter
|
|
|
13
13
|
|
|
14
14
|
from . import _iris
|
|
15
15
|
from ._message import _Message, _PydanticMessage
|
|
16
|
+
from ._persistent_message import (
|
|
17
|
+
is_persistent_message_class,
|
|
18
|
+
register_persistent_message_class,
|
|
19
|
+
)
|
|
16
20
|
|
|
17
21
|
class _Utils():
|
|
18
22
|
@staticmethod
|
|
@@ -84,6 +88,17 @@ class _Utils():
|
|
|
84
88
|
"""
|
|
85
89
|
_Utils.raise_on_error(_iris.get_iris().cls('IOP.Message.JSONSchema').Import(schema_str,categories,schema_name))
|
|
86
90
|
|
|
91
|
+
@staticmethod
|
|
92
|
+
def register_persistent_message(msg_cls: type, iris_classname: str, sync_schema: bool = True):
|
|
93
|
+
"""
|
|
94
|
+
Register a PersistentMessage as a native IRIS message body class.
|
|
95
|
+
|
|
96
|
+
:param msg_cls: PersistentMessage subclass to register
|
|
97
|
+
:param iris_classname: IRIS class name to generate, usually the CLASSES key
|
|
98
|
+
:param sync_schema: when True, sync the IRIS schema immediately
|
|
99
|
+
"""
|
|
100
|
+
register_persistent_message_class(msg_cls, iris_classname, sync_schema=sync_schema)
|
|
101
|
+
|
|
87
102
|
@staticmethod
|
|
88
103
|
def get_python_settings() -> Tuple[str,str,str]:
|
|
89
104
|
import iris_utils._cli
|
|
@@ -384,6 +399,9 @@ class _Utils():
|
|
|
384
399
|
"""
|
|
385
400
|
for key, value in class_items.items():
|
|
386
401
|
if inspect.isclass(value):
|
|
402
|
+
if is_persistent_message_class(value):
|
|
403
|
+
_Utils.register_persistent_message(value, key)
|
|
404
|
+
continue
|
|
387
405
|
path = None
|
|
388
406
|
if root_path:
|
|
389
407
|
path = root_path
|
|
@@ -401,6 +419,10 @@ class _Utils():
|
|
|
401
419
|
elif isinstance(value,dict):
|
|
402
420
|
# if the dict has a key 'path' and a key 'module' and a key 'class'
|
|
403
421
|
if 'path' in value and 'module' in value and 'class' in value:
|
|
422
|
+
msg_cls = _Utils._try_import_class(value['module'], value['class'], value['path'])
|
|
423
|
+
if msg_cls is not None and is_persistent_message_class(msg_cls):
|
|
424
|
+
_Utils.register_persistent_message(msg_cls, key)
|
|
425
|
+
continue
|
|
404
426
|
# register the component
|
|
405
427
|
_Utils.register_component(value['module'],value['class'],value['path'],1,key)
|
|
406
428
|
# if the dict has a key 'path' and a key 'package'
|
|
@@ -418,6 +440,31 @@ class _Utils():
|
|
|
418
440
|
else:
|
|
419
441
|
raise ValueError(f"Invalid value for {key}.")
|
|
420
442
|
|
|
443
|
+
@staticmethod
|
|
444
|
+
def _try_import_class(module_name: str, class_name: str, path: str):
|
|
445
|
+
remove_path = False
|
|
446
|
+
try:
|
|
447
|
+
path = os.path.abspath(os.path.normpath(path))
|
|
448
|
+
fullpath = _Utils.guess_path(module_name, path)
|
|
449
|
+
if path not in sys.path:
|
|
450
|
+
sys.path.insert(0, path)
|
|
451
|
+
remove_path = True
|
|
452
|
+
else:
|
|
453
|
+
remove_path = False
|
|
454
|
+
try:
|
|
455
|
+
module = _Utils.import_module_from_path(module_name, fullpath)
|
|
456
|
+
except Exception:
|
|
457
|
+
module = importlib.import_module(module_name)
|
|
458
|
+
return getattr(module, class_name)
|
|
459
|
+
except Exception:
|
|
460
|
+
return None
|
|
461
|
+
finally:
|
|
462
|
+
try:
|
|
463
|
+
if remove_path:
|
|
464
|
+
sys.path.remove(path)
|
|
465
|
+
except Exception:
|
|
466
|
+
pass
|
|
467
|
+
|
|
421
468
|
@staticmethod
|
|
422
469
|
def set_productions_settings(production_list,root_path=None):
|
|
423
470
|
"""
|
|
@@ -582,4 +629,4 @@ class _Utils():
|
|
|
582
629
|
module_path = module.replace(".", os.sep)
|
|
583
630
|
else:
|
|
584
631
|
module_path = module.replace(".", os.sep) + ".py"
|
|
585
|
-
return os.path.join(path, module_path)
|
|
632
|
+
return os.path.join(path, module_path)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris_pex_embedded_python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.1b1
|
|
4
4
|
Summary: Iris Interoperability based on Embedded Python
|
|
5
5
|
Author-email: grongier <guillaume.rongier@intersystems.com>
|
|
6
6
|
License: MIT License
|
|
@@ -34,19 +34,17 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
34
34
|
Classifier: Intended Audience :: Developers
|
|
35
35
|
Classifier: License :: OSI Approved :: MIT License
|
|
36
36
|
Classifier: Operating System :: OS Independent
|
|
37
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
38
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
39
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
40
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
41
37
|
Classifier: Programming Language :: Python :: 3.10
|
|
42
38
|
Classifier: Programming Language :: Python :: 3.11
|
|
43
39
|
Classifier: Programming Language :: Python :: 3.12
|
|
44
40
|
Classifier: Topic :: Utilities
|
|
41
|
+
Requires-Python: >=3.10
|
|
45
42
|
Description-Content-Type: text/markdown
|
|
46
43
|
License-File: LICENSE
|
|
47
44
|
Requires-Dist: pydantic>=2.0.0
|
|
48
45
|
Requires-Dist: xmltodict>=0.12.0
|
|
49
46
|
Requires-Dist: iris-embedded-python-wrapper>=0.0.6
|
|
47
|
+
Requires-Dist: iris-persistence>=0.1.0
|
|
50
48
|
Requires-Dist: jsonpath-ng>=1.7.0
|
|
51
49
|
Requires-Dist: debugpy>=1.8.0
|
|
52
50
|
Requires-Dist: requests>=2.24.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_cli.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_common.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_director.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/grongier/pex/_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_async_request.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_host.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_operation.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_process.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_business_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_decorators.py
RENAMED
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_director_protocol.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_generator_request.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_inbound_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_log_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_message_validator.py
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_outbound_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/_serialization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Common.cls
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Director.cls
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Message.cls
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Projection.cls
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Test.cls
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Utils.cls
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/cls/IOP/Wrapper.cls
RENAMED
|
File without changes
|
{iris_pex_embedded_python-3.6.1b1 → iris_pex_embedded_python-3.7.1b1}/src/iop/wsgi/handlers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|