iris-pex-embedded-python 4.0.0b6__tar.gz → 4.0.0b7__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-4.0.0b6/src/iris_pex_embedded_python.egg-info → iris_pex_embedded_python-4.0.0b7}/PKG-INFO +2 -2
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/README.md +2 -2
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/pyproject.toml +1 -1
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/__init__.py +2 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Common.cls +11 -2
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/PrivateSession/Duplex.cls +1 -1
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Utils.cls +7 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/business_operation.py +6 -5
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/business_process.py +6 -5
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/business_service.py +6 -5
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/common.py +65 -15
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/decorators.py +1 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/dispatch.py +151 -16
- iris_pex_embedded_python-4.0.0b7/src/iop/migration/manifest.py +534 -0
- iris_pex_embedded_python-4.0.0b7/src/iop/migration/plans.py +80 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/migration/utils.py +143 -227
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/component.py +1 -7
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/declarations.py +0 -9
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/declarative.py +1 -4
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/diff.py +0 -1
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/import_.py +1 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/model.py +0 -4
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/rendering.py +2 -4
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/types.py +4 -9
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7/src/iris_pex_embedded_python.egg-info}/PKG-INFO +2 -2
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iris_pex_embedded_python.egg-info/SOURCES.txt +1 -0
- iris_pex_embedded_python-4.0.0b6/src/iop/migration/plans.py +0 -182
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/LICENSE +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/setup.cfg +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/__main__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cli/__init__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cli/formatting.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cli/main.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cli/parser.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cli/types.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/BusinessOperation.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/BusinessProcess.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/BusinessService.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Director.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Duplex/Operation.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Duplex/Process.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Duplex/Service.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Generator/Message/Ack.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Generator/Message/Poll.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Generator/Message/Start.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Generator/Message/StartPickle.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Generator/Message/Stop.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/InboundAdapter.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Message/JSONSchema.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Message.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/OutboundAdapter.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/PickleMessage.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/PrivateSession/Message/Ack.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/PrivateSession/Message/Poll.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/PrivateSession/Message/Start.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/PrivateSession/Message/Stop.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Projection.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Service/Remote/Handler.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Service/Remote/Rest/v1.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Test.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Wrapper.cls +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/__init__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/async_request.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/business_host.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/debugpy.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/generator_request.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/inbound_adapter.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/log_manager.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/outbound_adapter.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/polling_business_service.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/private_session_duplex.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/private_session_process.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/settings.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/__init__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/base.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/persistent.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/serialization.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/validation.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/migration/__init__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/migration/io.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/__init__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/actions.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/common.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/inspection.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/reconstruction.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/runtime.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/production/validation.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/__init__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/director.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/environment.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/iris.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/local.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/protocol.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/remote/__init__.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/remote/client.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/remote/director.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/remote/migration.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/remote/settings.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/runtime/remote/setup.py +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iris_pex_embedded_python.egg-info/dependency_links.txt +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iris_pex_embedded_python.egg-info/entry_points.txt +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iris_pex_embedded_python.egg-info/requires.txt +0 -0
- {iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/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: 4.0.
|
|
3
|
+
Version: 4.0.0b7
|
|
4
4
|
Summary: Iris Interoperability based on Embedded Python
|
|
5
5
|
Author-email: grongier <guillaume.rongier@intersystems.com>
|
|
6
6
|
License: MIT License
|
|
@@ -86,6 +86,6 @@ pip install iris-pex-embedded-python
|
|
|
86
86
|
|
|
87
87
|
## Getting Started
|
|
88
88
|
|
|
89
|
-
If you're new to this project, begin by reading the [installation guide](https://grongierisc.github.io/interoperability-embedded-python/getting-started/installation). Then, follow the [first steps](https://grongierisc.github.io/interoperability-embedded-python/getting-started/first-steps) to create your first
|
|
89
|
+
If you're new to this project, begin by reading the [installation guide](https://grongierisc.github.io/interoperability-embedded-python/getting-started/installation). Then, follow the [first steps](https://grongierisc.github.io/interoperability-embedded-python/getting-started/first-steps) to create your first Python-authored production.
|
|
90
90
|
|
|
91
91
|
Happy coding!
|
|
@@ -32,6 +32,6 @@ pip install iris-pex-embedded-python
|
|
|
32
32
|
|
|
33
33
|
## Getting Started
|
|
34
34
|
|
|
35
|
-
If you're new to this project, begin by reading the [installation guide](https://grongierisc.github.io/interoperability-embedded-python/getting-started/installation). Then, follow the [first steps](https://grongierisc.github.io/interoperability-embedded-python/getting-started/first-steps) to create your first
|
|
35
|
+
If you're new to this project, begin by reading the [installation guide](https://grongierisc.github.io/interoperability-embedded-python/getting-started/installation). Then, follow the [first steps](https://grongierisc.github.io/interoperability-embedded-python/getting-started/first-steps) to create your first Python-authored production.
|
|
36
36
|
|
|
37
|
-
Happy coding!
|
|
37
|
+
Happy coding!
|
|
@@ -16,6 +16,7 @@ from iop.messages.base import (
|
|
|
16
16
|
_PydanticMessage,
|
|
17
17
|
_PydanticPickleMessage,
|
|
18
18
|
)
|
|
19
|
+
from iop.messages.decorators import handler as handler
|
|
19
20
|
from iop.messages.persistent import Field as Field
|
|
20
21
|
from iop.messages.persistent import Model as Model
|
|
21
22
|
from iop.messages.persistent import _PersistentMessage
|
|
@@ -85,6 +86,7 @@ __all__ = [
|
|
|
85
86
|
"Utils",
|
|
86
87
|
"bind_component",
|
|
87
88
|
"controls",
|
|
89
|
+
"handler",
|
|
88
90
|
"list_bindings",
|
|
89
91
|
"register_component",
|
|
90
92
|
"setting",
|
{iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Common.cls
RENAMED
|
@@ -187,7 +187,7 @@ Method OnTearDown() As %Status
|
|
|
187
187
|
set tSC = $$$OK
|
|
188
188
|
if $isObject(..%class) {
|
|
189
189
|
try {
|
|
190
|
-
do ..%class."_dispatch_on_tear_down"()
|
|
190
|
+
do ..%class."_dispatch_on_tear_down"($this)
|
|
191
191
|
} catch ex {
|
|
192
192
|
set tSC = ex.AsStatus()
|
|
193
193
|
}
|
|
@@ -313,7 +313,7 @@ ClassMethod OnGetConnections(
|
|
|
313
313
|
do pItem.GetModifiedSetting("%classname", .tClassname)
|
|
314
314
|
do pItem.GetModifiedSetting("%module", .tModule)
|
|
315
315
|
|
|
316
|
-
//
|
|
316
|
+
// Prepare the Python import path for connection discovery.
|
|
317
317
|
if tClasspaths '="" {
|
|
318
318
|
set sys = ##class(%SYS.Python).Import("sys")
|
|
319
319
|
set delimiter = $s($system.Version.GetOS()="Windows":";",1:":")
|
|
@@ -329,7 +329,14 @@ ClassMethod OnGetConnections(
|
|
|
329
329
|
set builtins = ##class(%SYS.Python).Import("builtins")
|
|
330
330
|
set module = ##class(%SYS.Python).Import(tModule)
|
|
331
331
|
set class = builtins.getattr(module, tClassname)
|
|
332
|
+
// Allocate without calling Python __init__. Connection discovery must not
|
|
333
|
+
// run user startup code; IoP uses on_init() as the lifecycle hook.
|
|
332
334
|
set tClass = class."__new__"(class)
|
|
335
|
+
Try {
|
|
336
|
+
do tClass."_warn_if_custom_init"()
|
|
337
|
+
}
|
|
338
|
+
Catch ex {
|
|
339
|
+
}
|
|
333
340
|
|
|
334
341
|
set tPythonList = tClass."on_get_connections"()
|
|
335
342
|
set tPythonListLen = tPythonList."__len__"()
|
|
@@ -535,6 +542,8 @@ Method CreateClassInstance(module As %SYS.Python) As %SYS.Python [ Private ]
|
|
|
535
542
|
{
|
|
536
543
|
set builtins = ##class(%SYS.Python).Import("builtins")
|
|
537
544
|
set class = builtins.getattr(module, ..%classname)
|
|
545
|
+
// Intentionally bypass Python __init__. IRIS applies handles/settings and
|
|
546
|
+
// then calls on_init() through _dispatch_on_init().
|
|
538
547
|
quit class."__new__"(class)
|
|
539
548
|
}
|
|
540
549
|
|
|
@@ -250,7 +250,7 @@ Method OnTearDown() As %Status
|
|
|
250
250
|
#dim tSC As %Status = $$$OK
|
|
251
251
|
try {
|
|
252
252
|
If ..%InPrivateSession Set tSC=..StopPrivateSession() Quit:$$$ISERR(tSC)
|
|
253
|
-
do ..%class."_dispatch_on_tear_down"()
|
|
253
|
+
do ..%class."_dispatch_on_tear_down"($this)
|
|
254
254
|
} catch {
|
|
255
255
|
Set tSC=$$$EnsSystemError
|
|
256
256
|
}
|
{iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/cls/IOP/Utils.cls
RENAMED
|
@@ -281,7 +281,14 @@ ClassMethod GetRemoteClassInfo(
|
|
|
281
281
|
|
|
282
282
|
// Get the class
|
|
283
283
|
set class = builtins.getattr(module, pRemoteClassname)
|
|
284
|
+
// Allocate without calling Python __init__. Registration only reads
|
|
285
|
+
// metadata; runtime startup belongs in on_init().
|
|
284
286
|
set tClass = class."__new__"(class)
|
|
287
|
+
Try {
|
|
288
|
+
Do tClass."_warn_if_custom_init"()
|
|
289
|
+
}
|
|
290
|
+
Catch ex {
|
|
291
|
+
}
|
|
285
292
|
|
|
286
293
|
If $IsObject(tClass) {
|
|
287
294
|
#; List of information about the class as a whole - $lb(SuperClass, Description, InfoURL, IconURL, Adapter)
|
|
@@ -55,11 +55,12 @@ class _BusinessOperation(_BusinessHost):
|
|
|
55
55
|
self.Adapter = self.adapter = handle_partner
|
|
56
56
|
return
|
|
57
57
|
|
|
58
|
-
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
59
|
-
"""For internal use only."""
|
|
60
|
-
|
|
61
|
-
self
|
|
62
|
-
|
|
58
|
+
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
59
|
+
"""For internal use only."""
|
|
60
|
+
self._log_custom_init_warning()
|
|
61
|
+
create_dispatch(self)
|
|
62
|
+
self.on_init()
|
|
63
|
+
return
|
|
63
64
|
|
|
64
65
|
@input_deserializer
|
|
65
66
|
@output_serializer
|
|
@@ -165,11 +165,12 @@ class _BusinessProcess(_BusinessHost):
|
|
|
165
165
|
self._save_persistent_properties(host_object)
|
|
166
166
|
return
|
|
167
167
|
|
|
168
|
-
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
169
|
-
"""For internal use only."""
|
|
170
|
-
self.
|
|
171
|
-
|
|
172
|
-
self
|
|
168
|
+
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
169
|
+
"""For internal use only."""
|
|
170
|
+
self._log_custom_init_warning()
|
|
171
|
+
self._restore_persistent_properties(host_object)
|
|
172
|
+
create_dispatch(self)
|
|
173
|
+
self.on_init()
|
|
173
174
|
self._save_persistent_properties(host_object)
|
|
174
175
|
return
|
|
175
176
|
|
|
@@ -34,11 +34,12 @@ class _BusinessService(_BusinessHost):
|
|
|
34
34
|
Adapter = adapter = None
|
|
35
35
|
_wait_for_next_call_interval = False
|
|
36
36
|
|
|
37
|
-
def _dispatch_on_init(self, host_object) -> None:
|
|
38
|
-
"""For internal use only."""
|
|
39
|
-
self.
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
def _dispatch_on_init(self, host_object) -> None:
|
|
38
|
+
"""For internal use only."""
|
|
39
|
+
self._log_custom_init_warning()
|
|
40
|
+
self.on_init()
|
|
41
|
+
|
|
42
|
+
return
|
|
42
43
|
|
|
43
44
|
def on_message(self, request=None):
|
|
44
45
|
"""Handle a message received by the business service.
|
{iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/components/common.py
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
import traceback
|
|
3
|
-
|
|
4
|
-
from
|
|
2
|
+
import traceback
|
|
3
|
+
import warnings
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from types import UnionType
|
|
5
6
|
from typing import (
|
|
6
7
|
Annotated,
|
|
7
8
|
Any,
|
|
@@ -133,8 +134,17 @@ def _is_setting_member(name: str, value: Any) -> bool:
|
|
|
133
134
|
return not (
|
|
134
135
|
inspect.ismethod(value) or inspect.isfunction(value) or inspect.isclass(value)
|
|
135
136
|
)
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _custom_init_owner(cls: type) -> type | None:
|
|
140
|
+
for base in inspect.getmro(cls):
|
|
141
|
+
init = base.__dict__.get("__init__", _NO_VALUE)
|
|
142
|
+
if init is _NO_VALUE or init is object.__init__:
|
|
143
|
+
continue
|
|
144
|
+
return base
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
|
|
138
148
|
class _Common:
|
|
139
149
|
"""Base class that defines common methods for all component types.
|
|
140
150
|
|
|
@@ -144,13 +154,52 @@ class _Common:
|
|
|
144
154
|
|
|
145
155
|
INFO_URL: ClassVar[str]
|
|
146
156
|
ICON_URL: ClassVar[str]
|
|
147
|
-
iris_handle: Any = None
|
|
148
|
-
_log_to_console: bool = False
|
|
149
|
-
_logger: logging.Logger | None = None
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
iris_handle: Any = None
|
|
158
|
+
_log_to_console: bool = False
|
|
159
|
+
_logger: logging.Logger | None = None
|
|
160
|
+
|
|
161
|
+
def __init_subclass__(cls, **kwargs: Any) -> None:
|
|
162
|
+
super().__init_subclass__(**kwargs)
|
|
163
|
+
cls._warn_if_custom_init_defined(stacklevel=2)
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def _custom_init_warning_message(cls) -> str | None:
|
|
167
|
+
if _custom_init_owner(cls) is None:
|
|
168
|
+
return None
|
|
169
|
+
classname = f"{cls.__module__}.{cls.__qualname__}"
|
|
170
|
+
return (
|
|
171
|
+
f"{classname} defines or inherits __init__(), but IoP/IRIS "
|
|
172
|
+
"instantiates components with __new__() and does not call "
|
|
173
|
+
"__init__(). Move startup logic to on_init(); use class attributes "
|
|
174
|
+
"or iop.Setting for configurable defaults."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
@classmethod
|
|
178
|
+
def _warn_if_custom_init_defined(cls, stacklevel: int = 2) -> None:
|
|
179
|
+
message = cls._custom_init_warning_message()
|
|
180
|
+
if message is None:
|
|
181
|
+
return
|
|
182
|
+
warnings.warn(message, RuntimeWarning, stacklevel=stacklevel)
|
|
183
|
+
|
|
184
|
+
def _log_custom_init_warning(self) -> None:
|
|
185
|
+
message = self.__class__._custom_init_warning_message()
|
|
186
|
+
if message is None:
|
|
187
|
+
return
|
|
188
|
+
try:
|
|
189
|
+
self.log_warning(message)
|
|
190
|
+
except Exception:
|
|
191
|
+
try:
|
|
192
|
+
warnings.warn(message, RuntimeWarning, stacklevel=2)
|
|
193
|
+
except Exception:
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
def _warn_if_custom_init(self) -> None:
|
|
197
|
+
"""Metadata-safe warning hook for ObjectScript __new__ allocations."""
|
|
198
|
+
self._log_custom_init_warning()
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def get_adapter_type() -> str | None:
|
|
202
|
+
"""Get the adapter type for this component. Override in subclasses."""
|
|
154
203
|
return None
|
|
155
204
|
|
|
156
205
|
@property
|
|
@@ -191,9 +240,10 @@ class _Common:
|
|
|
191
240
|
def _dispatch_on_connected(self, host_object: Any) -> None:
|
|
192
241
|
self.on_connected()
|
|
193
242
|
|
|
194
|
-
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
195
|
-
"""Initialize component when started."""
|
|
196
|
-
self.
|
|
243
|
+
def _dispatch_on_init(self, host_object: Any) -> None:
|
|
244
|
+
"""Initialize component when started."""
|
|
245
|
+
self._log_custom_init_warning()
|
|
246
|
+
self.on_init()
|
|
197
247
|
|
|
198
248
|
def _dispatch_on_tear_down(self, host_object: Any) -> None:
|
|
199
249
|
self.on_tear_down()
|
{iris_pex_embedded_python-4.0.0b6 → iris_pex_embedded_python-4.0.0b7}/src/iop/messages/dispatch.py
RENAMED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from dataclasses import dataclass
|
|
1
4
|
from inspect import Parameter, signature
|
|
2
5
|
from typing import Any
|
|
3
6
|
|
|
@@ -29,6 +32,34 @@ _PICKLE_MESSAGE_CLASSES = {
|
|
|
29
32
|
"IOP.PickleMessage",
|
|
30
33
|
"IOP.Generator.Message.StartPickle",
|
|
31
34
|
}
|
|
35
|
+
_HANDLER_ATTRIBUTE = "__iop_handler_message__"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class _DispatchCandidate:
|
|
40
|
+
message: str
|
|
41
|
+
method: str
|
|
42
|
+
source: str
|
|
43
|
+
priority: int
|
|
44
|
+
index: int
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def handler(message_type: Any) -> Callable[[Callable], Callable]:
|
|
48
|
+
"""Declare a method as the handler for a message type.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
message_type: The message class, fully qualified class name string, or
|
|
52
|
+
IRIS object instance this method handles.
|
|
53
|
+
"""
|
|
54
|
+
message = _message_class_name(message_type)
|
|
55
|
+
if message is None:
|
|
56
|
+
raise TypeError("handler() requires a message class or class name")
|
|
57
|
+
|
|
58
|
+
def _handler(method: Callable) -> Callable:
|
|
59
|
+
setattr(method, _HANDLER_ATTRIBUTE, message)
|
|
60
|
+
return method
|
|
61
|
+
|
|
62
|
+
return _handler
|
|
32
63
|
|
|
33
64
|
|
|
34
65
|
def dispatch_serializer(message: Any, is_generator: bool = False) -> Any:
|
|
@@ -119,7 +150,7 @@ def dispatch_message(host: Any, request: Any) -> Any:
|
|
|
119
150
|
|
|
120
151
|
for msg, method in host.DISPATCH:
|
|
121
152
|
if msg == module + "." + classname:
|
|
122
|
-
|
|
153
|
+
return getattr(host, method)(request)
|
|
123
154
|
|
|
124
155
|
return getattr(host, call)(request)
|
|
125
156
|
|
|
@@ -129,14 +160,35 @@ def create_dispatch(host: Any) -> None:
|
|
|
129
160
|
The dispatch table consists of tuples of (fully_qualified_class_name, method_name).
|
|
130
161
|
Only methods that take a single typed parameter are considered as handlers.
|
|
131
162
|
"""
|
|
132
|
-
|
|
163
|
+
candidates: list[_DispatchCandidate] = []
|
|
164
|
+
index = 0
|
|
165
|
+
|
|
166
|
+
for message, method in _decorated_dispatch(host):
|
|
167
|
+
candidates.append(
|
|
168
|
+
_DispatchCandidate(message, method, "@handler", priority=0, index=index)
|
|
169
|
+
)
|
|
170
|
+
index += 1
|
|
171
|
+
|
|
172
|
+
for message, method in _declared_dispatch(host):
|
|
173
|
+
candidates.append(
|
|
174
|
+
_DispatchCandidate(message, method, "DISPATCH", priority=1, index=index)
|
|
175
|
+
)
|
|
176
|
+
index += 1
|
|
133
177
|
|
|
134
178
|
for method_name in get_callable_methods(host):
|
|
179
|
+
if _handler_message(getattr(host, method_name)) is not None:
|
|
180
|
+
continue
|
|
135
181
|
handler_info = get_handler_info(host, method_name)
|
|
136
|
-
if handler_info
|
|
137
|
-
|
|
182
|
+
if handler_info:
|
|
183
|
+
message, method = handler_info
|
|
184
|
+
candidates.append(
|
|
185
|
+
_DispatchCandidate(
|
|
186
|
+
message, method, "typed method", priority=1, index=index
|
|
187
|
+
)
|
|
188
|
+
)
|
|
189
|
+
index += 1
|
|
138
190
|
|
|
139
|
-
host.DISPATCH =
|
|
191
|
+
host.DISPATCH = _deduplicate_dispatch(host, candidates)
|
|
140
192
|
|
|
141
193
|
|
|
142
194
|
def _declared_dispatch(host: Any) -> list[tuple[str, str]]:
|
|
@@ -150,6 +202,82 @@ def _declared_dispatch(host: Any) -> list[tuple[str, str]]:
|
|
|
150
202
|
return []
|
|
151
203
|
|
|
152
204
|
|
|
205
|
+
def _decorated_dispatch(host: Any) -> list[tuple[str, str]]:
|
|
206
|
+
dispatch = []
|
|
207
|
+
for method_name in dir(host):
|
|
208
|
+
method = getattr(host, method_name)
|
|
209
|
+
if not callable(method):
|
|
210
|
+
continue
|
|
211
|
+
message = _handler_message(method)
|
|
212
|
+
if message is not None:
|
|
213
|
+
dispatch.append((message, method_name))
|
|
214
|
+
return dispatch
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _deduplicate_dispatch(
|
|
218
|
+
host: Any, candidates: list[_DispatchCandidate]
|
|
219
|
+
) -> list[tuple[str, str]]:
|
|
220
|
+
selected: dict[str, _DispatchCandidate] = {}
|
|
221
|
+
|
|
222
|
+
for candidate in candidates:
|
|
223
|
+
current = selected.get(candidate.message)
|
|
224
|
+
if current is None:
|
|
225
|
+
selected[candidate.message] = candidate
|
|
226
|
+
continue
|
|
227
|
+
|
|
228
|
+
if current.method == candidate.method:
|
|
229
|
+
if _is_higher_priority(candidate, current):
|
|
230
|
+
selected[candidate.message] = candidate
|
|
231
|
+
continue
|
|
232
|
+
|
|
233
|
+
if _is_higher_priority(candidate, current):
|
|
234
|
+
_log_duplicate_mapping(host, kept=candidate, discarded=current)
|
|
235
|
+
selected[candidate.message] = candidate
|
|
236
|
+
else:
|
|
237
|
+
_log_duplicate_mapping(host, kept=current, discarded=candidate)
|
|
238
|
+
|
|
239
|
+
return [
|
|
240
|
+
(candidate.message, candidate.method)
|
|
241
|
+
for candidate in sorted(selected.values(), key=lambda item: item.index)
|
|
242
|
+
]
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _is_higher_priority(
|
|
246
|
+
candidate: _DispatchCandidate, current: _DispatchCandidate
|
|
247
|
+
) -> bool:
|
|
248
|
+
if candidate.priority != current.priority:
|
|
249
|
+
return candidate.priority < current.priority
|
|
250
|
+
return candidate.index > current.index
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _log_duplicate_mapping(
|
|
254
|
+
host: Any, kept: _DispatchCandidate, discarded: _DispatchCandidate
|
|
255
|
+
) -> None:
|
|
256
|
+
message = (
|
|
257
|
+
f"Duplicate dispatch mapping for {kept.message}: "
|
|
258
|
+
f"keeping {kept.method} from {kept.source}; "
|
|
259
|
+
f"discarding {discarded.method} from {discarded.source}."
|
|
260
|
+
)
|
|
261
|
+
log_warning = getattr(host, "log_warning", None)
|
|
262
|
+
if callable(log_warning):
|
|
263
|
+
try:
|
|
264
|
+
log_warning(message)
|
|
265
|
+
return
|
|
266
|
+
except Exception:
|
|
267
|
+
pass
|
|
268
|
+
|
|
269
|
+
logging.getLogger(__name__).warning(message)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _handler_message(method: Any) -> str | None:
|
|
273
|
+
message = getattr(method, _HANDLER_ATTRIBUTE, None)
|
|
274
|
+
if message is not None:
|
|
275
|
+
return message
|
|
276
|
+
|
|
277
|
+
func = getattr(method, "__func__", None)
|
|
278
|
+
return getattr(func, _HANDLER_ATTRIBUTE, None)
|
|
279
|
+
|
|
280
|
+
|
|
153
281
|
def get_callable_methods(host: Any) -> list[str]:
|
|
154
282
|
"""Returns a list of callable method names that don't start with underscore."""
|
|
155
283
|
return [
|
|
@@ -172,20 +300,27 @@ def get_handler_info(host: Any, method_name: str) -> tuple[str, str] | None:
|
|
|
172
300
|
param: Parameter = next(iter(params.values()))
|
|
173
301
|
annotation = param.annotation
|
|
174
302
|
|
|
175
|
-
if
|
|
176
|
-
|
|
177
|
-
return annotation, method_name
|
|
178
|
-
|
|
179
|
-
if is_iris_object_instance(annotation):
|
|
180
|
-
return (
|
|
181
|
-
f"{type(annotation).__module__}.{type(annotation).__name__}",
|
|
182
|
-
method_name,
|
|
183
|
-
)
|
|
303
|
+
if annotation == Parameter.empty:
|
|
304
|
+
return None
|
|
184
305
|
|
|
185
|
-
|
|
306
|
+
message = _message_class_name(annotation)
|
|
307
|
+
if message is None:
|
|
186
308
|
return None
|
|
187
309
|
|
|
188
|
-
return
|
|
310
|
+
return message, method_name
|
|
189
311
|
|
|
190
312
|
except ValueError:
|
|
191
313
|
return None
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _message_class_name(message_type: Any) -> str | None:
|
|
317
|
+
if isinstance(message_type, str):
|
|
318
|
+
return message_type
|
|
319
|
+
|
|
320
|
+
if is_iris_object_instance(message_type):
|
|
321
|
+
return f"{type(message_type).__module__}.{type(message_type).__name__}"
|
|
322
|
+
|
|
323
|
+
if not isinstance(message_type, type):
|
|
324
|
+
return None
|
|
325
|
+
|
|
326
|
+
return f"{message_type.__module__}.{message_type.__name__}"
|