intersect-sdk-common 0.0.0a0__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_common-0.0.0a0/PKG-INFO +52 -0
- intersect_sdk_common-0.0.0a0/README.md +32 -0
- intersect_sdk_common-0.0.0a0/pyproject.toml +183 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/__init__.py +72 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/config.py +168 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/constants.py +28 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/__init__.py +1 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/brokers/__init__.py +4 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/brokers/amqp_client.py +620 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/brokers/broker_client.py +81 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/brokers/mqtt_client.py +300 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/control_plane_manager.py +172 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/definitions.py +12 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/messages/__init__.py +6 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/messages/event.py +145 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/messages/lifecycle.py +112 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/messages/userspace.py +183 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/control_plane/topic_handler.py +31 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/core_definitions.py +47 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/data_plane/__init__.py +1 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/data_plane/data_plane_manager.py +109 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/data_plane/minio_utils.py +169 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/exceptions.py +19 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/logger.py +5 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/py.typed +0 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/utils/__init__.py +1 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/utils/multi_flag_thread_event.py +82 -0
- intersect_sdk_common-0.0.0a0/src/intersect_sdk_common/version.py +38 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: intersect-sdk-common
|
|
3
|
+
Version: 0.0.0a0
|
|
4
|
+
Summary: Python SDK to interact with INTERSECT
|
|
5
|
+
Keywords: intersect
|
|
6
|
+
Author: Lance Drane, Marshall McDonnell, Seth Hitefield, Andrew Ayres, Gregory Cage, Jesse McGaha, Robert Smith, Gavin Wiggins, Michael Brim, Rick Archibald, Addi Malviya Thakur
|
|
7
|
+
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>
|
|
8
|
+
License: BSD-3-Clause
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Dist: pydantic>=2.7.0
|
|
15
|
+
Requires-Dist: paho-mqtt>=2.1.0,<3.0.0
|
|
16
|
+
Requires-Dist: pika>=1.3.2,<2.0.0
|
|
17
|
+
Requires-Dist: minio>=7.2.3
|
|
18
|
+
Requires-Python: >=3.10, <4.0
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# INTERSECT common libraries
|
|
22
|
+
|
|
23
|
+
This library is meant to provide common definitions across all INTERSECT services, both domain science microservices and INTERSECT core services.
|
|
24
|
+
|
|
25
|
+
## IMPORTANT - READ THIS SECTION
|
|
26
|
+
|
|
27
|
+
If you are developing a domain science application, do NOT import directly from this package. Use the [intersect-sdk](https://github.com/INTERSECT-SDK/python-sdk) package instead. You also don't need to import this package directly, the `intersect-sdk` package will automatically manage this version for you.
|
|
28
|
+
|
|
29
|
+
## Version release policy
|
|
30
|
+
|
|
31
|
+
Note that this package does _not_ follow semantic versioning for everything, as this is meant to be an internal package used by both the INTERSECT SDK and INTERSECT core services; it ONLY follows semantic versioning for the internal message structure.
|
|
32
|
+
|
|
33
|
+
Prior to release 1.0.0, the policy is:
|
|
34
|
+
|
|
35
|
+
- MINOR VERSION CHANGE - if the message structure changes (relevant to end users and the ecosystem)
|
|
36
|
+
- PATCH VERSION CHANGE - any release, which may or may not be breaking (only relevant to the INTERSECT-SDK and INTERSECT core services)
|
|
37
|
+
|
|
38
|
+
After release 1.0.0, the policy is expected to be:
|
|
39
|
+
|
|
40
|
+
- MAJOR VERSION CHANGE - if the message structure changes (relevant to end users and the ecosystem)
|
|
41
|
+
- MINOR VERSION CHANGE - breaking API changes (this is only relevant to the INTERSECT-SDK and INTERSECT core services)
|
|
42
|
+
- PATCH VERSION CHANGE - backwards compatible changes
|
|
43
|
+
|
|
44
|
+
The INTERSECT-SDK MUST follow semantic versioning, and MUST update its semantic version if this package's semantic version is updated.
|
|
45
|
+
|
|
46
|
+
## Developing
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv venv .venv
|
|
50
|
+
source .venv/bin/activate
|
|
51
|
+
uv sync --locked --all-extras --all-groups
|
|
52
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# INTERSECT common libraries
|
|
2
|
+
|
|
3
|
+
This library is meant to provide common definitions across all INTERSECT services, both domain science microservices and INTERSECT core services.
|
|
4
|
+
|
|
5
|
+
## IMPORTANT - READ THIS SECTION
|
|
6
|
+
|
|
7
|
+
If you are developing a domain science application, do NOT import directly from this package. Use the [intersect-sdk](https://github.com/INTERSECT-SDK/python-sdk) package instead. You also don't need to import this package directly, the `intersect-sdk` package will automatically manage this version for you.
|
|
8
|
+
|
|
9
|
+
## Version release policy
|
|
10
|
+
|
|
11
|
+
Note that this package does _not_ follow semantic versioning for everything, as this is meant to be an internal package used by both the INTERSECT SDK and INTERSECT core services; it ONLY follows semantic versioning for the internal message structure.
|
|
12
|
+
|
|
13
|
+
Prior to release 1.0.0, the policy is:
|
|
14
|
+
|
|
15
|
+
- MINOR VERSION CHANGE - if the message structure changes (relevant to end users and the ecosystem)
|
|
16
|
+
- PATCH VERSION CHANGE - any release, which may or may not be breaking (only relevant to the INTERSECT-SDK and INTERSECT core services)
|
|
17
|
+
|
|
18
|
+
After release 1.0.0, the policy is expected to be:
|
|
19
|
+
|
|
20
|
+
- MAJOR VERSION CHANGE - if the message structure changes (relevant to end users and the ecosystem)
|
|
21
|
+
- MINOR VERSION CHANGE - breaking API changes (this is only relevant to the INTERSECT-SDK and INTERSECT core services)
|
|
22
|
+
- PATCH VERSION CHANGE - backwards compatible changes
|
|
23
|
+
|
|
24
|
+
The INTERSECT-SDK MUST follow semantic versioning, and MUST update its semantic version if this package's semantic version is updated.
|
|
25
|
+
|
|
26
|
+
## Developing
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv venv .venv
|
|
30
|
+
source .venv/bin/activate
|
|
31
|
+
uv sync --locked --all-extras --all-groups
|
|
32
|
+
```
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "intersect-sdk-common"
|
|
3
|
+
description = "Python SDK to interact with INTERSECT"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name = "Lance Drane", email = "dranelt@ornl.gov" },
|
|
6
|
+
{ name = "Marshall McDonnell", email = "mcdonnellmt@ornl.gov" },
|
|
7
|
+
{ name = "Seth Hitefield", email = "hitefieldsd@ornl.gov" },
|
|
8
|
+
{ name = "Andrew Ayres", email = "ayresaf@ornl.gov" },
|
|
9
|
+
{ name = "Gregory Cage", email = "cagege@ornl.gov" },
|
|
10
|
+
{ name = "Jesse McGaha", email = "mcgahajr@ornl.gov" },
|
|
11
|
+
{ name = "Robert Smith", email = "smithrw@ornl.gov" },
|
|
12
|
+
{ name = "Gavin Wiggins", email = "wigginsg@ornl.gov" },
|
|
13
|
+
{ name = "Michael Brim", email = "brimmj@ornl.gov" },
|
|
14
|
+
{ name = "Rick Archibald", email = "archibaldrk@ornl.gov" },
|
|
15
|
+
{ name = "Addi Malviya Thakur", email = "malviyaa@ornl.gov" },
|
|
16
|
+
]
|
|
17
|
+
readme = "README.md"
|
|
18
|
+
license = { text = "BSD-3-Clause" }
|
|
19
|
+
requires-python = ">=3.10,<4.0"
|
|
20
|
+
keywords = ["intersect"]
|
|
21
|
+
version = "0.0.0alpha.0"
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"pydantic>=2.7.0",
|
|
31
|
+
"paho-mqtt>=2.1.0,<3.0.0",
|
|
32
|
+
"pika>=1.3.2,<2.0.0",
|
|
33
|
+
"minio>=7.2.3",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[dependency-groups]
|
|
37
|
+
lint = [
|
|
38
|
+
"pre-commit>=3.3.1",
|
|
39
|
+
"ruff==0.12.7",
|
|
40
|
+
"mypy>=1.10.0",
|
|
41
|
+
"codespell>=2.3.0",
|
|
42
|
+
]
|
|
43
|
+
test = ["pytest>=7.3.2", "pytest-cov>=4.1.0", "httpretty>=1.1.4"]
|
|
44
|
+
|
|
45
|
+
[build-system]
|
|
46
|
+
requires = ["uv_build>=0.10.2,<0.11.0"]
|
|
47
|
+
build-backend = "uv_build"
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 100
|
|
51
|
+
format = { quote-style = 'single' }
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
isort = { known-first-party = ['src'] }
|
|
55
|
+
pydocstyle = { convention = 'google' }
|
|
56
|
+
flake8-quotes = { inline-quotes = 'single', multiline-quotes = 'double' }
|
|
57
|
+
mccabe = { max-complexity = 20 }
|
|
58
|
+
pylint = { max-args = 10, max-branches = 20, max-returns = 15, max-statements = 75 }
|
|
59
|
+
# pyflakes and the relevant pycodestyle rules are already configured
|
|
60
|
+
extend-select = [
|
|
61
|
+
'C90', # mccabe complexity
|
|
62
|
+
'I', # isort
|
|
63
|
+
'N', # pep8-naming
|
|
64
|
+
'D', # pydocstyle
|
|
65
|
+
'UP', # pyupgrade
|
|
66
|
+
'YTT', # flake8-2020
|
|
67
|
+
'ANN', # flake8-annotations
|
|
68
|
+
'ASYNC', # flake8-async
|
|
69
|
+
'S', # flake8-bandit
|
|
70
|
+
'BLE', # flake8-blind-except
|
|
71
|
+
'B', # flake8-bugbear
|
|
72
|
+
'A', # flake8-builtins
|
|
73
|
+
'COM', # flake8-commas
|
|
74
|
+
'C4', # flake8-comprehensions
|
|
75
|
+
'DTZ', # flake8-datetimez
|
|
76
|
+
'T10', # flake8-debugger
|
|
77
|
+
'EM', # flake8-error-message
|
|
78
|
+
'FA', # flake8-future-annotations
|
|
79
|
+
'ISC', # flake8-implicit-string-concat
|
|
80
|
+
'ICN', # flake8-import-conventions
|
|
81
|
+
'G', # flake8-logging-format
|
|
82
|
+
'INP', # flake8-no-pep420
|
|
83
|
+
'PIE', # flake8-PIE
|
|
84
|
+
'T20', # flake8-T20
|
|
85
|
+
'PYI', # flake8-pyi
|
|
86
|
+
'PT', # flake8-pytest-style
|
|
87
|
+
'Q', # flake8-quotes
|
|
88
|
+
'RSE', # flake8-raise
|
|
89
|
+
'RET', # flake8-return
|
|
90
|
+
'SLF', # flake8-self
|
|
91
|
+
'SLOT', # flake8-slots
|
|
92
|
+
'SIM', # flake8-simplify
|
|
93
|
+
'TC', # flake8-type-checking
|
|
94
|
+
'ARG', # flake8-unused-arguments
|
|
95
|
+
'PTH', # flake8-use-pathlib
|
|
96
|
+
'PGH', # pygrep-hooks
|
|
97
|
+
'PL', # pylint
|
|
98
|
+
'TRY', # tryceratops
|
|
99
|
+
'FLY', # flynt
|
|
100
|
+
'RUF', # RUFF additional rules
|
|
101
|
+
'INT', # flake8-gettext
|
|
102
|
+
]
|
|
103
|
+
# If you're seeking to disable a rule, first consider whether the rule is overbearing, or if it should only be turned off for your usecase.
|
|
104
|
+
ignore = [
|
|
105
|
+
'COM812', # formatter, handled by Ruff format
|
|
106
|
+
'ISC001', # formatter, handled by Ruff format
|
|
107
|
+
'SIM105', # "with contextlib.suppress():" is slower than try-except-pass
|
|
108
|
+
'ANN401', # allow explicit "Any" typing, use with care
|
|
109
|
+
'PLR2004', # allow "magic numbers"
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
[tool.ruff.lint.flake8-type-checking]
|
|
113
|
+
runtime-evaluated-base-classes = ["pydantic.BaseModel"]
|
|
114
|
+
runtime-evaluated-decorators = ["pydantic.dataclasses.dataclass","pydantic.validate_call"]
|
|
115
|
+
|
|
116
|
+
[tool.ruff.lint.extend-per-file-ignores]
|
|
117
|
+
'__init__.py' = [
|
|
118
|
+
'F401', # __init__.py commonly has unused imports
|
|
119
|
+
'TC004', # do lazy imports when importing from the base module
|
|
120
|
+
]
|
|
121
|
+
'docs/*' = [
|
|
122
|
+
'D', # the documentation folder does not need documentation
|
|
123
|
+
'INP001', # docs are not a namespace package
|
|
124
|
+
]
|
|
125
|
+
'tests/*' = [
|
|
126
|
+
'S101', # allow assert statements in tests
|
|
127
|
+
'S106', # don't care about credentials in tests
|
|
128
|
+
'S311', # don't care about cryptographic security in tests
|
|
129
|
+
'SLF001', # allow private member access in tests
|
|
130
|
+
'ANN', # tests in general don't need types, unless they are runtime types.
|
|
131
|
+
'ARG', # allow unused parameters in tests
|
|
132
|
+
'D', # ignore documentation in tests
|
|
133
|
+
'RUF012', # permit "mutable" class attributes to not be annotated with typing.ClassVar (these shouldn't be mutated anyways...)
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
# see https://mypy.readthedocs.io/en/stable/config_file.html for a complete reference
|
|
137
|
+
[tool.mypy]
|
|
138
|
+
strict = true
|
|
139
|
+
ignore_missing_imports = true # don't require typing for library stubs if they don't exist
|
|
140
|
+
disallow_untyped_decorators = false # this is needed for library decorator compatibility, i.e. "retrying"
|
|
141
|
+
plugins = ["pydantic.mypy"]
|
|
142
|
+
|
|
143
|
+
[tool.pydantic-mypy]
|
|
144
|
+
init_forbid_extra = true
|
|
145
|
+
init_typed = true
|
|
146
|
+
warn_required_dynamic_aliases = true
|
|
147
|
+
warn_untyped_fields = true
|
|
148
|
+
|
|
149
|
+
[tool.pytest.ini_options]
|
|
150
|
+
log_cli = true
|
|
151
|
+
addopts = "-ra"
|
|
152
|
+
|
|
153
|
+
[tool.coverage.report]
|
|
154
|
+
omit = [
|
|
155
|
+
'*__init__*', # __init__ files should just re-export other classes and functions
|
|
156
|
+
]
|
|
157
|
+
exclude_also = [
|
|
158
|
+
'pragma: no-cover', # standard
|
|
159
|
+
'if (typing\\.)?TYPE_CHECKING:', # type checking blocks are not executed in coverage, but we don't care
|
|
160
|
+
'@(abc\\.)?abstractmethod', # don't try to cover abstract methods
|
|
161
|
+
"class .*\\bProtocol\\):", # don't cover protocol classes (similar to abstract classes)
|
|
162
|
+
'raise NotImplementedError', # it's not implemented so shouldn't be covered
|
|
163
|
+
'except.* ImportError', # these are usually used to throw a "friendlier" error and are not really worth testing
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
#[project.scripts]
|
|
168
|
+
#test-all = "pytest tests/ --cov=src/intersect_sdk_common/ --cov-fail-under=80 --cov-report=html:reports/htmlcov/ --cov-report=xml:reports/coverage_report.xml --junitxml=reports/junit.xml"
|
|
169
|
+
#test-all-debug = "pytest tests/ --cov=src/intersect_sdk_common/ --cov-fail-under=80 --cov-report=html:reports/htmlcov/ --cov-report=xml:reports/coverage_report.xml --junitxml=reports/junit.xml -s"
|
|
170
|
+
#test-unit = "pytest tests/unit --cov=src/intersect_sdk_common/"
|
|
171
|
+
#test-e2e = "pytest tests/e2e --cov=src/intersect_sdk_common/"
|
|
172
|
+
#lint-docs = "sphinx-build -W --keep-going docs docs/_build"
|
|
173
|
+
#lint-format = "ruff format"
|
|
174
|
+
#lint-ruff = "ruff check --fix"
|
|
175
|
+
#lint-mypy = "mypy src/intersect_sdk_common/"
|
|
176
|
+
#lint-spelling = "codespell -w docs examples src tests *.md -S docs/_build"
|
|
177
|
+
|
|
178
|
+
[tool.codespell]
|
|
179
|
+
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
|
|
180
|
+
skip = '.git*,*.lock,.venv,.*cache/*,./docs/_build/*'
|
|
181
|
+
check-hidden = true
|
|
182
|
+
# ignore-regex = ''
|
|
183
|
+
# ignore-words-list = ''
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Common definitions shared across ALL INTERSECT services, be they domain science microservices or INTERSECT core services.
|
|
2
|
+
|
|
3
|
+
You can use the base package as the public API, no need to import from submodules.
|
|
4
|
+
|
|
5
|
+
IMPORTANT: If you are building a scientific microservice, do NOT import from this package. Instead, import from intersect-sdk, which is the public-facing library intended for you. Relevant definitions from this package will be re-exported there.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from importlib import import_module
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
# import everything eagerly for IDEs/LSPs
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .config import (
|
|
14
|
+
ControlPlaneConfig,
|
|
15
|
+
ControlProvider,
|
|
16
|
+
DataStoreConfig,
|
|
17
|
+
DataStoreConfigMap,
|
|
18
|
+
HierarchyConfig,
|
|
19
|
+
)
|
|
20
|
+
from .control_plane.control_plane_manager import ControlPlaneManager
|
|
21
|
+
from .control_plane.definitions import MessageCallback
|
|
22
|
+
from .core_definitions import IntersectDataHandler, IntersectMimeType
|
|
23
|
+
from .data_plane.data_plane_manager import DataPlaneManager
|
|
24
|
+
from .version import __version__, intersect_sdk_version_info, intersect_sdk_version_string
|
|
25
|
+
|
|
26
|
+
__all__ = (
|
|
27
|
+
'ControlPlaneConfig',
|
|
28
|
+
'ControlPlaneManager',
|
|
29
|
+
'ControlProvider',
|
|
30
|
+
'DataPlaneManager',
|
|
31
|
+
'DataStoreConfig',
|
|
32
|
+
'DataStoreConfigMap',
|
|
33
|
+
'HierarchyConfig',
|
|
34
|
+
'IntersectDataHandler',
|
|
35
|
+
'IntersectMimeType',
|
|
36
|
+
'MessageCallback',
|
|
37
|
+
'__version__',
|
|
38
|
+
'intersect_sdk_version_info',
|
|
39
|
+
'intersect_sdk_version_string',
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# PEP 562 stuff: do lazy imports for people who just want to import from the top-level module
|
|
43
|
+
|
|
44
|
+
__lazy_imports = {
|
|
45
|
+
'ControlPlaneConfig': '.config',
|
|
46
|
+
'ControlProvider': '.config',
|
|
47
|
+
'DataStoreConfig': '.config',
|
|
48
|
+
'DataStoreConfigMap': '.config',
|
|
49
|
+
'HierarchyConfig': '.config',
|
|
50
|
+
'ControlPlaneManager': '.control_plane.control_plane_manager',
|
|
51
|
+
'MessageCallback': '.control_plane.definitions',
|
|
52
|
+
'IntersectDataHandler': '.core_definitions',
|
|
53
|
+
'IntersectMimeType': '.core_definitions',
|
|
54
|
+
'DataPlaneManager': '.data_plane.data_plane_manager',
|
|
55
|
+
'__version__': '.version',
|
|
56
|
+
'intersect_sdk_version_info': '.version',
|
|
57
|
+
'intersect_sdk_version_string': '.version',
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def __getattr__(attr_name: str) -> object:
|
|
62
|
+
attr_module = __lazy_imports.get(attr_name)
|
|
63
|
+
if attr_module:
|
|
64
|
+
module = import_module(attr_module, package=__spec__.parent)
|
|
65
|
+
return getattr(module, attr_name)
|
|
66
|
+
|
|
67
|
+
msg = f'module {__name__!r} has no attribute {attr_name!r}'
|
|
68
|
+
raise AttributeError(msg)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def __dir__() -> list[str]:
|
|
72
|
+
return list(__all__)
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"""Configuration types shared across both Clients and Services."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Annotated, Literal
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field, PositiveInt
|
|
7
|
+
|
|
8
|
+
from .core_definitions import IntersectDataHandler
|
|
9
|
+
|
|
10
|
+
HIERARCHY_REGEX = r'^[a-z]((?!--)[a-z0-9-]){2,62}$'
|
|
11
|
+
"""
|
|
12
|
+
The hierarchy regex needs to be fairly restricted due to the number of different
|
|
13
|
+
systems we want to be compatible with. The rules:
|
|
14
|
+
|
|
15
|
+
- Only allow unreserved characters (alphanumeric and .-~_): https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
|
|
16
|
+
- Require lowercase letters to avoid incompatibilities with case-insensitive systems.
|
|
17
|
+
- MinIO has been found to forbid _ and ~ characters
|
|
18
|
+
- MinIO requires an alphanumeric character at the start of the string
|
|
19
|
+
- No adjacent non-alphanumeric characters allowed
|
|
20
|
+
- Range should be from 3-63 characters
|
|
21
|
+
|
|
22
|
+
The following commit tracks several issues with MINIO: https://code.ornl.gov/intersect/additive-manufacturing/ros-intersect-adapter/-/commit/fa71b791be0ccf1a5884910b5be3b5239cf9896f
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
ControlProvider = Literal['mqtt5.0', 'amqp0.9.1']
|
|
26
|
+
"""The type of broker we connect to."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class HierarchyConfig(BaseModel):
|
|
30
|
+
"""Configuration for registering this service in a system-of-system architecture."""
|
|
31
|
+
|
|
32
|
+
service: Annotated[str, Field(pattern=HIERARCHY_REGEX)]
|
|
33
|
+
"""
|
|
34
|
+
The name of this application - should be unique within an INTERSECT system
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
subsystem: str | None = Field(default=None, pattern=HIERARCHY_REGEX)
|
|
38
|
+
"""
|
|
39
|
+
An associated subsystem / service-grouping of the system (should be unique within an INTERSECT system)
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
system: Annotated[str, Field(pattern=HIERARCHY_REGEX)]
|
|
43
|
+
"""
|
|
44
|
+
Name of the "system", could also be thought of as a "device" (should be unique within a facility)
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
facility: Annotated[str, Field(pattern=HIERARCHY_REGEX)]
|
|
48
|
+
"""
|
|
49
|
+
Name of the facility (an ORNL institutional designation, i.e. 'neutrons') (NOT abbreviated, should be unique within an organization)
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
organization: Annotated[str, Field(pattern=HIERARCHY_REGEX)]
|
|
53
|
+
"""
|
|
54
|
+
Name of the organization (i.e. 'ornl') (NOT abbreviated) (should be unique in an INTERSECT cluster)
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def hierarchy_string(self, join_str: str = '') -> str:
|
|
58
|
+
"""Get the full hierarchy string. This is mostly used internally, but if you're developing a client, it could potentially be helpful.
|
|
59
|
+
|
|
60
|
+
Params
|
|
61
|
+
join_str: String used to separate different hierarchy parts in the full string (default: empty string).
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Single string, which will contain all system-of-system parts. For optional parts not configured (i.e. - no subsystem), they will be represented by a "-" character.
|
|
65
|
+
"""
|
|
66
|
+
if not self.subsystem:
|
|
67
|
+
return join_str.join([self.organization, self.facility, self.system, '-', self.service])
|
|
68
|
+
return join_str.join(
|
|
69
|
+
[
|
|
70
|
+
self.organization,
|
|
71
|
+
self.facility,
|
|
72
|
+
self.system,
|
|
73
|
+
self.subsystem,
|
|
74
|
+
self.service,
|
|
75
|
+
]
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# we need to use the Python regex engine instead of the Rust regex engine here, because Rust's does not support lookaheads
|
|
79
|
+
model_config = ConfigDict(regex_engine='python-re')
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class ControlPlaneConfig:
|
|
84
|
+
"""Configuration for interacting with a broker."""
|
|
85
|
+
|
|
86
|
+
protocol: ControlProvider
|
|
87
|
+
"""
|
|
88
|
+
The protocol of the broker you'd like to use (i.e. AMQP, MQTT...)
|
|
89
|
+
"""
|
|
90
|
+
# TODO - support more protocols and protocol versions as needed - see https://www.asyncapi.com/docs/reference/specification/v2.6.0#serverObject
|
|
91
|
+
|
|
92
|
+
username: Annotated[str, Field(min_length=1)]
|
|
93
|
+
"""
|
|
94
|
+
Username credentials for broker connection.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
password: Annotated[str, Field(min_length=1)]
|
|
98
|
+
"""
|
|
99
|
+
Password credentials for broker connection.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
host: Annotated[str, Field(min_length=1)] = '127.0.0.1'
|
|
103
|
+
"""
|
|
104
|
+
Broker hostname (default: 127.0.0.1)
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
port: PositiveInt | None = None
|
|
108
|
+
"""
|
|
109
|
+
Broker port. List of common ports:
|
|
110
|
+
|
|
111
|
+
- 1883 (MQTT)
|
|
112
|
+
- 4222 (NATS default port)
|
|
113
|
+
- 5222 (XMPP)
|
|
114
|
+
- 5223 (XMPP over TLS)
|
|
115
|
+
- 5671 (AMQP over TLS)
|
|
116
|
+
- 5672 (AMQP)
|
|
117
|
+
- 7400 (DDS Discovery)
|
|
118
|
+
- 7401 (DDS User traffic)
|
|
119
|
+
- 8883 (MQTT over TLS)
|
|
120
|
+
- 61613 (RabbitMQ STOMP - WARNING: ephemeral port)
|
|
121
|
+
|
|
122
|
+
NOTE: INTERSECT currently only supports AMQP and MQTT.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@dataclass
|
|
127
|
+
class DataStoreConfig:
|
|
128
|
+
"""Configuration for interacting with a data store."""
|
|
129
|
+
|
|
130
|
+
username: Annotated[str, Field(min_length=1)]
|
|
131
|
+
"""
|
|
132
|
+
Username credentials for data store connection.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
password: Annotated[str, Field(min_length=1)]
|
|
136
|
+
"""
|
|
137
|
+
Password credentials for data store connection.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
host: Annotated[str, Field(min_length=1)] = '127.0.0.1'
|
|
141
|
+
"""
|
|
142
|
+
Data store hostname (default: 127.0.0.1)
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
port: PositiveInt | None = None
|
|
146
|
+
"""
|
|
147
|
+
Data store port
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@dataclass
|
|
152
|
+
class DataStoreConfigMap:
|
|
153
|
+
"""Configurations for any data stores the application should talk to."""
|
|
154
|
+
|
|
155
|
+
minio: list[DataStoreConfig] = field(default_factory=list)
|
|
156
|
+
"""
|
|
157
|
+
minio configurations
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
def get_missing_data_store_types(self) -> set[IntersectDataHandler]:
|
|
161
|
+
"""Return a set of IntersectDataHandlers which will not be permitted, due to a configuration type missing.
|
|
162
|
+
|
|
163
|
+
If all data configurations exist, returns an empty set
|
|
164
|
+
"""
|
|
165
|
+
missing = set()
|
|
166
|
+
if not self.minio:
|
|
167
|
+
missing.add(IntersectDataHandler.MINIO)
|
|
168
|
+
return missing
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""These are miscellaneous constants used in INTERSECT which SDK users may obtain value from knowing about."""
|
|
2
|
+
|
|
3
|
+
SYSTEM_OF_SYSTEM_REGEX = r'^[a-z0-9][-a-z0-9.]*[-a-z0-9]$'
|
|
4
|
+
"""
|
|
5
|
+
This is the regex used as a representation of a source/destination.
|
|
6
|
+
This is only needed externally if you are building a client, services can ignore this.
|
|
7
|
+
|
|
8
|
+
NOTE: for future compatibility reasons, we are NOT specifying the number of "parts" (separated by a '.') in this regex. All that matters is that you don't start or end with a period, or start with a hyphen.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# see the internal schema file for full validation details
|
|
12
|
+
CAPABILITY_REGEX = r'^[a-zA-Z0-9]\w*$'
|
|
13
|
+
"""
|
|
14
|
+
This is the regex used for representing capabilities and event keys. Capabilities should start with an alphanumeric character, and not be longer than 255 characters.
|
|
15
|
+
|
|
16
|
+
This regex applies to namespacing local to a Service, so does not have to be unique across the ecosystem.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
MIME_TYPE_REGEX = r'\w+/[-+.\w]+'
|
|
20
|
+
"""
|
|
21
|
+
Regex used for validating Content Types.
|
|
22
|
+
|
|
23
|
+
References can be found at:
|
|
24
|
+
|
|
25
|
+
- https://www.iana.org/assignments/media-types/media-types.xhtml
|
|
26
|
+
|
|
27
|
+
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
|
28
|
+
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Logic associated with the control plane."""
|