tracdap-runtime 0.6.1.dev3__py3-none-any.whl → 0.6.3__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.
- tracdap/rt/_exec/actors.py +87 -10
- tracdap/rt/_exec/context.py +25 -1
- tracdap/rt/_exec/dev_mode.py +277 -221
- tracdap/rt/_exec/engine.py +79 -14
- tracdap/rt/_exec/functions.py +37 -8
- tracdap/rt/_exec/graph.py +2 -0
- tracdap/rt/_exec/graph_builder.py +118 -56
- tracdap/rt/_exec/runtime.py +108 -37
- tracdap/rt/_exec/server.py +345 -0
- tracdap/rt/_impl/config_parser.py +219 -49
- tracdap/rt/_impl/data.py +14 -0
- tracdap/rt/_impl/grpc/__init__.py +13 -0
- tracdap/rt/_impl/grpc/codec.py +99 -0
- tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.py +51 -0
- tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.pyi +61 -0
- tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2_grpc.py +183 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/common_pb2.py +33 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/common_pb2.pyi +34 -0
- tracdap/rt/{metadata → _impl/grpc/tracdap/metadata}/custom_pb2.py +5 -5
- tracdap/rt/_impl/grpc/tracdap/metadata/custom_pb2.pyi +15 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.py +51 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.pyi +115 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.py +28 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.pyi +22 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/flow_pb2.py +59 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/flow_pb2.pyi +109 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.py +76 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.pyi +177 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.py +63 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.pyi +119 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.py +32 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.pyi +68 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.py +40 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.pyi +46 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/search_pb2.py +39 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/search_pb2.pyi +83 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/stoarge_pb2.py +50 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/stoarge_pb2.pyi +89 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/tag_pb2.py +34 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/tag_pb2.pyi +26 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/tag_update_pb2.py +30 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/tag_update_pb2.pyi +34 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/type_pb2.py +47 -0
- tracdap/rt/_impl/grpc/tracdap/metadata/type_pb2.pyi +101 -0
- tracdap/rt/_impl/guard_rails.py +26 -6
- tracdap/rt/_impl/models.py +25 -0
- tracdap/rt/_impl/static_api.py +27 -9
- tracdap/rt/_impl/type_system.py +17 -0
- tracdap/rt/_impl/validation.py +10 -0
- tracdap/rt/_plugins/config_local.py +49 -0
- tracdap/rt/_version.py +1 -1
- tracdap/rt/api/hook.py +10 -3
- tracdap/rt/api/model_api.py +22 -0
- tracdap/rt/api/static_api.py +79 -19
- tracdap/rt/config/__init__.py +3 -3
- tracdap/rt/config/common.py +10 -0
- tracdap/rt/config/platform.py +9 -19
- tracdap/rt/config/runtime.py +2 -0
- tracdap/rt/ext/config.py +34 -0
- tracdap/rt/ext/embed.py +1 -3
- tracdap/rt/ext/plugins.py +47 -6
- tracdap/rt/launch/cli.py +7 -5
- tracdap/rt/launch/launch.py +49 -12
- tracdap/rt/metadata/__init__.py +24 -24
- tracdap/rt/metadata/common.py +7 -7
- tracdap/rt/metadata/custom.py +2 -0
- tracdap/rt/metadata/data.py +28 -5
- tracdap/rt/metadata/file.py +2 -0
- tracdap/rt/metadata/flow.py +66 -4
- tracdap/rt/metadata/job.py +56 -16
- tracdap/rt/metadata/model.py +10 -0
- tracdap/rt/metadata/object.py +3 -0
- tracdap/rt/metadata/object_id.py +9 -9
- tracdap/rt/metadata/search.py +35 -13
- tracdap/rt/metadata/stoarge.py +64 -6
- tracdap/rt/metadata/tag_update.py +21 -7
- tracdap/rt/metadata/type.py +28 -13
- {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/METADATA +22 -19
- tracdap_runtime-0.6.3.dist-info/RECORD +112 -0
- {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/WHEEL +1 -1
- tracdap/rt/config/common_pb2.py +0 -55
- tracdap/rt/config/job_pb2.py +0 -42
- tracdap/rt/config/platform_pb2.py +0 -71
- tracdap/rt/config/result_pb2.py +0 -37
- tracdap/rt/config/runtime_pb2.py +0 -42
- tracdap/rt/ext/_guard.py +0 -37
- tracdap/rt/metadata/common_pb2.py +0 -33
- tracdap/rt/metadata/data_pb2.py +0 -51
- tracdap/rt/metadata/file_pb2.py +0 -28
- tracdap/rt/metadata/flow_pb2.py +0 -55
- tracdap/rt/metadata/job_pb2.py +0 -76
- tracdap/rt/metadata/model_pb2.py +0 -51
- tracdap/rt/metadata/object_id_pb2.py +0 -32
- tracdap/rt/metadata/object_pb2.py +0 -35
- tracdap/rt/metadata/search_pb2.py +0 -39
- tracdap/rt/metadata/stoarge_pb2.py +0 -50
- tracdap/rt/metadata/tag_pb2.py +0 -34
- tracdap/rt/metadata/tag_update_pb2.py +0 -30
- tracdap/rt/metadata/type_pb2.py +0 -48
- tracdap_runtime-0.6.1.dev3.dist-info/RECORD +0 -96
- {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/LICENSE +0 -0
- {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/top_level.txt +0 -0
@@ -14,89 +14,216 @@
|
|
14
14
|
|
15
15
|
from __future__ import annotations
|
16
16
|
|
17
|
-
import
|
18
|
-
import typing as tp
|
17
|
+
import dataclasses as _dc
|
19
18
|
import decimal
|
20
19
|
import enum
|
21
|
-
import
|
20
|
+
import io
|
22
21
|
import inspect
|
23
|
-
import
|
22
|
+
import json
|
23
|
+
import os
|
24
|
+
import pathlib
|
25
|
+
import re
|
26
|
+
import typing as tp
|
27
|
+
import urllib.parse as _urlp
|
28
|
+
import uuid
|
24
29
|
|
30
|
+
import tracdap.rt.config as _config
|
25
31
|
import tracdap.rt.exceptions as _ex
|
32
|
+
import tracdap.rt.ext.plugins as _plugins
|
33
|
+
import tracdap.rt.ext.config as _config_ext
|
26
34
|
import tracdap.rt._impl.util as _util
|
27
35
|
|
28
|
-
import pathlib
|
29
|
-
import json
|
30
36
|
import yaml
|
31
37
|
import yaml.parser
|
32
38
|
|
33
|
-
|
34
39
|
_T = tp.TypeVar('_T')
|
35
40
|
|
36
41
|
|
37
|
-
class
|
42
|
+
class ConfigManager:
|
38
43
|
|
39
|
-
|
40
|
-
|
41
|
-
|
44
|
+
@classmethod
|
45
|
+
def for_root_config(cls, root_config_file: tp.Union[str, pathlib.Path, None]) -> ConfigManager:
|
46
|
+
|
47
|
+
if isinstance(root_config_file, pathlib.Path):
|
48
|
+
root_file_path = cls._resolve_scheme(root_config_file)
|
49
|
+
root_dir_path = cls._resolve_scheme(root_config_file.parent)
|
50
|
+
if root_dir_path[-1] not in ["/", "\\"]:
|
51
|
+
root_dir_path += os.sep
|
52
|
+
root_file_url = _urlp.urlparse(root_file_path, scheme="file")
|
53
|
+
root_dir_url = _urlp.urlparse(root_dir_path, scheme="file")
|
54
|
+
return ConfigManager(root_dir_url, root_file_url, )
|
55
|
+
|
56
|
+
elif isinstance(root_config_file, str):
|
57
|
+
root_file_with_scheme = cls._resolve_scheme(root_config_file)
|
58
|
+
root_file_url = _urlp.urlparse(root_file_with_scheme, scheme="file")
|
59
|
+
root_dir_path = str(pathlib.Path(root_file_url.path).parent)
|
60
|
+
if root_dir_path[-1] not in ["/", "\\"]:
|
61
|
+
root_dir_path += os.sep if root_file_url.scheme == "file" else "/"
|
62
|
+
root_dir_url = _urlp.urlparse(_urlp.urljoin(root_file_url.geturl(), root_dir_path))
|
63
|
+
return ConfigManager(root_dir_url, root_file_url)
|
42
64
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
str: str,
|
48
|
-
decimal.Decimal: decimal.Decimal
|
49
|
-
# TODO: Date (requires type system)
|
50
|
-
# TODO: Datetime (requires type system)
|
51
|
-
}
|
65
|
+
else:
|
66
|
+
working_dir_path = str(pathlib.Path.cwd().resolve())
|
67
|
+
working_dir_url = _urlp.urlparse(str(working_dir_path), scheme="file")
|
68
|
+
return ConfigManager(working_dir_url, None)
|
52
69
|
|
53
|
-
|
70
|
+
@classmethod
|
71
|
+
def for_root_dir(cls, root_config_dir: tp.Union[str, pathlib.Path]) -> ConfigManager:
|
72
|
+
|
73
|
+
if isinstance(root_config_dir, pathlib.Path):
|
74
|
+
root_dir_path = cls._resolve_scheme(root_config_dir)
|
75
|
+
if root_dir_path[-1] not in ["/", "\\"]:
|
76
|
+
root_dir_path += os.sep
|
77
|
+
root_dir_url = _urlp.urlparse(root_dir_path, scheme="file")
|
78
|
+
return ConfigManager(root_dir_url, None)
|
79
|
+
|
80
|
+
elif isinstance(root_config_dir, str):
|
81
|
+
root_dir_with_scheme = cls._resolve_scheme(root_config_dir)
|
82
|
+
if root_dir_with_scheme[-1] not in ["/", "\\"]:
|
83
|
+
root_dir_with_scheme += "/"
|
84
|
+
root_dir_url = _urlp.urlparse(root_dir_with_scheme, scheme="file")
|
85
|
+
return ConfigManager(root_dir_url, None)
|
86
|
+
|
87
|
+
# Should never happen since root dir is specified explicitly
|
88
|
+
else:
|
89
|
+
raise _ex.ETracInternal("Wrong parameter type for root_config_dir")
|
90
|
+
|
91
|
+
@classmethod
|
92
|
+
def _resolve_scheme(cls, raw_url: tp.Union[str, pathlib.Path]) -> str:
|
93
|
+
|
94
|
+
if isinstance(raw_url, pathlib.Path):
|
95
|
+
return "file:" + str(raw_url.resolve())
|
96
|
+
|
97
|
+
# Look for drive letters on Windows - these can be mis-interpreted as URL scheme
|
98
|
+
# If there is a drive letter, explicitly set scheme = file instead
|
99
|
+
if len(raw_url) > 1 and raw_url[1] == ":":
|
100
|
+
return "file:" + raw_url
|
101
|
+
else:
|
102
|
+
return raw_url
|
103
|
+
|
104
|
+
def __init__(self, root_dir_url: _urlp.ParseResult, root_file_url: tp.Optional[_urlp.ParseResult]):
|
54
105
|
self._log = _util.logger_for_object(self)
|
55
|
-
self.
|
56
|
-
self.
|
57
|
-
|
106
|
+
self._root_dir_url = root_dir_url
|
107
|
+
self._root_file_url = root_file_url
|
108
|
+
|
109
|
+
def config_dir_path(self):
|
110
|
+
if self._root_dir_url.scheme == "file":
|
111
|
+
return pathlib.Path(self._root_dir_url.path).resolve()
|
112
|
+
else:
|
113
|
+
return None
|
114
|
+
|
115
|
+
def load_root_object(
|
116
|
+
self, config_class: type(_T),
|
117
|
+
dev_mode_locations: tp.List[str] = None,
|
118
|
+
config_file_name: tp.Optional[str] = None) -> _T:
|
58
119
|
|
59
|
-
|
120
|
+
# Root config not available normally means you're using embedded config
|
121
|
+
# In which case this method should not be called
|
122
|
+
if self._root_file_url is None:
|
123
|
+
message = f"Root config file not available"
|
124
|
+
self._log.error(message)
|
125
|
+
raise _ex.EConfigLoad(message)
|
126
|
+
|
127
|
+
resolved_url = self._root_file_url
|
60
128
|
|
61
129
|
if config_file_name is not None:
|
62
|
-
self._log.info(f"Loading {config_file_name} config: {
|
130
|
+
self._log.info(f"Loading {config_file_name} config: {self._url_to_str(resolved_url)}")
|
63
131
|
else:
|
64
|
-
self._log.info(f"Loading config file: {
|
132
|
+
self._log.info(f"Loading config file: {self._url_to_str(resolved_url)}")
|
133
|
+
|
134
|
+
config_dict = self._load_config_dict(resolved_url)
|
65
135
|
|
66
|
-
|
67
|
-
|
136
|
+
parser = ConfigParser(config_class, dev_mode_locations)
|
137
|
+
return parser.parse(config_dict, resolved_url.path)
|
68
138
|
|
69
|
-
|
70
|
-
|
139
|
+
def load_config_object(
|
140
|
+
self, config_url: tp.Union[str, pathlib.Path],
|
141
|
+
config_class: type(_T),
|
142
|
+
dev_mode_locations: tp.List[str] = None,
|
143
|
+
config_file_name: tp.Optional[str] = None) -> _T:
|
71
144
|
|
72
|
-
|
73
|
-
config_path = config_file
|
145
|
+
resolved_url = self._resolve_config_file(config_url)
|
74
146
|
|
147
|
+
if config_file_name is not None:
|
148
|
+
self._log.info(f"Loading {config_file_name} config: {self._url_to_str(resolved_url)}")
|
75
149
|
else:
|
76
|
-
|
77
|
-
err = f"Attempt to load an invalid config file, expected a path, got {config_file_type}"
|
78
|
-
self._log.error(err)
|
79
|
-
raise _ex.EConfigLoad(err)
|
150
|
+
self._log.info(f"Loading config file: {self._url_to_str(resolved_url)}")
|
80
151
|
|
81
|
-
|
82
|
-
msg = f"Config file not found: [{config_file}]"
|
83
|
-
self._log.error(msg)
|
84
|
-
raise _ex.EConfigLoad(msg)
|
152
|
+
config_dict = self._load_config_dict(resolved_url)
|
85
153
|
|
86
|
-
|
87
|
-
|
88
|
-
self._log.error(msg)
|
89
|
-
raise _ex.EConfigLoad(msg)
|
154
|
+
parser = ConfigParser(config_class, dev_mode_locations)
|
155
|
+
return parser.parse(config_dict, config_url)
|
90
156
|
|
91
|
-
|
157
|
+
def load_config_file(
|
158
|
+
self, config_url: tp.Union[str, pathlib.Path],
|
159
|
+
config_file_name: tp.Optional[str] = None) -> bytes:
|
92
160
|
|
93
|
-
|
161
|
+
resolved_url = self._resolve_config_file(config_url)
|
162
|
+
|
163
|
+
if config_file_name is not None:
|
164
|
+
self._log.info(f"Loading {config_file_name} config: {self._url_to_str(resolved_url)}")
|
165
|
+
else:
|
166
|
+
self._log.info(f"Loading config file: {self._url_to_str(resolved_url)}")
|
167
|
+
|
168
|
+
return self._load_config_file(resolved_url)
|
169
|
+
|
170
|
+
def _resolve_config_file(self, config_url: tp.Union[str, pathlib.Path]) -> _urlp.ParseResult:
|
171
|
+
|
172
|
+
# If the config URL defines a scheme, treat it as absolute
|
173
|
+
# (This also works for Windows paths, C:\ is an absolute path)
|
174
|
+
if ":" in str(config_url):
|
175
|
+
absolute_url = str(config_url)
|
176
|
+
# If the root URL is a path, resolve using path logic (this allows for config_url to be an absolute path)
|
177
|
+
elif self._root_dir_url.scheme == "file":
|
178
|
+
absolute_url = str(pathlib.Path(self._root_dir_url.path).joinpath(str(config_url)))
|
179
|
+
# Otherwise resolve relative to the root URL
|
180
|
+
else:
|
181
|
+
absolute_url = _urlp.urljoin(self._root_dir_url.geturl(), str(config_url))
|
182
|
+
|
183
|
+
# Look for drive letters on Windows - these can be mis-interpreted as URL scheme
|
184
|
+
# If there is a drive letter, explicitly set scheme = file instead
|
185
|
+
if len(absolute_url) > 1 and absolute_url[1] == ":":
|
186
|
+
absolute_url = "file:" + absolute_url
|
187
|
+
|
188
|
+
return _urlp.urlparse(absolute_url, scheme="file")
|
189
|
+
|
190
|
+
def _load_config_file(self, resolved_url: _urlp.ParseResult) -> bytes:
|
191
|
+
|
192
|
+
loader = self._get_loader(resolved_url)
|
193
|
+
config_url = self._url_to_str(resolved_url)
|
194
|
+
|
195
|
+
if not loader.has_config_file(config_url):
|
196
|
+
message = f"Config file not found: {config_url}"
|
197
|
+
self._log.error(message)
|
198
|
+
raise _ex.EConfigLoad(message)
|
199
|
+
|
200
|
+
return loader.load_config_file(config_url)
|
201
|
+
|
202
|
+
def _load_config_dict(self, resolved_url: _urlp.ParseResult) -> dict:
|
203
|
+
|
204
|
+
loader = self._get_loader(resolved_url)
|
205
|
+
config_url = self._url_to_str(resolved_url)
|
206
|
+
|
207
|
+
if loader.has_config_dict(config_url):
|
208
|
+
return loader.load_config_dict(config_url)
|
209
|
+
|
210
|
+
elif loader.has_config_file(config_url):
|
211
|
+
config_bytes = loader.load_config_file(config_url)
|
212
|
+
config_path = pathlib.Path(resolved_url.path)
|
213
|
+
return self._parse_config_dict(config_bytes, config_path)
|
214
|
+
|
215
|
+
else:
|
216
|
+
message = f"Config file not found: {config_url}"
|
217
|
+
self._log.error(message)
|
218
|
+
raise _ex.EConfigLoad(message)
|
219
|
+
|
220
|
+
def _parse_config_dict(self, config_bytes: bytes, config_path: pathlib.Path):
|
94
221
|
|
95
222
|
# Read in the raw config, use the file extension to decide which format to expect
|
96
223
|
|
97
224
|
try:
|
98
225
|
|
99
|
-
with
|
226
|
+
with io.BytesIO(config_bytes) as config_stream:
|
100
227
|
|
101
228
|
extension = config_path.suffix.lower()
|
102
229
|
|
@@ -123,11 +250,54 @@ class ConfigParser(tp.Generic[_T]):
|
|
123
250
|
self._log.error(err)
|
124
251
|
raise _ex.EConfigParse(err) from e
|
125
252
|
|
126
|
-
except yaml.parser.ParserError as e:
|
253
|
+
except (yaml.parser.ParserError, yaml.reader.ReaderError) as e:
|
127
254
|
err = f"Config file contains invalid YAML ({str(e)})"
|
128
255
|
self._log.error(err)
|
129
256
|
raise _ex.EConfigParse(err) from e
|
130
257
|
|
258
|
+
def _get_loader(self, resolved_url: _urlp.ParseResult) -> _config_ext.IConfigLoader:
|
259
|
+
|
260
|
+
protocol = resolved_url.scheme
|
261
|
+
loader_config = _config.PluginConfig(protocol)
|
262
|
+
|
263
|
+
if not _plugins.PluginManager.is_plugin_available(_config_ext.IConfigLoader, protocol):
|
264
|
+
message = f"No config loader available for protocol [{protocol}]: {self._url_to_str(resolved_url)}"
|
265
|
+
self._log.error(message)
|
266
|
+
raise _ex.EConfigLoad(message)
|
267
|
+
|
268
|
+
return _plugins.PluginManager.load_config_plugin(_config_ext.IConfigLoader, loader_config)
|
269
|
+
|
270
|
+
@staticmethod
|
271
|
+
def _url_to_str(url: _urlp.ParseResult) -> str:
|
272
|
+
|
273
|
+
if url.scheme == "file" and not url.netloc:
|
274
|
+
return url.path
|
275
|
+
else:
|
276
|
+
return url.geturl()
|
277
|
+
|
278
|
+
|
279
|
+
class ConfigParser(tp.Generic[_T]):
|
280
|
+
|
281
|
+
# The metaclass for generic types varies between versions of the typing library
|
282
|
+
# To work around this, detect the correct metaclass by inspecting a generic type variable
|
283
|
+
__generic_metaclass = type(tp.List[object])
|
284
|
+
|
285
|
+
__primitive_types: tp.Dict[type, callable] = {
|
286
|
+
bool: bool,
|
287
|
+
int: int,
|
288
|
+
float: float,
|
289
|
+
str: str,
|
290
|
+
decimal.Decimal: decimal.Decimal
|
291
|
+
# TODO: Date (requires type system)
|
292
|
+
# TODO: Datetime (requires type system)
|
293
|
+
}
|
294
|
+
|
295
|
+
def __init__(self, config_class: _T.__class__, dev_mode_locations: tp.List[str] = None):
|
296
|
+
self._log = _util.logger_for_object(self)
|
297
|
+
self._config_class = config_class
|
298
|
+
self._dev_mode_locations = dev_mode_locations or []
|
299
|
+
self._errors = []
|
300
|
+
|
131
301
|
def parse(self, config_dict: dict, config_file: tp.Union[str, pathlib.Path] = None) -> _T:
|
132
302
|
|
133
303
|
# If config is empty, return a default (blank) config
|
tracdap/rt/_impl/data.py
CHANGED
@@ -58,6 +58,13 @@ class DataItem:
|
|
58
58
|
pandas: tp.Optional[pd.DataFrame] = None
|
59
59
|
pyspark: tp.Any = None
|
60
60
|
|
61
|
+
def is_empty(self) -> bool:
|
62
|
+
return self.table is None and (self.batches is None or len(self.batches) == 0)
|
63
|
+
|
64
|
+
@staticmethod
|
65
|
+
def create_empty() -> DataItem:
|
66
|
+
return DataItem(pa.schema([]))
|
67
|
+
|
61
68
|
|
62
69
|
@dc.dataclass(frozen=True)
|
63
70
|
class DataView:
|
@@ -72,6 +79,13 @@ class DataView:
|
|
72
79
|
arrow_schema = DataMapping.trac_to_arrow_schema(trac_schema)
|
73
80
|
return DataView(trac_schema, arrow_schema, dict())
|
74
81
|
|
82
|
+
def is_empty(self) -> bool:
|
83
|
+
return self.parts is None or len(self.parts) == 0
|
84
|
+
|
85
|
+
@staticmethod
|
86
|
+
def create_empty() -> DataView:
|
87
|
+
return DataView(_meta.SchemaDefinition(), pa.schema([]), dict())
|
88
|
+
|
75
89
|
|
76
90
|
class _DataInternal:
|
77
91
|
pass
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Copyright 2024 Accenture Global Solutions Limited
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# Copyright 2024 Accenture Global Solutions Limited
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
import enum
|
16
|
+
import typing as tp
|
17
|
+
|
18
|
+
import tracdap.rt.exceptions as ex
|
19
|
+
import tracdap.rt.metadata as metadata
|
20
|
+
|
21
|
+
import tracdap.rt._impl.grpc.tracdap.metadata.type_pb2 as type_pb2
|
22
|
+
import tracdap.rt._impl.grpc.tracdap.metadata.object_id_pb2 as object_id_pb2
|
23
|
+
import tracdap.rt._impl.grpc.tracdap.metadata.object_pb2 as object_pb2
|
24
|
+
from tracdap.rt._impl.grpc.tracdap.metadata import model_pb2
|
25
|
+
import tracdap.rt._impl.grpc.tracdap.metadata.data_pb2 as data_pb2
|
26
|
+
import tracdap.rt._impl.grpc.tracdap.metadata.stoarge_pb2 as storage_pb2
|
27
|
+
|
28
|
+
from google.protobuf import message as _message
|
29
|
+
|
30
|
+
|
31
|
+
__METADATA_MAPPING = {
|
32
|
+
metadata.TypeDescriptor: type_pb2.TypeDescriptor,
|
33
|
+
metadata.Value: type_pb2.Value,
|
34
|
+
metadata.DecimalValue: type_pb2.DecimalValue,
|
35
|
+
metadata.DateValue: type_pb2.DateValue,
|
36
|
+
metadata.DatetimeValue: type_pb2.DatetimeValue,
|
37
|
+
metadata.ArrayValue: type_pb2.ArrayValue,
|
38
|
+
metadata.MapValue: type_pb2.MapValue,
|
39
|
+
metadata.TagHeader: object_id_pb2.TagHeader,
|
40
|
+
metadata.TagSelector: object_id_pb2.TagSelector,
|
41
|
+
metadata.ObjectDefinition: object_pb2.ObjectDefinition,
|
42
|
+
metadata.ModelDefinition: model_pb2.ModelDefinition,
|
43
|
+
metadata.ModelParameter: model_pb2.ModelParameter,
|
44
|
+
metadata.ModelInputSchema: model_pb2.ModelInputSchema,
|
45
|
+
metadata.ModelOutputSchema: model_pb2.ModelOutputSchema,
|
46
|
+
metadata.SchemaDefinition: data_pb2.SchemaDefinition,
|
47
|
+
metadata.TableSchema: data_pb2.TableSchema,
|
48
|
+
metadata.FieldSchema: data_pb2.FieldSchema,
|
49
|
+
metadata.PartKey: data_pb2.PartKey,
|
50
|
+
metadata.DataDefinition: data_pb2.DataDefinition,
|
51
|
+
metadata.DataDefinition.Part: data_pb2.DataDefinition.Part,
|
52
|
+
metadata.DataDefinition.Snap: data_pb2.DataDefinition.Snap,
|
53
|
+
metadata.DataDefinition.Delta: data_pb2.DataDefinition.Delta,
|
54
|
+
metadata.StorageDefinition: storage_pb2.StorageDefinition,
|
55
|
+
metadata.StorageIncarnation: storage_pb2.StorageIncarnation,
|
56
|
+
metadata.StorageCopy: storage_pb2.StorageCopy,
|
57
|
+
metadata.StorageItem: storage_pb2.StorageItem
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
_T_MSG = tp.TypeVar('_T_MSG', bound=_message.Message)
|
62
|
+
|
63
|
+
|
64
|
+
def encode_message(msg_class: _T_MSG.__class__, obj: tp.Any) -> _T_MSG:
|
65
|
+
|
66
|
+
attrs = dict((k, encode(v)) for k, v in obj.__dict__.items())
|
67
|
+
|
68
|
+
return msg_class(**attrs)
|
69
|
+
|
70
|
+
|
71
|
+
def encode(obj: tp.Any) -> tp.Any:
|
72
|
+
|
73
|
+
# Translate TRAC domain objects into generic dict / list structures
|
74
|
+
# These can be accepted by gRPC message constructors, do not try to build messages directly
|
75
|
+
# Use shallow copies and builtins to minimize performance impact
|
76
|
+
|
77
|
+
if obj is None:
|
78
|
+
return None
|
79
|
+
|
80
|
+
if isinstance(obj, str) or isinstance(obj, bool) or isinstance(obj, int) or isinstance(obj, float):
|
81
|
+
return obj
|
82
|
+
|
83
|
+
if isinstance(obj, enum.Enum):
|
84
|
+
return obj.value
|
85
|
+
|
86
|
+
if isinstance(obj, list):
|
87
|
+
return list(map(encode, obj))
|
88
|
+
|
89
|
+
if isinstance(obj, dict):
|
90
|
+
return dict((k, encode(v)) for k, v in obj.items())
|
91
|
+
|
92
|
+
msg_class = __METADATA_MAPPING.get(type(obj))
|
93
|
+
|
94
|
+
if msg_class is None:
|
95
|
+
raise ex.ETracInternal(f"No gRPC metadata mapping is available for type {type(obj).__name__}")
|
96
|
+
|
97
|
+
attrs = dict((k, encode(v)) for k, v in obj.__dict__.items() if v is not None)
|
98
|
+
|
99
|
+
return msg_class(**attrs)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
3
|
+
# source: tracdap/rt/_impl/grpc/tracdap/api/internal/runtime.proto
|
4
|
+
# Protobuf Python Version: 4.25.3
|
5
|
+
"""Generated protocol buffer code."""
|
6
|
+
from google.protobuf import descriptor as _descriptor
|
7
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
8
|
+
from google.protobuf import symbol_database as _symbol_database
|
9
|
+
from google.protobuf.internal import builder as _builder
|
10
|
+
# @@protoc_insertion_point(imports)
|
11
|
+
|
12
|
+
_sym_db = _symbol_database.Default()
|
13
|
+
|
14
|
+
|
15
|
+
from tracdap.rt._impl.grpc.tracdap.metadata import object_id_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_object__id__pb2
|
16
|
+
from tracdap.rt._impl.grpc.tracdap.metadata import job_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_job__pb2
|
17
|
+
from tracdap.rt._impl.grpc.tracdap.metadata import object_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_object__pb2
|
18
|
+
from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2
|
19
|
+
|
20
|
+
|
21
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n8tracdap/rt/_impl/grpc/tracdap/api/internal/runtime.proto\x12\x14tracdap.api.internal\x1a\x36tracdap/rt/_impl/grpc/tracdap/metadata/object_id.proto\x1a\x30tracdap/rt/_impl/grpc/tracdap/metadata/job.proto\x1a\x33tracdap/rt/_impl/grpc/tracdap/metadata/object.proto\x1a\x1cgoogle/api/annotations.proto\"6\n\x16RuntimeListJobsRequest\x12\x12\n\x05limit\x18\x01 \x01(\rH\x00\x88\x01\x01\x42\x08\n\x06_limit\"O\n\x17RuntimeListJobsResponse\x12\x34\n\x04jobs\x18\x01 \x03(\x0b\x32&.tracdap.api.internal.RuntimeJobStatus\"f\n\x15RuntimeJobInfoRequest\x12\x34\n\x0bjobSelector\x18\x01 \x01(\x0b\x32\x1d.tracdap.metadata.TagSelectorH\x00\x12\x10\n\x06jobKey\x18\x02 \x01(\tH\x00\x42\x05\n\x03job\"\x9f\x01\n\x10RuntimeJobStatus\x12*\n\x05jobId\x18\x01 \x01(\x0b\x32\x1b.tracdap.metadata.TagHeader\x12\x33\n\nstatusCode\x18\x02 \x01(\x0e\x32\x1f.tracdap.metadata.JobStatusCode\x12\x15\n\rstatusMessage\x18\x03 \x01(\t\x12\x13\n\x0b\x65rrorDetail\x18\x04 \x01(\t\"\xa4\x02\n\x10RuntimeJobResult\x12*\n\x05jobId\x18\x01 \x01(\x0b\x32\x1b.tracdap.metadata.TagHeader\x12\x33\n\nstatusCode\x18\x02 \x01(\x0e\x32\x1f.tracdap.metadata.JobStatusCode\x12\x15\n\rstatusMessage\x18\x03 \x01(\t\x12\x44\n\x07results\x18\x04 \x03(\x0b\x32\x33.tracdap.api.internal.RuntimeJobResult.ResultsEntry\x1aR\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x31\n\x05value\x18\x02 \x01(\x0b\x32\".tracdap.metadata.ObjectDefinition:\x02\x38\x01\x32\x95\x03\n\x0eTracRuntimeApi\x12{\n\x08listJobs\x12,.tracdap.api.internal.RuntimeListJobsRequest\x1a-.tracdap.api.internal.RuntimeListJobsResponse\"\x12\x82\xd3\xe4\x93\x02\x0c\x12\n/list-jobs\x12\x81\x01\n\x0cgetJobStatus\x12+.tracdap.api.internal.RuntimeJobInfoRequest\x1a&.tracdap.api.internal.RuntimeJobStatus\"\x1c\x82\xd3\xe4\x93\x02\x16\x12\x14/job-status/{jobKey}\x12\x81\x01\n\x0cgetJobResult\x12+.tracdap.api.internal.RuntimeJobInfoRequest\x1a&.tracdap.api.internal.RuntimeJobResult\"\x1c\x82\xd3\xe4\x93\x02\x16\x12\x14/job-result/{jobKey}B\"\n\x1eorg.finos.tracdap.api.internalP\x01\x62\x06proto3')
|
22
|
+
|
23
|
+
_globals = globals()
|
24
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
25
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tracdap.rt._impl.grpc.tracdap.api.internal.runtime_pb2', _globals)
|
26
|
+
if _descriptor._USE_C_DESCRIPTORS == False:
|
27
|
+
_globals['DESCRIPTOR']._options = None
|
28
|
+
_globals['DESCRIPTOR']._serialized_options = b'\n\036org.finos.tracdap.api.internalP\001'
|
29
|
+
_globals['_RUNTIMEJOBRESULT_RESULTSENTRY']._options = None
|
30
|
+
_globals['_RUNTIMEJOBRESULT_RESULTSENTRY']._serialized_options = b'8\001'
|
31
|
+
_globals['_TRACRUNTIMEAPI'].methods_by_name['listJobs']._options = None
|
32
|
+
_globals['_TRACRUNTIMEAPI'].methods_by_name['listJobs']._serialized_options = b'\202\323\344\223\002\014\022\n/list-jobs'
|
33
|
+
_globals['_TRACRUNTIMEAPI'].methods_by_name['getJobStatus']._options = None
|
34
|
+
_globals['_TRACRUNTIMEAPI'].methods_by_name['getJobStatus']._serialized_options = b'\202\323\344\223\002\026\022\024/job-status/{jobKey}'
|
35
|
+
_globals['_TRACRUNTIMEAPI'].methods_by_name['getJobResult']._options = None
|
36
|
+
_globals['_TRACRUNTIMEAPI'].methods_by_name['getJobResult']._serialized_options = b'\202\323\344\223\002\026\022\024/job-result/{jobKey}'
|
37
|
+
_globals['_RUNTIMELISTJOBSREQUEST']._serialized_start=271
|
38
|
+
_globals['_RUNTIMELISTJOBSREQUEST']._serialized_end=325
|
39
|
+
_globals['_RUNTIMELISTJOBSRESPONSE']._serialized_start=327
|
40
|
+
_globals['_RUNTIMELISTJOBSRESPONSE']._serialized_end=406
|
41
|
+
_globals['_RUNTIMEJOBINFOREQUEST']._serialized_start=408
|
42
|
+
_globals['_RUNTIMEJOBINFOREQUEST']._serialized_end=510
|
43
|
+
_globals['_RUNTIMEJOBSTATUS']._serialized_start=513
|
44
|
+
_globals['_RUNTIMEJOBSTATUS']._serialized_end=672
|
45
|
+
_globals['_RUNTIMEJOBRESULT']._serialized_start=675
|
46
|
+
_globals['_RUNTIMEJOBRESULT']._serialized_end=967
|
47
|
+
_globals['_RUNTIMEJOBRESULT_RESULTSENTRY']._serialized_start=885
|
48
|
+
_globals['_RUNTIMEJOBRESULT_RESULTSENTRY']._serialized_end=967
|
49
|
+
_globals['_TRACRUNTIMEAPI']._serialized_start=970
|
50
|
+
_globals['_TRACRUNTIMEAPI']._serialized_end=1375
|
51
|
+
# @@protoc_insertion_point(module_scope)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
from tracdap.rt._impl.grpc.tracdap.metadata import object_id_pb2 as _object_id_pb2
|
2
|
+
from tracdap.rt._impl.grpc.tracdap.metadata import job_pb2 as _job_pb2
|
3
|
+
from tracdap.rt._impl.grpc.tracdap.metadata import object_pb2 as _object_pb2
|
4
|
+
from google.api import annotations_pb2 as _annotations_pb2
|
5
|
+
from google.protobuf.internal import containers as _containers
|
6
|
+
from google.protobuf import descriptor as _descriptor
|
7
|
+
from google.protobuf import message as _message
|
8
|
+
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
9
|
+
|
10
|
+
DESCRIPTOR: _descriptor.FileDescriptor
|
11
|
+
|
12
|
+
class RuntimeListJobsRequest(_message.Message):
|
13
|
+
__slots__ = ("limit",)
|
14
|
+
LIMIT_FIELD_NUMBER: _ClassVar[int]
|
15
|
+
limit: int
|
16
|
+
def __init__(self, limit: _Optional[int] = ...) -> None: ...
|
17
|
+
|
18
|
+
class RuntimeListJobsResponse(_message.Message):
|
19
|
+
__slots__ = ("jobs",)
|
20
|
+
JOBS_FIELD_NUMBER: _ClassVar[int]
|
21
|
+
jobs: _containers.RepeatedCompositeFieldContainer[RuntimeJobStatus]
|
22
|
+
def __init__(self, jobs: _Optional[_Iterable[_Union[RuntimeJobStatus, _Mapping]]] = ...) -> None: ...
|
23
|
+
|
24
|
+
class RuntimeJobInfoRequest(_message.Message):
|
25
|
+
__slots__ = ("jobSelector", "jobKey")
|
26
|
+
JOBSELECTOR_FIELD_NUMBER: _ClassVar[int]
|
27
|
+
JOBKEY_FIELD_NUMBER: _ClassVar[int]
|
28
|
+
jobSelector: _object_id_pb2.TagSelector
|
29
|
+
jobKey: str
|
30
|
+
def __init__(self, jobSelector: _Optional[_Union[_object_id_pb2.TagSelector, _Mapping]] = ..., jobKey: _Optional[str] = ...) -> None: ...
|
31
|
+
|
32
|
+
class RuntimeJobStatus(_message.Message):
|
33
|
+
__slots__ = ("jobId", "statusCode", "statusMessage", "errorDetail")
|
34
|
+
JOBID_FIELD_NUMBER: _ClassVar[int]
|
35
|
+
STATUSCODE_FIELD_NUMBER: _ClassVar[int]
|
36
|
+
STATUSMESSAGE_FIELD_NUMBER: _ClassVar[int]
|
37
|
+
ERRORDETAIL_FIELD_NUMBER: _ClassVar[int]
|
38
|
+
jobId: _object_id_pb2.TagHeader
|
39
|
+
statusCode: _job_pb2.JobStatusCode
|
40
|
+
statusMessage: str
|
41
|
+
errorDetail: str
|
42
|
+
def __init__(self, jobId: _Optional[_Union[_object_id_pb2.TagHeader, _Mapping]] = ..., statusCode: _Optional[_Union[_job_pb2.JobStatusCode, str]] = ..., statusMessage: _Optional[str] = ..., errorDetail: _Optional[str] = ...) -> None: ...
|
43
|
+
|
44
|
+
class RuntimeJobResult(_message.Message):
|
45
|
+
__slots__ = ("jobId", "statusCode", "statusMessage", "results")
|
46
|
+
class ResultsEntry(_message.Message):
|
47
|
+
__slots__ = ("key", "value")
|
48
|
+
KEY_FIELD_NUMBER: _ClassVar[int]
|
49
|
+
VALUE_FIELD_NUMBER: _ClassVar[int]
|
50
|
+
key: str
|
51
|
+
value: _object_pb2.ObjectDefinition
|
52
|
+
def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[_object_pb2.ObjectDefinition, _Mapping]] = ...) -> None: ...
|
53
|
+
JOBID_FIELD_NUMBER: _ClassVar[int]
|
54
|
+
STATUSCODE_FIELD_NUMBER: _ClassVar[int]
|
55
|
+
STATUSMESSAGE_FIELD_NUMBER: _ClassVar[int]
|
56
|
+
RESULTS_FIELD_NUMBER: _ClassVar[int]
|
57
|
+
jobId: _object_id_pb2.TagHeader
|
58
|
+
statusCode: _job_pb2.JobStatusCode
|
59
|
+
statusMessage: str
|
60
|
+
results: _containers.MessageMap[str, _object_pb2.ObjectDefinition]
|
61
|
+
def __init__(self, jobId: _Optional[_Union[_object_id_pb2.TagHeader, _Mapping]] = ..., statusCode: _Optional[_Union[_job_pb2.JobStatusCode, str]] = ..., statusMessage: _Optional[str] = ..., results: _Optional[_Mapping[str, _object_pb2.ObjectDefinition]] = ...) -> None: ...
|