muscles-data 0.1.0__py3-none-any.whl
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.
- muscles_data/__init__.py +158 -0
- muscles_data/actions.py +144 -0
- muscles_data/adapters/__init__.py +3 -0
- muscles_data/adapters/memory.py +610 -0
- muscles_data/catalog.py +66 -0
- muscles_data/config.py +47 -0
- muscles_data/contracts.py +140 -0
- muscles_data/errors.py +61 -0
- muscles_data/models.py +323 -0
- muscles_data/package.py +210 -0
- muscles_data/ports.py +196 -0
- muscles_data/runtime.py +251 -0
- muscles_data-0.1.0.dist-info/METADATA +321 -0
- muscles_data-0.1.0.dist-info/RECORD +16 -0
- muscles_data-0.1.0.dist-info/WHEEL +5 -0
- muscles_data-0.1.0.dist-info/top_level.txt +1 -0
muscles_data/__init__.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .catalog import DataAdapterCatalog, DataAdapterFactory
|
|
7
|
+
from .config import DataConfig
|
|
8
|
+
from .models import (
|
|
9
|
+
DataCapability,
|
|
10
|
+
DataEventAckRequest,
|
|
11
|
+
DataEventAckResult,
|
|
12
|
+
DataEventEnvelope,
|
|
13
|
+
DataEventPublishRequest,
|
|
14
|
+
DataEventPublishResult,
|
|
15
|
+
DataEventReadRequest,
|
|
16
|
+
DataEventReadResult,
|
|
17
|
+
DataEventSchemaRef,
|
|
18
|
+
DataResourceConfig,
|
|
19
|
+
)
|
|
20
|
+
from .package import DataPackage
|
|
21
|
+
from .ports import (
|
|
22
|
+
DocumentStorePort,
|
|
23
|
+
EventConsumerPort,
|
|
24
|
+
EventPublisherPort,
|
|
25
|
+
EventStorePort,
|
|
26
|
+
KeyValuePort,
|
|
27
|
+
LockPort,
|
|
28
|
+
ObjectStorePort,
|
|
29
|
+
SearchIndexPort,
|
|
30
|
+
SqlResourcePort,
|
|
31
|
+
StreamPort,
|
|
32
|
+
VectorSearchPort,
|
|
33
|
+
)
|
|
34
|
+
from .runtime import DataResourceHandle, DataRuntime
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"DataAdapterCatalog",
|
|
39
|
+
"DataAdapterFactory",
|
|
40
|
+
"DataCapability",
|
|
41
|
+
"DataEventAckRequest",
|
|
42
|
+
"DataEventAckResult",
|
|
43
|
+
"DataEventEnvelope",
|
|
44
|
+
"DataEventPublishRequest",
|
|
45
|
+
"DataEventPublishResult",
|
|
46
|
+
"DataEventReadRequest",
|
|
47
|
+
"DataEventReadResult",
|
|
48
|
+
"DataEventSchemaRef",
|
|
49
|
+
"DataConfig",
|
|
50
|
+
"DataPackage",
|
|
51
|
+
"DataResourceConfig",
|
|
52
|
+
"DataResourceHandle",
|
|
53
|
+
"DataRuntime",
|
|
54
|
+
"DocumentStorePort",
|
|
55
|
+
"EventConsumerPort",
|
|
56
|
+
"EventPublisherPort",
|
|
57
|
+
"EventStorePort",
|
|
58
|
+
"KeyValuePort",
|
|
59
|
+
"LockPort",
|
|
60
|
+
"ObjectStorePort",
|
|
61
|
+
"SearchIndexPort",
|
|
62
|
+
"SqlResourcePort",
|
|
63
|
+
"StreamPort",
|
|
64
|
+
"VectorSearchPort",
|
|
65
|
+
"init_package",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def __getattr__(name: str):
|
|
70
|
+
if name == "DataAdapterCatalog":
|
|
71
|
+
from .catalog import DataAdapterCatalog
|
|
72
|
+
return DataAdapterCatalog
|
|
73
|
+
if name == "DataAdapterFactory":
|
|
74
|
+
from .catalog import DataAdapterFactory
|
|
75
|
+
return DataAdapterFactory
|
|
76
|
+
if name == "DataCapability":
|
|
77
|
+
from .models import DataCapability
|
|
78
|
+
return DataCapability
|
|
79
|
+
if name == "DataConfig":
|
|
80
|
+
from .config import DataConfig
|
|
81
|
+
return DataConfig
|
|
82
|
+
if name == "DataEventAckRequest":
|
|
83
|
+
from .models import DataEventAckRequest
|
|
84
|
+
return DataEventAckRequest
|
|
85
|
+
if name == "DataEventAckResult":
|
|
86
|
+
from .models import DataEventAckResult
|
|
87
|
+
return DataEventAckResult
|
|
88
|
+
if name == "DataEventEnvelope":
|
|
89
|
+
from .models import DataEventEnvelope
|
|
90
|
+
return DataEventEnvelope
|
|
91
|
+
if name == "DataEventPublishRequest":
|
|
92
|
+
from .models import DataEventPublishRequest
|
|
93
|
+
return DataEventPublishRequest
|
|
94
|
+
if name == "DataEventPublishResult":
|
|
95
|
+
from .models import DataEventPublishResult
|
|
96
|
+
return DataEventPublishResult
|
|
97
|
+
if name == "DataEventReadRequest":
|
|
98
|
+
from .models import DataEventReadRequest
|
|
99
|
+
return DataEventReadRequest
|
|
100
|
+
if name == "DataEventReadResult":
|
|
101
|
+
from .models import DataEventReadResult
|
|
102
|
+
return DataEventReadResult
|
|
103
|
+
if name == "DataEventSchemaRef":
|
|
104
|
+
from .models import DataEventSchemaRef
|
|
105
|
+
return DataEventSchemaRef
|
|
106
|
+
if name == "DataPackage":
|
|
107
|
+
from .package import DataPackage
|
|
108
|
+
return DataPackage
|
|
109
|
+
if name == "DataResourceConfig":
|
|
110
|
+
from .models import DataResourceConfig
|
|
111
|
+
return DataResourceConfig
|
|
112
|
+
if name == "DataResourceHandle":
|
|
113
|
+
from .runtime import DataResourceHandle
|
|
114
|
+
return DataResourceHandle
|
|
115
|
+
if name == "DataRuntime":
|
|
116
|
+
from .runtime import DataRuntime
|
|
117
|
+
return DataRuntime
|
|
118
|
+
if name == "DocumentStorePort":
|
|
119
|
+
from .ports import DocumentStorePort
|
|
120
|
+
return DocumentStorePort
|
|
121
|
+
if name == "EventConsumerPort":
|
|
122
|
+
from .ports import EventConsumerPort
|
|
123
|
+
return EventConsumerPort
|
|
124
|
+
if name == "EventPublisherPort":
|
|
125
|
+
from .ports import EventPublisherPort
|
|
126
|
+
return EventPublisherPort
|
|
127
|
+
if name == "EventStorePort":
|
|
128
|
+
from .ports import EventStorePort
|
|
129
|
+
return EventStorePort
|
|
130
|
+
if name == "KeyValuePort":
|
|
131
|
+
from .ports import KeyValuePort
|
|
132
|
+
return KeyValuePort
|
|
133
|
+
if name == "LockPort":
|
|
134
|
+
from .ports import LockPort
|
|
135
|
+
return LockPort
|
|
136
|
+
if name == "ObjectStorePort":
|
|
137
|
+
from .ports import ObjectStorePort
|
|
138
|
+
return ObjectStorePort
|
|
139
|
+
if name == "SearchIndexPort":
|
|
140
|
+
from .ports import SearchIndexPort
|
|
141
|
+
return SearchIndexPort
|
|
142
|
+
if name == "SqlResourcePort":
|
|
143
|
+
from .ports import SqlResourcePort
|
|
144
|
+
return SqlResourcePort
|
|
145
|
+
if name == "StreamPort":
|
|
146
|
+
from .ports import StreamPort
|
|
147
|
+
return StreamPort
|
|
148
|
+
if name == "VectorSearchPort":
|
|
149
|
+
from .ports import VectorSearchPort
|
|
150
|
+
return VectorSearchPort
|
|
151
|
+
if name == "init_package":
|
|
152
|
+
from .package import init_package
|
|
153
|
+
return init_package
|
|
154
|
+
raise AttributeError(name)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def __dir__():
|
|
158
|
+
return sorted(__all__)
|
muscles_data/actions.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from contextlib import contextmanager
|
|
4
|
+
from dataclasses import asdict, is_dataclass
|
|
5
|
+
from typing import Any, Iterator
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from muscles import ActionContext
|
|
9
|
+
except Exception: # pragma: no cover
|
|
10
|
+
from muscles.core.core import ActionContext
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from muscles import register_action # type: ignore[import-not-found]
|
|
14
|
+
except Exception: # pragma: no cover
|
|
15
|
+
register_action = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
EMPTY_SCHEMA = {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {},
|
|
21
|
+
"additionalProperties": False,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
RESOURCE_SCHEMA = {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"name": {"type": "string"},
|
|
28
|
+
},
|
|
29
|
+
"required": ["name"],
|
|
30
|
+
"additionalProperties": False,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def register_data_actions(app, *, transports: list[str]) -> None:
|
|
35
|
+
_register_action(
|
|
36
|
+
app,
|
|
37
|
+
name="data.resources.list",
|
|
38
|
+
description="List configured data resources without initializing backends.",
|
|
39
|
+
input_schema=EMPTY_SCHEMA,
|
|
40
|
+
handler=_resources_list,
|
|
41
|
+
transports=transports,
|
|
42
|
+
)
|
|
43
|
+
_register_action(
|
|
44
|
+
app,
|
|
45
|
+
name="data.resource.inspect",
|
|
46
|
+
description="Inspect one configured data resource without leaking secrets.",
|
|
47
|
+
input_schema=RESOURCE_SCHEMA,
|
|
48
|
+
handler=_resource_inspect,
|
|
49
|
+
transports=transports,
|
|
50
|
+
)
|
|
51
|
+
_register_action(
|
|
52
|
+
app,
|
|
53
|
+
name="data.doctor",
|
|
54
|
+
description="Run safe data resource diagnostics.",
|
|
55
|
+
input_schema=EMPTY_SCHEMA,
|
|
56
|
+
handler=_doctor,
|
|
57
|
+
transports=transports,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _register_action(app, **kwargs):
|
|
62
|
+
if register_action is not None:
|
|
63
|
+
return register_action(app, **kwargs)
|
|
64
|
+
from muscles.core.core import ActionContract, get_application_registry
|
|
65
|
+
|
|
66
|
+
return get_application_registry(app).add_action(
|
|
67
|
+
ActionContract(
|
|
68
|
+
name=kwargs["name"],
|
|
69
|
+
description=kwargs.get("description", ""),
|
|
70
|
+
input_schema=kwargs.get("input_schema", None),
|
|
71
|
+
output_schema=kwargs.get("output_schema", None),
|
|
72
|
+
rules=kwargs.get("rules", []),
|
|
73
|
+
handler_ref=kwargs.get("handler_ref", None),
|
|
74
|
+
transports=kwargs.get("transports", []),
|
|
75
|
+
stream_output=kwargs.get("stream_output", False),
|
|
76
|
+
stream_metadata=kwargs.get("stream_metadata", None) or {},
|
|
77
|
+
metadata=kwargs.get("metadata", None) or {},
|
|
78
|
+
handler=kwargs.get("handler"),
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _runtime(context: ActionContext):
|
|
84
|
+
from .runtime import DataRuntime
|
|
85
|
+
|
|
86
|
+
container = getattr(context.application, "container", None)
|
|
87
|
+
if container is None:
|
|
88
|
+
raise RuntimeError("data runtime is not initialized")
|
|
89
|
+
try:
|
|
90
|
+
return container.resolve(DataRuntime)
|
|
91
|
+
except KeyError as exc:
|
|
92
|
+
raise RuntimeError("data runtime is not registered") from exc
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _resources_list(payload: dict[str, Any], context: ActionContext) -> dict[str, Any]:
|
|
96
|
+
del payload
|
|
97
|
+
runtime = _runtime(context)
|
|
98
|
+
with _telemetry(context).span("muscles.data.resources.list", **{"data.operation": "resources.list"}):
|
|
99
|
+
return {"resources": runtime.list_resources()}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _resource_inspect(payload: dict[str, Any], context: ActionContext) -> dict[str, Any]:
|
|
103
|
+
runtime = _runtime(context)
|
|
104
|
+
name = payload["name"]
|
|
105
|
+
with _telemetry(context).span(
|
|
106
|
+
"muscles.data.resource.inspect",
|
|
107
|
+
**{"data.resource.name": name, "data.operation": "resource.inspect"},
|
|
108
|
+
):
|
|
109
|
+
return _serialize(runtime.inspect_resource(name))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _doctor(payload: dict[str, Any], context: ActionContext) -> dict[str, Any]:
|
|
113
|
+
del payload
|
|
114
|
+
runtime = _runtime(context)
|
|
115
|
+
with _telemetry(context).span("muscles.data.doctor", **{"data.operation": "doctor"}):
|
|
116
|
+
return _serialize(runtime.doctor())
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _telemetry(context: ActionContext):
|
|
120
|
+
try:
|
|
121
|
+
from muscles import resolve_telemetry # type: ignore[import-not-found]
|
|
122
|
+
|
|
123
|
+
return resolve_telemetry(context.application)
|
|
124
|
+
except Exception:
|
|
125
|
+
return _NoopTelemetry()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _serialize(value: Any):
|
|
129
|
+
if is_dataclass(value):
|
|
130
|
+
return asdict(value)
|
|
131
|
+
if isinstance(value, list):
|
|
132
|
+
return [_serialize(item) for item in value]
|
|
133
|
+
if isinstance(value, tuple):
|
|
134
|
+
return [_serialize(item) for item in value]
|
|
135
|
+
if isinstance(value, dict):
|
|
136
|
+
return {key: _serialize(item) for key, item in value.items()}
|
|
137
|
+
return value
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class _NoopTelemetry:
|
|
141
|
+
@contextmanager
|
|
142
|
+
def span(self, name: str, **attributes: Any) -> Iterator[None]:
|
|
143
|
+
del name, attributes
|
|
144
|
+
yield
|