intersect-sdk 0.8.3__tar.gz → 0.9.0__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.
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/PKG-INFO +9 -9
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/README.md +2 -1
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/pyproject.toml +23 -15
- intersect_sdk-0.9.0/src/intersect_sdk/__init__.py +130 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/constants.py +0 -2
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/control_plane/brokers/amqp_client.py +38 -9
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/control_plane/brokers/broker_client.py +5 -1
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/control_plane/brokers/mqtt_client.py +109 -25
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/control_plane/control_plane_manager.py +21 -19
- intersect_sdk-0.9.0/src/intersect_sdk/_internal/control_plane/definitions.py +10 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/control_plane/topic_handler.py +2 -4
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/data_plane/data_plane_manager.py +20 -9
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/data_plane/minio_utils.py +9 -4
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/event_metadata.py +2 -6
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/exceptions.py +1 -1
- intersect_sdk-0.9.0/src/intersect_sdk/_internal/function_metadata.py +52 -0
- intersect_sdk-0.9.0/src/intersect_sdk/_internal/generic_serializer.py +5 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/interfaces.py +4 -2
- intersect_sdk-0.9.0/src/intersect_sdk/_internal/messages/event.py +145 -0
- intersect_sdk-0.9.0/src/intersect_sdk/_internal/messages/lifecycle.py +107 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/messages/userspace.py +76 -78
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/pydantic_schema_generator.py +1 -7
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/schema.py +232 -154
- intersect_sdk-0.9.0/src/intersect_sdk/_internal/status_metadata.py +14 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/version.py +2 -2
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/version_resolver.py +18 -17
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/app_lifecycle.py +3 -1
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/capability/__init__.py +0 -6
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/capability/base.py +36 -49
- intersect_sdk-0.9.0/src/intersect_sdk/capability/universal_capability/__init__.py +4 -0
- intersect_sdk-0.9.0/src/intersect_sdk/capability/universal_capability/status.py +25 -0
- intersect_sdk-0.9.0/src/intersect_sdk/capability/universal_capability/universal_capability.py +60 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/client.py +61 -51
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/client_callback_definitions.py +26 -19
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/config/__init__.py +0 -11
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/config/client.py +3 -3
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/config/service.py +2 -3
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/config/shared.py +7 -8
- intersect_sdk-0.9.0/src/intersect_sdk/constants.py +28 -0
- intersect_sdk-0.9.0/src/intersect_sdk/core_definitions.py +47 -0
- intersect_sdk-0.9.0/src/intersect_sdk/exceptions.py +40 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/schema.py +7 -6
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/service.py +361 -240
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/service_callback_definitions.py +7 -4
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/service_definitions.py +25 -80
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/shared_callback_definitions.py +34 -14
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/version.py +1 -3
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/fixtures/example_schema.json +384 -168
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/fixtures/example_schema.py +83 -54
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/integration/test_return_type_mismatch.py +17 -16
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/integration/test_service.py +217 -93
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/unit/test_annotations.py +19 -80
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/unit/test_base_capability_implementation.py +10 -46
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/unit/test_config.py +1 -1
- intersect_sdk-0.9.0/tests/unit/test_event_message_headers.py +119 -0
- intersect_sdk-0.9.0/tests/unit/test_imports.py +7 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/unit/test_invalid_schema_runtime.py +6 -3
- intersect_sdk-0.9.0/tests/unit/test_lifecycle_message_headers.py +101 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/unit/test_schema_invalids.py +71 -121
- intersect_sdk-0.9.0/tests/unit/test_schema_ref_resolution.py +55 -0
- intersect_sdk-0.9.0/tests/unit/test_schema_valid.py +157 -0
- intersect_sdk-0.9.0/tests/unit/test_userspace_message_headers.py +139 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/unit/test_version_resolver.py +39 -51
- intersect_sdk-0.8.3/src/intersect_sdk/__init__.py +0 -73
- intersect_sdk-0.8.3/src/intersect_sdk/_internal/control_plane/discovery_service.py +0 -40
- intersect_sdk-0.8.3/src/intersect_sdk/_internal/function_metadata.py +0 -31
- intersect_sdk-0.8.3/src/intersect_sdk/_internal/messages/event.py +0 -157
- intersect_sdk-0.8.3/src/intersect_sdk/_internal/messages/lifecycle.py +0 -174
- intersect_sdk-0.8.3/src/intersect_sdk/constants.py +0 -9
- intersect_sdk-0.8.3/src/intersect_sdk/core_definitions.py +0 -37
- intersect_sdk-0.8.3/tests/unit/test_lifecycle_message.py +0 -101
- intersect_sdk-0.8.3/tests/unit/test_schema_valid.py +0 -134
- intersect_sdk-0.8.3/tests/unit/test_userspace_message.py +0 -106
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/LICENSE +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/control_plane/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/control_plane/brokers/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/data_plane/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/logger.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/messages/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/multi_flag_thread_event.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/stoppable_thread.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/_internal/utils.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/src/intersect_sdk/py.typed +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/conftest.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/e2e/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/e2e/test_examples.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/fixtures/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/fixtures/return_type_mismatch.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/integration/__init__.py +0 -0
- {intersect_sdk-0.8.3 → intersect_sdk-0.9.0}/tests/unit/__init__.py +0 -0
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: intersect-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Python SDK to interact with INTERSECT
|
|
5
5
|
Keywords: intersect
|
|
6
6
|
Author-Email: Lance Drane <dranelt@ornl.gov>, Marshall McDonnell <mcdonnellmt@ornl.gov>, Seth Hitefield <hitefieldsd@ornl.gov>, Andrew Ayres <ayresaf@ornl.gov>, Gregory Cage <cagege@ornl.gov>, Jesse McGaha <mcgahajr@ornl.gov>, Robert Smith <smithrw@ornl.gov>, Gavin Wiggins <wigginsg@ornl.gov>, Michael Brim <brimmj@ornl.gov>, Rick Archibald <archibaldrk@ornl.gov>, Addi Malviya Thakur <malviyaa@ornl.gov>
|
|
7
7
|
License: BSD-3-Clause
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
11
9
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
10
|
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
13
|
Project-URL: Homepage, https://github.com/INTERSECT-SDK/python-sdk/
|
|
14
14
|
Project-URL: Changelog, https://github.com/INTERSECT-SDK/python-sdk/blob/main/CHANGELOG.md
|
|
15
15
|
Project-URL: Documentation, https://intersect-python-sdk.readthedocs.io/en/latest/
|
|
16
16
|
Project-URL: Issues, https://github.com/INTERSECT-SDK/python-sdk/issues
|
|
17
|
-
Requires-Python: <4.0,>=3.
|
|
17
|
+
Requires-Python: <4.0,>=3.10
|
|
18
18
|
Requires-Dist: pydantic>=2.7.0
|
|
19
19
|
Requires-Dist: retrying<2.0.0,>=1.3.4
|
|
20
|
-
Requires-Dist: paho-mqtt<
|
|
20
|
+
Requires-Dist: paho-mqtt<3.0.0,>=2.1.0
|
|
21
|
+
Requires-Dist: pika<2.0.0,>=1.3.2
|
|
21
22
|
Requires-Dist: minio>=7.2.3
|
|
22
23
|
Requires-Dist: jsonschema[format-nongpl]>=4.21.1
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Provides-Extra: amqp
|
|
25
|
-
Requires-Dist: pika<2.0.0,>=1.3.2; extra == "amqp"
|
|
24
|
+
Requires-Dist: psutil>=7.0.0
|
|
26
25
|
Provides-Extra: docs
|
|
27
26
|
Requires-Dist: sphinx>=5.3.0; extra == "docs"
|
|
28
27
|
Requires-Dist: furo>=2023.3.27; extra == "docs"
|
|
@@ -49,7 +48,8 @@ For a high-level overview, please see [the architecture website.](https://inters
|
|
|
49
48
|
|
|
50
49
|
- Event-driven architecture
|
|
51
50
|
- Support core interaction types: request/response, events, commands, statuses
|
|
52
|
-
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT
|
|
51
|
+
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT 5.0 and AMQP 0.9.1, but other protocols will be supported as well.
|
|
52
|
+
- As a general rule, we will not support any protocols which do not support headers, do not allow for asynchronous messaging, or require the microservice itself to "keep alive" multiple connections.
|
|
53
53
|
- Users automatically generate schema from code; schemas are part of the core contract of an INTERSECT microservice, and both external inputs and microservice outputs are required to uphold this contract.
|
|
54
54
|
|
|
55
55
|
## Authors
|
|
@@ -19,7 +19,8 @@ For a high-level overview, please see [the architecture website.](https://inters
|
|
|
19
19
|
|
|
20
20
|
- Event-driven architecture
|
|
21
21
|
- Support core interaction types: request/response, events, commands, statuses
|
|
22
|
-
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT
|
|
22
|
+
- Borrows several concepts from [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest), and intends to support multiple different protocols. Currently, we support MQTT 5.0 and AMQP 0.9.1, but other protocols will be supported as well.
|
|
23
|
+
- As a general rule, we will not support any protocols which do not support headers, do not allow for asynchronous messaging, or require the microservice itself to "keep alive" multiple connections.
|
|
23
24
|
- Users automatically generate schema from code; schemas are part of the core contract of an INTERSECT microservice, and both external inputs and microservice outputs are required to uphold this contract.
|
|
24
25
|
|
|
25
26
|
## Authors
|
|
@@ -15,27 +15,28 @@ authors = [
|
|
|
15
15
|
{ name = "Addi Malviya Thakur", email = "malviyaa@ornl.gov" },
|
|
16
16
|
]
|
|
17
17
|
readme = "README.md"
|
|
18
|
-
requires-python = ">=3.
|
|
18
|
+
requires-python = ">=3.10,<4.0"
|
|
19
19
|
keywords = [
|
|
20
20
|
"intersect",
|
|
21
21
|
]
|
|
22
22
|
dynamic = []
|
|
23
23
|
classifiers = [
|
|
24
24
|
"Programming Language :: Python :: 3",
|
|
25
|
-
"Programming Language :: Python :: 3.8",
|
|
26
|
-
"Programming Language :: Python :: 3.9",
|
|
27
25
|
"Programming Language :: Python :: 3.10",
|
|
28
26
|
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
29
|
]
|
|
30
30
|
dependencies = [
|
|
31
31
|
"pydantic>=2.7.0",
|
|
32
32
|
"retrying>=1.3.4,<2.0.0",
|
|
33
|
-
"paho-mqtt>=1.
|
|
33
|
+
"paho-mqtt>=2.1.0,<3.0.0",
|
|
34
|
+
"pika>=1.3.2,<2.0.0",
|
|
34
35
|
"minio>=7.2.3",
|
|
35
36
|
"jsonschema[format-nongpl]>=4.21.1",
|
|
36
|
-
"
|
|
37
|
+
"psutil>=7.0.0",
|
|
37
38
|
]
|
|
38
|
-
version = "0.
|
|
39
|
+
version = "0.9.0"
|
|
39
40
|
|
|
40
41
|
[project.license]
|
|
41
42
|
text = "BSD-3-Clause"
|
|
@@ -47,9 +48,6 @@ Documentation = "https://intersect-python-sdk.readthedocs.io/en/latest/"
|
|
|
47
48
|
Issues = "https://github.com/INTERSECT-SDK/python-sdk/issues"
|
|
48
49
|
|
|
49
50
|
[project.optional-dependencies]
|
|
50
|
-
amqp = [
|
|
51
|
-
"pika>=1.3.2,<2.0.0",
|
|
52
|
-
]
|
|
53
51
|
docs = [
|
|
54
52
|
"sphinx>=5.3.0",
|
|
55
53
|
"furo>=2023.3.27",
|
|
@@ -95,7 +93,7 @@ extend-select = [
|
|
|
95
93
|
"SLF",
|
|
96
94
|
"SLOT",
|
|
97
95
|
"SIM",
|
|
98
|
-
"
|
|
96
|
+
"TC",
|
|
99
97
|
"ARG",
|
|
100
98
|
"PTH",
|
|
101
99
|
"PGH",
|
|
@@ -103,6 +101,7 @@ extend-select = [
|
|
|
103
101
|
"TRY",
|
|
104
102
|
"FLY",
|
|
105
103
|
"RUF",
|
|
104
|
+
"INT",
|
|
106
105
|
]
|
|
107
106
|
ignore = [
|
|
108
107
|
"COM812",
|
|
@@ -130,12 +129,23 @@ max-complexity = 20
|
|
|
130
129
|
[tool.ruff.lint.pylint]
|
|
131
130
|
max-args = 10
|
|
132
131
|
max-branches = 20
|
|
133
|
-
max-returns =
|
|
132
|
+
max-returns = 15
|
|
134
133
|
max-statements = 75
|
|
135
134
|
|
|
135
|
+
[tool.ruff.lint.flake8-type-checking]
|
|
136
|
+
runtime-evaluated-base-classes = [
|
|
137
|
+
"pydantic.BaseModel",
|
|
138
|
+
"intersect_sdk.IntersectBaseCapabilityImplementation",
|
|
139
|
+
]
|
|
140
|
+
runtime-evaluated-decorators = [
|
|
141
|
+
"pydantic.dataclasses.dataclass",
|
|
142
|
+
"pydantic.validate_call",
|
|
143
|
+
]
|
|
144
|
+
|
|
136
145
|
[tool.ruff.lint.extend-per-file-ignores]
|
|
137
146
|
"__init__.py" = [
|
|
138
147
|
"F401",
|
|
148
|
+
"TC004",
|
|
139
149
|
]
|
|
140
150
|
"docs/*" = [
|
|
141
151
|
"D",
|
|
@@ -148,7 +158,6 @@ max-statements = 75
|
|
|
148
158
|
"D100",
|
|
149
159
|
"D104",
|
|
150
160
|
"TRY002",
|
|
151
|
-
"FA100",
|
|
152
161
|
]
|
|
153
162
|
"tests/*" = [
|
|
154
163
|
"S101",
|
|
@@ -158,7 +167,7 @@ max-statements = 75
|
|
|
158
167
|
"ANN",
|
|
159
168
|
"ARG",
|
|
160
169
|
"D",
|
|
161
|
-
"
|
|
170
|
+
"RUF012",
|
|
162
171
|
]
|
|
163
172
|
|
|
164
173
|
[tool.mypy]
|
|
@@ -196,9 +205,8 @@ exclude_also = [
|
|
|
196
205
|
[tool.pdm.dev-dependencies]
|
|
197
206
|
lint = [
|
|
198
207
|
"pre-commit>=3.3.1",
|
|
199
|
-
"ruff==0.
|
|
208
|
+
"ruff==0.12.7",
|
|
200
209
|
"mypy>=1.10.0",
|
|
201
|
-
"types-paho-mqtt>=1.6.0.20240106",
|
|
202
210
|
"codespell>=2.3.0",
|
|
203
211
|
]
|
|
204
212
|
test = [
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""The root module contains the intended public API for users of the INTERSECT-SDK.
|
|
2
|
+
|
|
3
|
+
Users should not need to import anything outside of the root.
|
|
4
|
+
|
|
5
|
+
In general, most breaking changes on version updates will relate to:
|
|
6
|
+
- Configuration classes (both adding and removing new config models). These configuration classes are relevant to the next point.
|
|
7
|
+
- When a new data service is integrated into INTERSECT, ALL adapters will need to update to support this data service, which will include new dependencies.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from importlib import import_module
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
# import everything eagerly for IDEs/LSPs
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .app_lifecycle import default_intersect_lifecycle_loop
|
|
16
|
+
from .capability.base import IntersectBaseCapabilityImplementation
|
|
17
|
+
from .client import IntersectClient
|
|
18
|
+
from .client_callback_definitions import (
|
|
19
|
+
INTERSECT_CLIENT_EVENT_CALLBACK_TYPE,
|
|
20
|
+
INTERSECT_CLIENT_RESPONSE_CALLBACK_TYPE,
|
|
21
|
+
IntersectClientCallback,
|
|
22
|
+
)
|
|
23
|
+
from .config.client import IntersectClientConfig
|
|
24
|
+
from .config.service import IntersectServiceConfig
|
|
25
|
+
from .config.shared import (
|
|
26
|
+
ControlPlaneConfig,
|
|
27
|
+
ControlProvider,
|
|
28
|
+
DataStoreConfig,
|
|
29
|
+
DataStoreConfigMap,
|
|
30
|
+
HierarchyConfig,
|
|
31
|
+
)
|
|
32
|
+
from .core_definitions import IntersectDataHandler, IntersectMimeType
|
|
33
|
+
from .exceptions import IntersectCapabilityError
|
|
34
|
+
from .schema import get_schema_from_capability_implementations
|
|
35
|
+
from .service import IntersectService
|
|
36
|
+
from .service_callback_definitions import (
|
|
37
|
+
INTERSECT_SERVICE_RESPONSE_CALLBACK_TYPE,
|
|
38
|
+
)
|
|
39
|
+
from .service_definitions import (
|
|
40
|
+
IntersectEventDefinition,
|
|
41
|
+
intersect_message,
|
|
42
|
+
intersect_status,
|
|
43
|
+
)
|
|
44
|
+
from .shared_callback_definitions import (
|
|
45
|
+
INTERSECT_JSON_VALUE,
|
|
46
|
+
INTERSECT_RESPONSE_VALUE,
|
|
47
|
+
IntersectDirectMessageParams,
|
|
48
|
+
IntersectEventMessageParams,
|
|
49
|
+
)
|
|
50
|
+
from .version import __version__, version_info, version_string
|
|
51
|
+
|
|
52
|
+
__all__ = (
|
|
53
|
+
'INTERSECT_CLIENT_EVENT_CALLBACK_TYPE',
|
|
54
|
+
'INTERSECT_CLIENT_RESPONSE_CALLBACK_TYPE',
|
|
55
|
+
'INTERSECT_JSON_VALUE',
|
|
56
|
+
'INTERSECT_RESPONSE_VALUE',
|
|
57
|
+
'INTERSECT_SERVICE_RESPONSE_CALLBACK_TYPE',
|
|
58
|
+
'ControlPlaneConfig',
|
|
59
|
+
'ControlProvider',
|
|
60
|
+
'DataStoreConfig',
|
|
61
|
+
'DataStoreConfigMap',
|
|
62
|
+
'HierarchyConfig',
|
|
63
|
+
'IntersectBaseCapabilityImplementation',
|
|
64
|
+
'IntersectCapabilityError',
|
|
65
|
+
'IntersectClient',
|
|
66
|
+
'IntersectClientCallback',
|
|
67
|
+
'IntersectClientConfig',
|
|
68
|
+
'IntersectDataHandler',
|
|
69
|
+
'IntersectDirectMessageParams',
|
|
70
|
+
'IntersectEventDefinition',
|
|
71
|
+
'IntersectEventMessageParams',
|
|
72
|
+
'IntersectMimeType',
|
|
73
|
+
'IntersectService',
|
|
74
|
+
'IntersectServiceConfig',
|
|
75
|
+
'__version__',
|
|
76
|
+
'default_intersect_lifecycle_loop',
|
|
77
|
+
'get_schema_from_capability_implementations',
|
|
78
|
+
'intersect_message',
|
|
79
|
+
'intersect_status',
|
|
80
|
+
'version_info',
|
|
81
|
+
'version_string',
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# PEP 562 stuff: do lazy imports for people who just want to import from the top-level module
|
|
85
|
+
|
|
86
|
+
__lazy_imports = {
|
|
87
|
+
'INTERSECT_CLIENT_EVENT_CALLBACK_TYPE': '.client_callback_definitions',
|
|
88
|
+
'INTERSECT_CLIENT_RESPONSE_CALLBACK_TYPE': '.client_callback_definitions',
|
|
89
|
+
'INTERSECT_JSON_VALUE': '.shared_callback_definitions',
|
|
90
|
+
'INTERSECT_RESPONSE_VALUE': '.shared_callback_definitions',
|
|
91
|
+
'INTERSECT_SERVICE_RESPONSE_CALLBACK_TYPE': '.service_callback_definitions',
|
|
92
|
+
'ControlPlaneConfig': '.config.shared',
|
|
93
|
+
'ControlProvider': '.config.shared',
|
|
94
|
+
'DataStoreConfig': '.config.shared',
|
|
95
|
+
'DataStoreConfigMap': '.config.shared',
|
|
96
|
+
'HierarchyConfig': '.config.shared',
|
|
97
|
+
'IntersectBaseCapabilityImplementation': '.capability.base',
|
|
98
|
+
'IntersectCapabilityError': '.exceptions',
|
|
99
|
+
'IntersectClient': '.client',
|
|
100
|
+
'IntersectClientCallback': '.client_callback_definitions',
|
|
101
|
+
'IntersectClientConfig': '.config.client',
|
|
102
|
+
'IntersectDataHandler': '.core_definitions',
|
|
103
|
+
'IntersectDirectMessageParams': '.shared_callback_definitions',
|
|
104
|
+
'IntersectEventDefinition': '.service_definitions',
|
|
105
|
+
'IntersectEventMessageParams': '.shared_callback_definitions',
|
|
106
|
+
'IntersectMimeType': '.core_definitions',
|
|
107
|
+
'IntersectService': '.service',
|
|
108
|
+
'IntersectServiceConfig': '.config.service',
|
|
109
|
+
'__version__': '.version',
|
|
110
|
+
'default_intersect_lifecycle_loop': '.app_lifecycle',
|
|
111
|
+
'get_schema_from_capability_implementations': '.schema',
|
|
112
|
+
'intersect_message': '.service_definitions',
|
|
113
|
+
'intersect_status': '.service_definitions',
|
|
114
|
+
'version_info': '.version',
|
|
115
|
+
'version_string': '.version',
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def __getattr__(attr_name: str) -> object:
|
|
120
|
+
attr_module = __lazy_imports.get(attr_name)
|
|
121
|
+
if attr_module:
|
|
122
|
+
module = import_module(attr_module, package=__spec__.parent)
|
|
123
|
+
return getattr(module, attr_name)
|
|
124
|
+
|
|
125
|
+
msg = f'module {__name__!r} has no attribute {attr_name!r}'
|
|
126
|
+
raise AttributeError(msg)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def __dir__() -> list[str]:
|
|
130
|
+
return list(__all__)
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
BASE_RESPONSE_ATTR = '__is_intersect_response__'
|
|
2
2
|
BASE_STATUS_ATTR = '__is_intersect_status__'
|
|
3
|
-
BASE_EVENT_ATTR = '__is_intersect_event__'
|
|
4
3
|
# in theory, as long as the next attributes are unique, they can be any string
|
|
5
4
|
REQUEST_CONTENT = '__request_content_type__'
|
|
6
5
|
RESPONSE_CONTENT = '__response_content_type__'
|
|
7
6
|
RESPONSE_DATA = '__response_data_transfer_handler__'
|
|
8
7
|
STRICT_VALIDATION = '__strict_validation__'
|
|
9
8
|
SHUTDOWN_KEYS = '__ignore_message__'
|
|
10
|
-
EVENT_ATTR_KEY = '__intersect_sdk_events__'
|
|
@@ -12,7 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
import functools
|
|
13
13
|
import threading
|
|
14
14
|
from hashlib import sha384
|
|
15
|
-
from typing import TYPE_CHECKING
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
16
|
|
|
17
17
|
import pika
|
|
18
18
|
import pika.delivery_mode
|
|
@@ -24,10 +24,13 @@ from ...multi_flag_thread_event import MultiFlagThreadEvent
|
|
|
24
24
|
from .broker_client import BrokerClient
|
|
25
25
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
|
+
from collections.abc import Callable
|
|
28
|
+
|
|
27
29
|
from pika.channel import Channel
|
|
28
30
|
from pika.frame import Frame
|
|
29
31
|
from pika.spec import Basic, BasicProperties
|
|
30
32
|
|
|
33
|
+
from ..definitions import MessageCallback
|
|
31
34
|
from ..topic_handler import TopicHandler
|
|
32
35
|
|
|
33
36
|
|
|
@@ -191,7 +194,9 @@ class AMQPClient(BrokerClient):
|
|
|
191
194
|
def considered_unrecoverable(self) -> bool:
|
|
192
195
|
return self._unrecoverable
|
|
193
196
|
|
|
194
|
-
def publish(
|
|
197
|
+
def publish(
|
|
198
|
+
self, topic: str, payload: bytes, content_type: str, headers: dict[str, str], persist: bool
|
|
199
|
+
) -> None:
|
|
195
200
|
"""Publish the given message.
|
|
196
201
|
|
|
197
202
|
Publish payload with the pre-existing connection (via connect()) on topic.
|
|
@@ -199,6 +204,8 @@ class AMQPClient(BrokerClient):
|
|
|
199
204
|
Args:
|
|
200
205
|
topic: The topic on which to publish the message as a string
|
|
201
206
|
payload: The message to publish, as raw bytes.
|
|
207
|
+
content_type: The content type of the message (if the data plane used is the control plane itself), or the value to be retrieved from the data plane (if the message handler is MINIO/etc.)
|
|
208
|
+
headers: UTF-8 dictionary which can help parse information about the message
|
|
202
209
|
persist: True if message should persist until consumers available, False if message should be removed immediately.
|
|
203
210
|
"""
|
|
204
211
|
topic = _hierarchy_2_amqp(topic)
|
|
@@ -210,11 +217,11 @@ class AMQPClient(BrokerClient):
|
|
|
210
217
|
routing_key=topic,
|
|
211
218
|
body=payload,
|
|
212
219
|
properties=pika.BasicProperties(
|
|
213
|
-
content_type=
|
|
220
|
+
content_type=content_type,
|
|
221
|
+
headers=headers,
|
|
214
222
|
delivery_mode=pika.delivery_mode.DeliveryMode.Persistent
|
|
215
223
|
if persist
|
|
216
224
|
else pika.delivery_mode.DeliveryMode.Transient,
|
|
217
|
-
# expiration=None if persist else '8640000',
|
|
218
225
|
),
|
|
219
226
|
)
|
|
220
227
|
else:
|
|
@@ -533,7 +540,7 @@ class AMQPClient(BrokerClient):
|
|
|
533
540
|
self,
|
|
534
541
|
channel: Channel,
|
|
535
542
|
basic_deliver: Basic.Deliver,
|
|
536
|
-
|
|
543
|
+
properties: BasicProperties,
|
|
537
544
|
body: bytes,
|
|
538
545
|
persist: bool,
|
|
539
546
|
) -> None:
|
|
@@ -545,7 +552,7 @@ class AMQPClient(BrokerClient):
|
|
|
545
552
|
Args:
|
|
546
553
|
channel: The AMQP channel the message was received on. Used to manually acknowledge messages.
|
|
547
554
|
basic_deliver: Contains internal AMQP delivery information - i.e. the routing key.
|
|
548
|
-
|
|
555
|
+
properties: Object from the AMQP call. Contains various metadata.
|
|
549
556
|
body: the AMQP message to be handled.
|
|
550
557
|
persist: Whether or not our queue should persist on either broker or application shutdown.
|
|
551
558
|
"""
|
|
@@ -557,6 +564,18 @@ class AMQPClient(BrokerClient):
|
|
|
557
564
|
channel.basic_reject(basic_deliver.delivery_tag)
|
|
558
565
|
return
|
|
559
566
|
|
|
567
|
+
# make sure that we have a content-type and headers, note that this does not publish a "reply" message if we fail here
|
|
568
|
+
content_type = properties.content_type
|
|
569
|
+
if not content_type:
|
|
570
|
+
logger.error('Missing message content type')
|
|
571
|
+
channel.basic_ack(basic_deliver.delivery_tag)
|
|
572
|
+
return
|
|
573
|
+
headers = properties.headers
|
|
574
|
+
if not headers:
|
|
575
|
+
logger.error('Missing message headers')
|
|
576
|
+
channel.basic_ack(basic_deliver.delivery_tag)
|
|
577
|
+
return
|
|
578
|
+
|
|
560
579
|
tth_key = _amqp_2_hierarchy(basic_deliver.routing_key)
|
|
561
580
|
topic_handler = self._topics_to_handlers().get(tth_key)
|
|
562
581
|
if topic_handler:
|
|
@@ -571,7 +590,15 @@ class AMQPClient(BrokerClient):
|
|
|
571
590
|
consumer_tag_info.wait(1.0)
|
|
572
591
|
thrd = threading.Thread(
|
|
573
592
|
target=self._consume_message_subthread,
|
|
574
|
-
args=(
|
|
593
|
+
args=(
|
|
594
|
+
channel,
|
|
595
|
+
topic_handler.callbacks,
|
|
596
|
+
body,
|
|
597
|
+
content_type,
|
|
598
|
+
headers,
|
|
599
|
+
basic_deliver.delivery_tag,
|
|
600
|
+
persist,
|
|
601
|
+
),
|
|
575
602
|
)
|
|
576
603
|
self._consumer_tags_to_threads[consumer_tag_info.consumer_tag] = thrd
|
|
577
604
|
thrd.start()
|
|
@@ -582,14 +609,16 @@ class AMQPClient(BrokerClient):
|
|
|
582
609
|
def _consume_message_subthread(
|
|
583
610
|
self,
|
|
584
611
|
channel: Channel,
|
|
585
|
-
callbacks: set[
|
|
612
|
+
callbacks: set[MessageCallback],
|
|
586
613
|
body: bytes,
|
|
614
|
+
content_type: str,
|
|
615
|
+
headers: dict[str, str],
|
|
587
616
|
delivery_tag: int,
|
|
588
617
|
persist: bool,
|
|
589
618
|
) -> None:
|
|
590
619
|
"""This is a subthread which executes the consumer code without blocking the IO loop. Without using a subthread, the AMQP heartbeat checker will be blocked."""
|
|
591
620
|
for cb in callbacks:
|
|
592
|
-
cb(body)
|
|
621
|
+
cb(body, content_type, headers)
|
|
593
622
|
# With persistent messages, we only acknowledge the message AFTER we are done processing
|
|
594
623
|
# (this removes the message from the broker queue)
|
|
595
624
|
# this allows us to retry a message if the broker OR this application goes down
|
|
@@ -32,7 +32,9 @@ class BrokerClient(Protocol):
|
|
|
32
32
|
"""
|
|
33
33
|
...
|
|
34
34
|
|
|
35
|
-
def publish(
|
|
35
|
+
def publish(
|
|
36
|
+
self, topic: str, payload: bytes, content_type: str, headers: dict[str, str], persist: bool
|
|
37
|
+
) -> None:
|
|
36
38
|
"""Publishes the given message.
|
|
37
39
|
|
|
38
40
|
Publish payload with the pre-existing connection (via connect()) on topic.
|
|
@@ -40,6 +42,8 @@ class BrokerClient(Protocol):
|
|
|
40
42
|
Args:
|
|
41
43
|
topic: The topic on which to publish the message as a string.
|
|
42
44
|
payload: The message to publish, as raw bytes.
|
|
45
|
+
content_type: The content type of the message (if the data plane used is the control plane itself), or the value to be retrieved from the data plane (if the message handler is MINIO/etc.)
|
|
46
|
+
headers: UTF-8 dictionary which can help parse information about the message
|
|
43
47
|
persist:
|
|
44
48
|
True = message will persist forever in associated queues until consumers are available (usually used for Userspace messages)
|
|
45
49
|
False = remove message immediately if no consumers available (usually used for Event messages and Lifecycle messages)
|