iris-pex-embedded-python 3.7.2b1__tar.gz → 4.0.0b1__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.
Files changed (141) hide show
  1. {iris_pex_embedded_python-3.7.2b1/src/iris_pex_embedded_python.egg-info → iris_pex_embedded_python-4.0.0b1}/PKG-INFO +3 -1
  2. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/pyproject.toml +13 -2
  3. iris_pex_embedded_python-4.0.0b1/src/iop/__init__.py +138 -0
  4. iris_pex_embedded_python-4.0.0b1/src/iop/__main__.py +5 -0
  5. iris_pex_embedded_python-4.0.0b1/src/iop/cli/__init__.py +1 -0
  6. iris_pex_embedded_python-4.0.0b1/src/iop/cli/formatting.py +45 -0
  7. iris_pex_embedded_python-3.7.2b1/src/iop/_cli.py → iris_pex_embedded_python-4.0.0b1/src/iop/cli/main.py +97 -204
  8. iris_pex_embedded_python-4.0.0b1/src/iop/cli/parser.py +128 -0
  9. iris_pex_embedded_python-4.0.0b1/src/iop/cli/types.py +57 -0
  10. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Service/Remote/Rest/v1.cls +151 -5
  11. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Utils.cls +413 -8
  12. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Wrapper.cls +1 -1
  13. iris_pex_embedded_python-4.0.0b1/src/iop/components/__init__.py +16 -0
  14. iris_pex_embedded_python-3.7.2b1/src/iop/_async_request.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/async_request.py +7 -7
  15. iris_pex_embedded_python-4.0.0b1/src/iop/components/business_host.py +319 -0
  16. iris_pex_embedded_python-3.7.2b1/src/iop/_business_operation.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/business_operation.py +16 -33
  17. iris_pex_embedded_python-3.7.2b1/src/iop/_business_process.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/business_process.py +28 -71
  18. iris_pex_embedded_python-3.7.2b1/src/iop/_business_service.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/business_service.py +16 -30
  19. iris_pex_embedded_python-4.0.0b1/src/iop/components/common.py +498 -0
  20. iris_pex_embedded_python-3.7.2b1/src/iop/_debugpy.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/debugpy.py +11 -11
  21. iris_pex_embedded_python-3.7.2b1/src/iop/_generator_request.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/generator_request.py +4 -4
  22. iris_pex_embedded_python-3.7.2b1/src/iop/_inbound_adapter.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/inbound_adapter.py +10 -18
  23. iris_pex_embedded_python-3.7.2b1/src/iop/_log_manager.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/log_manager.py +1 -1
  24. iris_pex_embedded_python-3.7.2b1/src/iop/_outbound_adapter.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/outbound_adapter.py +1 -1
  25. iris_pex_embedded_python-4.0.0b1/src/iop/components/polling_business_service.py +6 -0
  26. iris_pex_embedded_python-3.7.2b1/src/iop/_private_session_duplex.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/private_session_duplex.py +7 -9
  27. iris_pex_embedded_python-3.7.2b1/src/iop/_private_session_process.py → iris_pex_embedded_python-4.0.0b1/src/iop/components/private_session_process.py +2 -2
  28. iris_pex_embedded_python-4.0.0b1/src/iop/components/settings.py +187 -0
  29. iris_pex_embedded_python-4.0.0b1/src/iop/messages/__init__.py +7 -0
  30. iris_pex_embedded_python-3.7.2b1/src/iop/_message.py → iris_pex_embedded_python-4.0.0b1/src/iop/messages/base.py +15 -15
  31. iris_pex_embedded_python-3.7.2b1/src/iop/_decorators.py → iris_pex_embedded_python-4.0.0b1/src/iop/messages/decorators.py +3 -2
  32. iris_pex_embedded_python-3.7.2b1/src/iop/_dispatch.py → iris_pex_embedded_python-4.0.0b1/src/iop/messages/dispatch.py +19 -22
  33. iris_pex_embedded_python-3.7.2b1/src/iop/_persistent_message.py → iris_pex_embedded_python-4.0.0b1/src/iop/messages/persistent.py +16 -19
  34. iris_pex_embedded_python-3.7.2b1/src/iop/_serialization.py → iris_pex_embedded_python-4.0.0b1/src/iop/messages/serialization.py +21 -17
  35. iris_pex_embedded_python-3.7.2b1/src/iop/_message_validator.py → iris_pex_embedded_python-4.0.0b1/src/iop/messages/validation.py +4 -4
  36. iris_pex_embedded_python-4.0.0b1/src/iop/migration/__init__.py +1 -0
  37. iris_pex_embedded_python-4.0.0b1/src/iop/migration/io.py +61 -0
  38. iris_pex_embedded_python-4.0.0b1/src/iop/migration/plans.py +159 -0
  39. iris_pex_embedded_python-4.0.0b1/src/iop/migration/utils.py +1135 -0
  40. iris_pex_embedded_python-4.0.0b1/src/iop/production/__init__.py +29 -0
  41. iris_pex_embedded_python-4.0.0b1/src/iop/production/actions.py +228 -0
  42. iris_pex_embedded_python-4.0.0b1/src/iop/production/common.py +79 -0
  43. iris_pex_embedded_python-4.0.0b1/src/iop/production/component.py +240 -0
  44. iris_pex_embedded_python-4.0.0b1/src/iop/production/diff.py +321 -0
  45. iris_pex_embedded_python-4.0.0b1/src/iop/production/import_.py +259 -0
  46. iris_pex_embedded_python-4.0.0b1/src/iop/production/inspection.py +92 -0
  47. iris_pex_embedded_python-4.0.0b1/src/iop/production/model.py +783 -0
  48. iris_pex_embedded_python-4.0.0b1/src/iop/production/reconstruction.py +169 -0
  49. iris_pex_embedded_python-4.0.0b1/src/iop/production/rendering.py +289 -0
  50. iris_pex_embedded_python-4.0.0b1/src/iop/production/runtime.py +76 -0
  51. iris_pex_embedded_python-4.0.0b1/src/iop/production/types.py +301 -0
  52. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/__init__.py +1 -0
  53. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/director.py +405 -0
  54. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/environment.py +59 -0
  55. iris_pex_embedded_python-3.7.2b1/src/iop/_iris.py → iris_pex_embedded_python-4.0.0b1/src/iop/runtime/iris.py +2 -2
  56. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/local.py +126 -0
  57. iris_pex_embedded_python-3.7.2b1/src/iop/_director_protocol.py → iris_pex_embedded_python-4.0.0b1/src/iop/runtime/protocol.py +15 -7
  58. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/remote/__init__.py +12 -0
  59. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/remote/client.py +90 -0
  60. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/remote/director.py +265 -0
  61. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/remote/migration.py +51 -0
  62. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/remote/settings.py +69 -0
  63. iris_pex_embedded_python-4.0.0b1/src/iop/runtime/remote/setup.py +72 -0
  64. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1/src/iris_pex_embedded_python.egg-info}/PKG-INFO +3 -1
  65. iris_pex_embedded_python-4.0.0b1/src/iris_pex_embedded_python.egg-info/SOURCES.txt +96 -0
  66. iris_pex_embedded_python-4.0.0b1/src/iris_pex_embedded_python.egg-info/entry_points.txt +2 -0
  67. iris_pex_embedded_python-4.0.0b1/src/iris_pex_embedded_python.egg-info/top_level.txt +1 -0
  68. iris_pex_embedded_python-3.7.2b1/setup.py +0 -3
  69. iris_pex_embedded_python-3.7.2b1/src/grongier/__init__.py +0 -0
  70. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/BusinessOperation.cls +0 -8
  71. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/BusinessProcess.cls +0 -13
  72. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/BusinessService.cls +0 -8
  73. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Common.cls +0 -10
  74. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Director.cls +0 -10
  75. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Duplex/Operation.cls +0 -4
  76. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Duplex/Process.cls +0 -13
  77. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Duplex/Service.cls +0 -4
  78. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/InboundAdapter.cls +0 -8
  79. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Message.cls +0 -13
  80. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/OutboundAdapter.cls +0 -8
  81. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/PickleMessage.cls +0 -13
  82. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/PrivateSession/Duplex.cls +0 -8
  83. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Ack.cls +0 -14
  84. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Poll.cls +0 -14
  85. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Start.cls +0 -14
  86. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/PrivateSession/Message/Stop.cls +0 -14
  87. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Test.cls +0 -10
  88. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/PEX/Utils.cls +0 -10
  89. iris_pex_embedded_python-3.7.2b1/src/grongier/cls/Grongier/Service/WSGI.cls +0 -4
  90. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/__init__.py +0 -66
  91. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/__main__.py +0 -4
  92. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/_business_host.py +0 -1
  93. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/_cli.py +0 -4
  94. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/_common.py +0 -1
  95. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/_director.py +0 -1
  96. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/_utils.py +0 -1
  97. iris_pex_embedded_python-3.7.2b1/src/grongier/pex/wsgi/handlers.py +0 -104
  98. iris_pex_embedded_python-3.7.2b1/src/iop/__init__.py +0 -78
  99. iris_pex_embedded_python-3.7.2b1/src/iop/__main__.py +0 -5
  100. iris_pex_embedded_python-3.7.2b1/src/iop/_business_host.py +0 -322
  101. iris_pex_embedded_python-3.7.2b1/src/iop/_common.py +0 -416
  102. iris_pex_embedded_python-3.7.2b1/src/iop/_director.py +0 -333
  103. iris_pex_embedded_python-3.7.2b1/src/iop/_local.py +0 -106
  104. iris_pex_embedded_python-3.7.2b1/src/iop/_remote.py +0 -473
  105. iris_pex_embedded_python-3.7.2b1/src/iop/_utils.py +0 -710
  106. iris_pex_embedded_python-3.7.2b1/src/iop/cls/IOP/Service/WSGI.cls +0 -310
  107. iris_pex_embedded_python-3.7.2b1/src/iop/wsgi/handlers.py +0 -112
  108. iris_pex_embedded_python-3.7.2b1/src/iris_pex_embedded_python.egg-info/SOURCES.txt +0 -98
  109. iris_pex_embedded_python-3.7.2b1/src/iris_pex_embedded_python.egg-info/entry_points.txt +0 -2
  110. iris_pex_embedded_python-3.7.2b1/src/iris_pex_embedded_python.egg-info/top_level.txt +0 -2
  111. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/LICENSE +0 -0
  112. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/README.md +0 -0
  113. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/setup.cfg +0 -0
  114. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/BusinessOperation.cls +0 -0
  115. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/BusinessProcess.cls +0 -0
  116. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/BusinessService.cls +0 -0
  117. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Common.cls +0 -0
  118. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Director.cls +0 -0
  119. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Duplex/Operation.cls +0 -0
  120. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Duplex/Process.cls +0 -0
  121. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Duplex/Service.cls +0 -0
  122. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Generator/Message/Ack.cls +0 -0
  123. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Generator/Message/Poll.cls +0 -0
  124. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Generator/Message/Start.cls +0 -0
  125. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Generator/Message/StartPickle.cls +0 -0
  126. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Generator/Message/Stop.cls +0 -0
  127. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/InboundAdapter.cls +0 -0
  128. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Message/JSONSchema.cls +0 -0
  129. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Message.cls +0 -0
  130. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/OutboundAdapter.cls +0 -0
  131. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/PickleMessage.cls +0 -0
  132. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/PrivateSession/Duplex.cls +0 -0
  133. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/PrivateSession/Message/Ack.cls +0 -0
  134. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/PrivateSession/Message/Poll.cls +0 -0
  135. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/PrivateSession/Message/Start.cls +0 -0
  136. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/PrivateSession/Message/Stop.cls +0 -0
  137. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Projection.cls +0 -0
  138. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Service/Remote/Handler.cls +0 -0
  139. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iop/cls/IOP/Test.cls +0 -0
  140. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iris_pex_embedded_python.egg-info/dependency_links.txt +0 -0
  141. {iris_pex_embedded_python-3.7.2b1 → iris_pex_embedded_python-4.0.0b1}/src/iris_pex_embedded_python.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iris_pex_embedded_python
3
- Version: 3.7.2b1
3
+ Version: 4.0.0b1
4
4
  Summary: Iris Interoperability based on Embedded Python
5
5
  Author-email: grongier <guillaume.rongier@intersystems.com>
6
6
  License: MIT License
@@ -37,6 +37,8 @@ Classifier: Operating System :: OS Independent
37
37
  Classifier: Programming Language :: Python :: 3.10
38
38
  Classifier: Programming Language :: Python :: 3.11
39
39
  Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Programming Language :: Python :: 3.13
41
+ Classifier: Programming Language :: Python :: 3.14
40
42
  Classifier: Topic :: Utilities
41
43
  Requires-Python: >=3.10
42
44
  Description-Content-Type: text/markdown
@@ -3,7 +3,7 @@ requires = ["setuptools", "wheel"]
3
3
 
4
4
  [project]
5
5
  name = "iris_pex_embedded_python"
6
- version = "3.7.2b1"
6
+ version = "4.0.0b1"
7
7
  description = "Iris Interoperability based on Embedded Python"
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.10"
@@ -20,6 +20,8 @@ classifiers = [
20
20
  "Programming Language :: Python :: 3.10",
21
21
  "Programming Language :: Python :: 3.11",
22
22
  "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
23
25
  "Topic :: Utilities"
24
26
  ]
25
27
 
@@ -42,10 +44,11 @@ repository = "https://github.com/grongierisc/interoperability-embedded-python"
42
44
  issues = "https://github.com/grongierisc/interoperability-embedded-python/issues"
43
45
 
44
46
  [project.scripts]
45
- iop = "iop._cli:main"
47
+ iop = "iop.cli.main:main"
46
48
 
47
49
  [tool.setuptools.packages.find]
48
50
  where = ["src"]
51
+ include = ["iop*"]
49
52
  exclude = ["tests*"]
50
53
 
51
54
  [tool.setuptools.package-data]
@@ -59,3 +62,11 @@ markers = [
59
62
  "e2e_local: end-to-end test requiring a local IRIS instance",
60
63
  "e2e_remote: end-to-end test requiring a remote IRIS instance via REST API",
61
64
  ]
65
+
66
+ [tool.ruff]
67
+ target-version = "py310"
68
+ line-length = 88
69
+
70
+ [tool.ruff.lint]
71
+ select = ["E", "F", "I", "B", "UP"]
72
+ ignore = ["E501"]
@@ -0,0 +1,138 @@
1
+ from iop.components.business_operation import _BusinessOperation
2
+ from iop.components.business_process import _BusinessProcess
3
+ from iop.components.business_service import _BusinessService
4
+ from iop.components.inbound_adapter import _InboundAdapter
5
+ from iop.components.outbound_adapter import _OutboundAdapter
6
+ from iop.components.polling_business_service import _PollingBusinessServiceMixin
7
+ from iop.components.private_session_duplex import _PrivateSessionDuplex
8
+ from iop.components.private_session_process import _PrivateSessionProcess
9
+ from iop.components.settings import Category as Category
10
+ from iop.components.settings import Setting as Setting
11
+ from iop.components.settings import controls as controls
12
+ from iop.components.settings import setting as setting
13
+ from iop.messages.base import (
14
+ _Message,
15
+ _PickleMessage,
16
+ _PydanticMessage,
17
+ _PydanticPickleMessage,
18
+ )
19
+ from iop.messages.persistent import Field as Field
20
+ from iop.messages.persistent import Model as Model
21
+ from iop.messages.persistent import _PersistentMessage
22
+ from iop.migration.utils import _Utils
23
+ from iop.migration.utils import bind_component as bind_component
24
+ from iop.migration.utils import list_bindings as list_bindings
25
+ from iop.migration.utils import register_component as register_component
26
+ from iop.migration.utils import unbind_component as unbind_component
27
+ from iop.migration.utils import unregister_component as unregister_component
28
+ from iop.production import ComponentRef as ComponentRef
29
+ from iop.production import Port as Port
30
+ from iop.production import Production as Production
31
+ from iop.production import ProductionDiff as ProductionDiff
32
+ from iop.production import ProductionDiffEntry as ProductionDiffEntry
33
+ from iop.production import ProductionGraph as ProductionGraph
34
+ from iop.production import target as target
35
+ from iop.runtime.director import _Director
36
+ from iop.runtime.protocol import DirectorProtocol as DirectorProtocol
37
+
38
+ __all__ = [
39
+ "BusinessOperation",
40
+ "BusinessProcess",
41
+ "BusinessService",
42
+ "Category",
43
+ "ComponentRef",
44
+ "Director",
45
+ "DirectorProtocol",
46
+ "DuplexOperation",
47
+ "DuplexProcess",
48
+ "DuplexService",
49
+ "Field",
50
+ "InboundAdapter",
51
+ "Message",
52
+ "Model",
53
+ "OutboundAdapter",
54
+ "PersistentMessage",
55
+ "PickleMessage",
56
+ "PollingBusinessService",
57
+ "Port",
58
+ "Production",
59
+ "ProductionDiff",
60
+ "ProductionDiffEntry",
61
+ "ProductionGraph",
62
+ "PydanticMessage",
63
+ "PydanticPickleMessage",
64
+ "Setting",
65
+ "Utils",
66
+ "bind_component",
67
+ "controls",
68
+ "list_bindings",
69
+ "register_component",
70
+ "setting",
71
+ "target",
72
+ "unbind_component",
73
+ "unregister_component",
74
+ ]
75
+
76
+
77
+ class Utils(_Utils):
78
+ pass
79
+
80
+
81
+ class InboundAdapter(_InboundAdapter):
82
+ pass
83
+
84
+
85
+ class OutboundAdapter(_OutboundAdapter):
86
+ pass
87
+
88
+
89
+ class BusinessService(_BusinessService):
90
+ pass
91
+
92
+
93
+ class PollingBusinessService(_PollingBusinessServiceMixin, BusinessService):
94
+ pass
95
+
96
+
97
+ class BusinessOperation(_BusinessOperation):
98
+ pass
99
+
100
+
101
+ class BusinessProcess(_BusinessProcess):
102
+ pass
103
+
104
+
105
+ class DuplexService(_PrivateSessionDuplex):
106
+ pass
107
+
108
+
109
+ class DuplexOperation(_PrivateSessionDuplex):
110
+ pass
111
+
112
+
113
+ class DuplexProcess(_PrivateSessionProcess):
114
+ pass
115
+
116
+
117
+ class Message(_Message):
118
+ pass
119
+
120
+
121
+ class PickleMessage(_PickleMessage):
122
+ pass
123
+
124
+
125
+ class PydanticMessage(_PydanticMessage):
126
+ pass
127
+
128
+
129
+ class PydanticPickleMessage(_PydanticPickleMessage):
130
+ pass
131
+
132
+
133
+ class PersistentMessage(_PersistentMessage):
134
+ _iop_persistent_message_abstract = True
135
+
136
+
137
+ class Director(_Director):
138
+ pass
@@ -0,0 +1,5 @@
1
+ # main entry is cli.main()
2
+ if __name__ == "__main__":
3
+ from iop.cli.main import main
4
+
5
+ main()
@@ -0,0 +1 @@
1
+ from .main import main as main
@@ -0,0 +1,45 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ import json
5
+ from typing import Any
6
+
7
+
8
+ def format_test_response(response: Any) -> str:
9
+ """Pretty-print any test_component() return value."""
10
+ if isinstance(response, dict):
11
+ parts = []
12
+ if response.get("error"):
13
+ return f"Error: {response['error']}"
14
+ if response.get("classname"):
15
+ parts.append(f"classname: {response['classname']}")
16
+ body = response.get("body", "")
17
+ if body:
18
+ try:
19
+ parsed = json.loads(body)
20
+ parts.append("body:\n" + json.dumps(parsed, indent=4))
21
+ except (json.JSONDecodeError, TypeError):
22
+ parts.append(f"body: {body}")
23
+ if response.get("truncated"):
24
+ parts.append("(response body was truncated)")
25
+ return "\n".join(parts) if parts else str(response)
26
+
27
+ if isinstance(response, str):
28
+ if " : " in response:
29
+ classname_part, _, body_part = response.partition(" : ")
30
+ try:
31
+ parsed = json.loads(body_part)
32
+ return (
33
+ f"classname: {classname_part.strip()}\n"
34
+ f"body:\n{json.dumps(parsed, indent=4)}"
35
+ )
36
+ except (json.JSONDecodeError, TypeError):
37
+ pass
38
+ try:
39
+ return json.dumps(json.loads(response), indent=4)
40
+ except (json.JSONDecodeError, TypeError):
41
+ return response
42
+
43
+ if dataclasses.is_dataclass(response):
44
+ return json.dumps(dataclasses.asdict(response), indent=4)
45
+ return str(response)
@@ -1,62 +1,23 @@
1
1
  from __future__ import annotations
2
- import argparse
2
+
3
3
  import json
4
4
  import logging
5
- import requests
6
5
  import os
7
- from dataclasses import dataclass
8
- from enum import Enum, auto
9
6
  import sys
10
- from typing import Optional
11
7
  from importlib.metadata import version
12
8
 
13
- from ._local import _LocalDirector
14
- from ._remote import _RemoteDirector, get_remote_settings
15
- from ._director_protocol import DirectorProtocol
16
-
17
-
18
- class CommandType(Enum):
19
- DEFAULT = auto()
20
- LIST = auto()
21
- START = auto()
22
- STOP = auto()
23
- KILL = auto()
24
- RESTART = auto()
25
- STATUS = auto()
26
- TEST = auto()
27
- VERSION = auto()
28
- EXPORT = auto()
29
- MIGRATE = auto()
30
- LOG = auto()
31
- INIT = auto()
32
- HELP = auto()
33
- UPDATE = auto()
34
-
35
-
36
- @dataclass
37
- class CommandArgs:
38
- """Container for parsed command arguments"""
39
-
40
- default: Optional[str] = None
41
- list: bool = False
42
- start: Optional[str] = None
43
- detach: bool = False
44
- stop: bool = False
45
- kill: bool = False
46
- restart: bool = False
47
- status: bool = False
48
- migrate: Optional[str] = None
49
- export: Optional[str] = None
50
- version: bool = False
51
- log: Optional[str] = None
52
- init: Optional[str] = None
53
- test: Optional[str] = None
54
- classname: Optional[str] = None
55
- body: Optional[str] = None
56
- namespace: Optional[str] = None
57
- force_local: bool = False
58
- remote_settings: Optional[str] = None
59
- update: bool = False
9
+ import requests
10
+
11
+ from ..migration import utils as migration_utils
12
+ from ..production import Production
13
+ from ..runtime.local import _LocalDirector
14
+ from ..runtime.protocol import DirectorProtocol
15
+ from ..runtime.remote import _RemoteDirector, get_remote_settings
16
+ from .formatting import format_test_response
17
+ from .parser import create_parser
18
+ from .types import CommandArgs, CommandType
19
+
20
+ _format_test_response = format_test_response
60
21
 
61
22
 
62
23
  class Command:
@@ -112,12 +73,18 @@ class Command:
112
73
  self.args.export,
113
74
  self.args.migrate,
114
75
  self.args.log,
76
+ self.args.queue,
115
77
  self.args.init,
78
+ self.args.bindings,
79
+ self.args.unbind is not None,
116
80
  self.args.update,
117
81
  ]
118
82
  )
119
83
 
120
84
  def execute(self) -> None:
85
+ if self.args.unused and not self.args.bindings:
86
+ raise ValueError("--unused can only be used with --bindings.")
87
+
121
88
  if self.args.namespace == "not_set" and not self._has_primary_command():
122
89
  print(os.getenv("IRISNAMESPACE", "not set"))
123
90
  return
@@ -136,7 +103,10 @@ class Command:
136
103
  CommandType.EXPORT: self._handle_export,
137
104
  CommandType.MIGRATE: self._handle_migrate,
138
105
  CommandType.LOG: self._handle_log,
106
+ CommandType.QUEUE: self._handle_queue,
139
107
  CommandType.INIT: self._handle_init,
108
+ CommandType.BINDINGS: self._handle_bindings,
109
+ CommandType.UNBIND: self._handle_unbind,
140
110
  CommandType.HELP: self._handle_help,
141
111
  CommandType.UPDATE: self._handle_update,
142
112
  }
@@ -169,8 +139,14 @@ class Command:
169
139
  return CommandType.MIGRATE
170
140
  if self.args.log:
171
141
  return CommandType.LOG
142
+ if self.args.queue:
143
+ return CommandType.QUEUE
172
144
  if self.args.init:
173
145
  return CommandType.INIT
146
+ if self.args.bindings:
147
+ return CommandType.BINDINGS
148
+ if self.args.unbind is not None:
149
+ return CommandType.UNBIND
174
150
  if self.args.update:
175
151
  return CommandType.UPDATE
176
152
  return CommandType.HELP
@@ -228,13 +204,13 @@ class Command:
228
204
  filepath = body[1:]
229
205
  if not os.path.isabs(filepath):
230
206
  filepath = os.path.join(os.getcwd(), filepath)
231
- with open(filepath, "r", encoding="utf-8") as fh:
207
+ with open(filepath, encoding="utf-8") as fh:
232
208
  body = fh.read()
233
209
 
234
210
  response = self.director.test_component(
235
211
  test_name, classname=classname, body=body
236
212
  )
237
- print(_format_test_response(response))
213
+ print(format_test_response(response))
238
214
 
239
215
  def _handle_version(self) -> None:
240
216
  print(version("iris-pex-embedded-python"))
@@ -245,14 +221,46 @@ class Command:
245
221
  if self.args.export == "not_set"
246
222
  else self.args.export
247
223
  )
248
- print(json.dumps(self.director.export_production(export_name), indent=4))
224
+ export_format = self.args.export_format or "json"
225
+ if export_format == "json":
226
+ print(json.dumps(self.director.export_production(export_name), indent=4))
227
+ return
228
+
229
+ production = Production.from_iris(export_name, director=self.director)
230
+ if export_format == "python":
231
+ print(production.to_python(), end="")
232
+ return
233
+ if export_format == "graph":
234
+ print(production.graph())
235
+ return
236
+ raise ValueError(f"Unsupported export format: {export_format}")
249
237
 
250
238
  def _handle_migrate(self) -> None:
251
239
  migrate_path = self.args.migrate
252
240
  if migrate_path is not None:
253
241
  if not os.path.isabs(migrate_path):
254
242
  migrate_path = os.path.join(os.getcwd(), migrate_path)
243
+ mode = "REMOTE" if self._is_remote else "LOCAL"
244
+ if self.args.migration_plan:
245
+ print(
246
+ migration_utils.explain_migration(
247
+ migrate_path, mode=mode, namespace=self.director.namespace
248
+ )
249
+ )
250
+ return
251
+ if self._is_remote:
252
+ print(
253
+ migration_utils.explain_migration(
254
+ migrate_path, mode=mode, namespace=self.director.namespace
255
+ )
256
+ )
255
257
  self.director.migrate(migrate_path)
258
+ if self._is_remote:
259
+ print(
260
+ migration_utils.format_migration_success(
261
+ migrate_path, namespace=self.director.namespace
262
+ )
263
+ )
256
264
 
257
265
  def _handle_log(self) -> None:
258
266
  if self.args.log == "not_set":
@@ -260,10 +268,43 @@ class Command:
260
268
  elif self.args.log is not None:
261
269
  self.director.log_production_top(int(self.args.log))
262
270
 
271
+ def _handle_queue(self) -> None:
272
+ production_name = (
273
+ self.director.get_default_production()
274
+ if self.args.queue == "not_set"
275
+ else self.args.queue
276
+ )
277
+ if not production_name or production_name == "Not defined":
278
+ print(
279
+ "Error: no production name provided and no default production is defined.",
280
+ file=sys.stderr,
281
+ )
282
+ sys.exit(1)
283
+ print(
284
+ json.dumps(
285
+ self.director.export_production_queue_info(production_name),
286
+ indent=4,
287
+ )
288
+ )
289
+
263
290
  def _handle_init(self) -> None:
264
291
  path = None if self.args.init == "not_set" else self.args.init
265
292
  self.director.setup(path)
266
293
 
294
+ def _handle_bindings(self) -> None:
295
+ print(
296
+ json.dumps(
297
+ self.director.list_bindings(unused_only=self.args.unused),
298
+ indent=4,
299
+ )
300
+ )
301
+
302
+ def _handle_unbind(self) -> None:
303
+ if not self.args.unbind:
304
+ raise ValueError("IRIS class name is required.")
305
+ self.director.unbind_component(self.args.unbind)
306
+ print(f"Removed binding {self.args.unbind}.")
307
+
267
308
  def _handle_help(self) -> None:
268
309
  create_parser().print_help()
269
310
  if self._is_remote:
@@ -275,154 +316,6 @@ class Command:
275
316
  logging.warning("Could not retrieve default production.")
276
317
 
277
318
 
278
- def _format_test_response(response) -> str:
279
- """Pretty-print any test_component() return value.
280
-
281
- Handles three cases:
282
- - dict : remote response with ``classname`` / ``body`` keys
283
- - str : local response in ``"ClassName : {json}"`` format
284
- - other : Python dataclass / object returned by the local director
285
- """
286
- if isinstance(response, dict):
287
- parts = []
288
- if response.get("error"):
289
- return f"Error: {response['error']}"
290
- if response.get("classname"):
291
- parts.append(f"classname: {response['classname']}")
292
- body = response.get("body", "")
293
- if body:
294
- try:
295
- parsed = json.loads(body)
296
- parts.append("body:\n" + json.dumps(parsed, indent=4))
297
- except (json.JSONDecodeError, TypeError):
298
- parts.append(f"body: {body}")
299
- if response.get("truncated"):
300
- parts.append("(response body was truncated)")
301
- return "\n".join(parts) if parts else str(response)
302
-
303
- if isinstance(response, str):
304
- # Try to detect the "ClassName : {json_body}" pattern from local mode
305
- if " : " in response:
306
- classname_part, _, body_part = response.partition(" : ")
307
- try:
308
- parsed = json.loads(body_part)
309
- return (
310
- f"classname: {classname_part.strip()}\n"
311
- f"body:\n{json.dumps(parsed, indent=4)}"
312
- )
313
- except (json.JSONDecodeError, TypeError):
314
- pass
315
- # Plain string — try JSON pretty-print
316
- try:
317
- return json.dumps(json.loads(response), indent=4)
318
- except (json.JSONDecodeError, TypeError):
319
- return response
320
-
321
- # Python dataclass / arbitrary object
322
- try:
323
- import dataclasses
324
-
325
- if dataclasses.is_dataclass(response):
326
- return json.dumps(dataclasses.asdict(response), indent=4)
327
- except Exception:
328
- pass
329
- return str(response)
330
-
331
-
332
- def create_parser() -> argparse.ArgumentParser:
333
- """Create and configure argument parser"""
334
- main_parser = argparse.ArgumentParser(
335
- epilog=(
336
- "Remote mode: set IOP_URL (e.g. http://localhost:8080) to run all commands\n"
337
- "against a remote IRIS instance via its REST API. Optional env vars:\n"
338
- " IOP_USERNAME, IOP_PASSWORD, IOP_NAMESPACE (default: USER),\n"
339
- " IOP_VERIFY_SSL (set to 0 to disable TLS verification).\n"
340
- "Alternatively use -R /path/to/settings.py or set IOP_SETTINGS=\n"
341
- "(file must contain a REMOTE_SETTINGS dict with at least 'url').\n"
342
- "Use --force-local to suppress remote mode entirely."
343
- ),
344
- formatter_class=argparse.RawDescriptionHelpFormatter,
345
- )
346
- parser = main_parser.add_mutually_exclusive_group()
347
-
348
- # Main commands
349
- parser.add_argument(
350
- "-d", "--default", help="set the default production", nargs="?", const="not_set"
351
- )
352
- parser.add_argument("-l", "--list", help="list productions", action="store_true")
353
- parser.add_argument(
354
- "-s", "--start", help="start a production", nargs="?", const="not_set"
355
- )
356
- parser.add_argument("-S", "--stop", help="stop a production", action="store_true")
357
- parser.add_argument("-k", "--kill", help="kill a production", action="store_true")
358
- parser.add_argument(
359
- "-r", "--restart", help="restart a production", action="store_true"
360
- )
361
- parser.add_argument(
362
- "-x", "--status", help="status a production", action="store_true"
363
- )
364
- parser.add_argument(
365
- "-m",
366
- "-M",
367
- "--migrate",
368
- help="migrate production and classes with settings file",
369
- )
370
- parser.add_argument(
371
- "-e", "--export", help="export a production", nargs="?", const="not_set"
372
- )
373
- parser.add_argument("-v", "--version", help="display version", action="store_true")
374
- parser.add_argument("-L", "--log", help="display log", nargs="?", const="not_set")
375
- parser.add_argument(
376
- "-i", "--init", help="init the pex module in iris", nargs="?", const="not_set"
377
- )
378
- parser.add_argument(
379
- "-t", "--test", help="test the pex module in iris", nargs="?", const="not_set"
380
- )
381
- parser.add_argument(
382
- "-u", "--update", help="update a production", action="store_true"
383
- )
384
-
385
- # Command groups
386
- start = main_parser.add_argument_group("start arguments")
387
- start.add_argument(
388
- "-D", "--detach", help="start a production in detach mode", action="store_true"
389
- )
390
-
391
- test = main_parser.add_argument_group("test arguments")
392
- test.add_argument(
393
- "-C", "--classname", help="test classname", nargs="?", const="not_set"
394
- )
395
- test.add_argument(
396
- "-B",
397
- "--body",
398
- help="test body (JSON string or @path/to/file.json)",
399
- nargs="?",
400
- const="not_set",
401
- )
402
-
403
- migrate = main_parser.add_argument_group("migrate arguments")
404
- migrate.add_argument(
405
- "--force-local",
406
- help="force local mode, skip remote even if REMOTE_SETTINGS or IOP_URL is present",
407
- action="store_true",
408
- )
409
-
410
- remote = main_parser.add_argument_group("remote arguments")
411
- remote.add_argument(
412
- "-R",
413
- "--remote-settings",
414
- help="path to a settings.py containing REMOTE_SETTINGS (overrides IOP_SETTINGS env var)",
415
- metavar="FILE",
416
- )
417
-
418
- namespace = main_parser.add_argument_group("namespace arguments")
419
- namespace.add_argument(
420
- "-n", "--namespace", help="set namespace", nargs="?", const="not_set"
421
- )
422
-
423
- return main_parser
424
-
425
-
426
319
  def main(argv=None) -> None:
427
320
  parser = create_parser()
428
321
  args = parser.parse_args(argv)
@@ -443,7 +336,7 @@ def main(argv=None) -> None:
443
336
  except requests.exceptions.HTTPError as exc:
444
337
  print(f"Error: {exc}", file=sys.stderr)
445
338
  sys.exit(1)
446
- except RuntimeError as exc:
339
+ except (RuntimeError, ValueError) as exc:
447
340
  print(f"Error: {exc}", file=sys.stderr)
448
341
  sys.exit(1)
449
342
  sys.exit(0)