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.
@@ -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__)
@@ -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
@@ -0,0 +1,3 @@
1
+ from __future__ import annotations
2
+
3
+ __all__ = []