tracdap-runtime 0.8.0b2__py3-none-any.whl → 0.8.0b4__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/_impl/core/__init__.py +14 -0
- tracdap/rt/_impl/{config_parser.py → core/config_parser.py} +59 -35
- tracdap/rt/_impl/{data.py → core/data.py} +64 -33
- tracdap/rt/_impl/{models.py → core/models.py} +6 -6
- tracdap/rt/_impl/{repos.py → core/repos.py} +1 -1
- tracdap/rt/_impl/{schemas.py → core/schemas.py} +4 -4
- tracdap/rt/_impl/{shim.py → core/shim.py} +3 -3
- tracdap/rt/_impl/{storage.py → core/storage.py} +8 -5
- tracdap/rt/_impl/core/struct.py +547 -0
- tracdap/rt/_impl/{type_system.py → core/type_system.py} +73 -33
- tracdap/rt/_impl/{validation.py → core/validation.py} +58 -17
- tracdap/rt/_impl/exec/__init__.py +14 -0
- tracdap/rt/{_exec → _impl/exec}/actors.py +9 -12
- tracdap/rt/{_exec → _impl/exec}/context.py +70 -16
- tracdap/rt/{_exec → _impl/exec}/dev_mode.py +31 -20
- tracdap/rt/{_exec → _impl/exec}/engine.py +9 -9
- tracdap/rt/{_exec → _impl/exec}/functions.py +89 -40
- tracdap/rt/{_exec → _impl/exec}/graph.py +1 -1
- tracdap/rt/{_exec → _impl/exec}/graph_builder.py +2 -2
- tracdap/rt/{_exec → _impl/grpc}/server.py +4 -4
- tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.py +2 -2
- tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2_grpc.py +1 -1
- tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.py +31 -19
- tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.pyi +48 -2
- tracdap/rt/{_exec → _impl}/runtime.py +13 -13
- tracdap/rt/_impl/static_api.py +13 -5
- tracdap/rt/_plugins/format_csv.py +1 -1
- tracdap/rt/_plugins/storage_sql.py +13 -6
- tracdap/rt/_version.py +1 -1
- tracdap/rt/api/experimental.py +32 -0
- tracdap/rt/api/hook.py +11 -0
- tracdap/rt/config/__init__.py +8 -10
- tracdap/rt/config/common.py +0 -34
- tracdap/rt/config/platform.py +14 -26
- tracdap/rt/ext/embed.py +2 -2
- tracdap/rt/ext/plugins.py +2 -2
- tracdap/rt/launch/launch.py +3 -3
- tracdap/rt/metadata/__init__.py +11 -9
- tracdap/rt/metadata/data.py +40 -0
- {tracdap_runtime-0.8.0b2.dist-info → tracdap_runtime-0.8.0b4.dist-info}/METADATA +15 -13
- {tracdap_runtime-0.8.0b2.dist-info → tracdap_runtime-0.8.0b4.dist-info}/RECORD +47 -45
- {tracdap_runtime-0.8.0b2.dist-info → tracdap_runtime-0.8.0b4.dist-info}/WHEEL +1 -1
- tracdap/rt/_exec/__init__.py +0 -0
- /tracdap/rt/_impl/{guard_rails.py → core/guard_rails.py} +0 -0
- /tracdap/rt/_impl/{logging.py → core/logging.py} +0 -0
- /tracdap/rt/_impl/{util.py → core/util.py} +0 -0
- {tracdap_runtime-0.8.0b2.dist-info → tracdap_runtime-0.8.0b4.dist-info}/LICENSE +0 -0
- {tracdap_runtime-0.8.0b2.dist-info → tracdap_runtime-0.8.0b4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# Licensed to the Fintech Open Source Foundation (FINOS) under one or
|
2
|
+
# more contributor license agreements. See the NOTICE file distributed
|
3
|
+
# with this work for additional information regarding copyright ownership.
|
4
|
+
# FINOS licenses this file to you under the Apache License, Version 2.0
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
@@ -13,8 +13,6 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
|
16
|
-
from __future__ import annotations
|
17
|
-
|
18
16
|
import dataclasses as _dc
|
19
17
|
import decimal
|
20
18
|
import enum
|
@@ -24,6 +22,7 @@ import json
|
|
24
22
|
import os
|
25
23
|
import pathlib
|
26
24
|
import re
|
25
|
+
import types as ts
|
27
26
|
import typing as tp
|
28
27
|
import urllib.parse as _urlp
|
29
28
|
import uuid
|
@@ -32,19 +31,24 @@ import tracdap.rt.config as _config
|
|
32
31
|
import tracdap.rt.exceptions as _ex
|
33
32
|
import tracdap.rt.ext.plugins as _plugins
|
34
33
|
import tracdap.rt.ext.config as _config_ext
|
35
|
-
import tracdap.rt._impl.logging as _logging
|
36
|
-
import tracdap.rt._impl.util as _util
|
34
|
+
import tracdap.rt._impl.core.logging as _logging
|
35
|
+
import tracdap.rt._impl.core.util as _util
|
37
36
|
|
38
37
|
import yaml
|
39
38
|
import yaml.parser
|
40
39
|
|
40
|
+
try:
|
41
|
+
import pydantic as _pyd # noqa
|
42
|
+
except ModuleNotFoundError:
|
43
|
+
_pyd = None
|
44
|
+
|
41
45
|
_T = tp.TypeVar('_T')
|
42
46
|
|
43
47
|
|
44
48
|
class ConfigManager:
|
45
49
|
|
46
50
|
@classmethod
|
47
|
-
def for_root_config(cls, root_config_file: tp.Union[str, pathlib.Path, None]) -> ConfigManager:
|
51
|
+
def for_root_config(cls, root_config_file: tp.Union[str, pathlib.Path, None]) -> "ConfigManager":
|
48
52
|
|
49
53
|
if isinstance(root_config_file, pathlib.Path):
|
50
54
|
root_file_path = cls._resolve_scheme(root_config_file)
|
@@ -70,7 +74,7 @@ class ConfigManager:
|
|
70
74
|
return ConfigManager(working_dir_url, None)
|
71
75
|
|
72
76
|
@classmethod
|
73
|
-
def for_root_dir(cls, root_config_dir: tp.Union[str, pathlib.Path]) -> ConfigManager:
|
77
|
+
def for_root_dir(cls, root_config_dir: tp.Union[str, pathlib.Path]) -> "ConfigManager":
|
74
78
|
|
75
79
|
if isinstance(root_config_dir, pathlib.Path):
|
76
80
|
root_dir_path = cls._resolve_scheme(root_config_dir)
|
@@ -280,9 +284,17 @@ class ConfigManager:
|
|
280
284
|
|
281
285
|
class ConfigParser(tp.Generic[_T]):
|
282
286
|
|
283
|
-
#
|
284
|
-
#
|
285
|
-
|
287
|
+
# Support both new and old styles for generic, union and optional types
|
288
|
+
# Old-style annotations are still valid, even when the new style is fully supported
|
289
|
+
__generic_types: list[type] = [
|
290
|
+
ts.GenericAlias,
|
291
|
+
type(tp.List[int]),
|
292
|
+
type(tp.Optional[int])
|
293
|
+
]
|
294
|
+
|
295
|
+
# UnionType was added to the types module in Python 3.10, we support 3.9 (Jan 2025)
|
296
|
+
if hasattr(ts, "UnionType"):
|
297
|
+
__generic_types.append(ts.UnionType)
|
286
298
|
|
287
299
|
__primitive_types: tp.Dict[type, callable] = {
|
288
300
|
bool: bool,
|
@@ -322,6 +334,23 @@ class ConfigParser(tp.Generic[_T]):
|
|
322
334
|
|
323
335
|
def _parse_value(self, location: str, raw_value: tp.Any, annotation: type):
|
324
336
|
|
337
|
+
if self._is_dev_mode_location(location):
|
338
|
+
|
339
|
+
if type(raw_value) in ConfigParser.__primitive_types:
|
340
|
+
return self._parse_primitive(location, raw_value, type(raw_value))
|
341
|
+
|
342
|
+
if isinstance(raw_value, list):
|
343
|
+
if len(raw_value) == 0:
|
344
|
+
return []
|
345
|
+
items = iter((self._child_location(location, i), x) for i, x in enumerate(raw_value))
|
346
|
+
return list(self._parse_value(loc, x, tp.Any) for loc, x in items)
|
347
|
+
|
348
|
+
if isinstance(raw_value, dict):
|
349
|
+
if len(raw_value) == 0:
|
350
|
+
return {}
|
351
|
+
items = iter((self._child_location(location, k), k, v) for k, v in raw_value.items())
|
352
|
+
return dict((k, self._parse_value(loc, v, tp.Any)) for loc, k, v in items)
|
353
|
+
|
325
354
|
if raw_value is None:
|
326
355
|
return None
|
327
356
|
|
@@ -340,24 +369,17 @@ class ConfigParser(tp.Generic[_T]):
|
|
340
369
|
return self._parse_enum(location, raw_value, annotation)
|
341
370
|
|
342
371
|
if _dc.is_dataclass(annotation):
|
372
|
+
return self._parse_simple_class(location, raw_value, annotation)
|
343
373
|
|
344
|
-
|
345
|
-
|
374
|
+
# Basic support for Pydantic, if it is installed
|
375
|
+
if _pyd and isinstance(annotation, type) and issubclass(annotation, _pyd.BaseModel):
|
376
|
+
return self._parse_simple_class(location, raw_value, annotation)
|
346
377
|
|
347
|
-
|
348
|
-
if type(raw_value) in ConfigParser.__primitive_types:
|
349
|
-
return self._parse_primitive(location, raw_value, type(raw_value))
|
350
|
-
if isinstance(raw_value, list):
|
351
|
-
if len(raw_value) == 0:
|
352
|
-
return []
|
353
|
-
list_type = type(raw_value[0])
|
354
|
-
return list(map(lambda x: self._parse_primitive(location, x, list_type), raw_value))
|
355
|
-
|
356
|
-
return self._error(location, f"Expected type {annotation.__name__}, got '{str(raw_value)}'")
|
357
|
-
|
358
|
-
if isinstance(annotation, self.__generic_metaclass):
|
378
|
+
if any(map(lambda _t: isinstance(annotation, _t), self.__generic_types)):
|
359
379
|
return self._parse_generic_class(location, raw_value, annotation) # noqa
|
360
380
|
|
381
|
+
return self._error(location, f"Cannot parse value of type {annotation.__name__}")
|
382
|
+
|
361
383
|
def _is_dev_mode_location(self, location):
|
362
384
|
|
363
385
|
return any(map(lambda pattern: re.match(pattern, location), self._dev_mode_locations))
|
@@ -417,14 +439,14 @@ class ConfigParser(tp.Generic[_T]):
|
|
417
439
|
def _parse_simple_class(self, location: str, raw_dict: tp.Any, metaclass: type) -> object:
|
418
440
|
|
419
441
|
if raw_dict is not None and not isinstance(raw_dict, dict):
|
420
|
-
|
442
|
+
return self._error(location, f"Expected type {metaclass.__name__}, got '{str(raw_dict)}'")
|
421
443
|
|
422
444
|
obj = metaclass.__new__(metaclass, object()) # noqa
|
423
445
|
|
424
446
|
init_signature = inspect.signature(metaclass.__init__)
|
425
447
|
init_types = tp.get_type_hints(metaclass.__init__)
|
426
448
|
init_params = iter(init_signature.parameters.items())
|
427
|
-
init_values: tp.
|
449
|
+
init_values: tp.Dict[str, tp.Any] = dict()
|
428
450
|
|
429
451
|
# Do not process 'self'
|
430
452
|
next(init_params)
|
@@ -438,20 +460,20 @@ class ConfigParser(tp.Generic[_T]):
|
|
438
460
|
message = f"Class {metaclass.__name__} does not support config decoding: " + \
|
439
461
|
f"Missing type information for init parameter '{param_name}'"
|
440
462
|
self._error(location, message)
|
441
|
-
init_values
|
463
|
+
init_values[param_name] = None
|
442
464
|
|
443
465
|
elif param_name in raw_dict and raw_dict[param_name] is not None:
|
444
466
|
param_value = self._parse_value(param_location, raw_dict[param_name], param_type)
|
445
|
-
init_values
|
467
|
+
init_values[param_name] = param_value
|
446
468
|
|
447
469
|
elif param.default != inspect._empty: # noqa
|
448
|
-
init_values
|
470
|
+
init_values[param_name] = param.default
|
449
471
|
|
450
472
|
else:
|
451
473
|
self._error(location, f"Missing required value '{param_name}'")
|
452
|
-
init_values
|
474
|
+
init_values[param_name] = None
|
453
475
|
|
454
|
-
binding = init_signature.bind(obj,
|
476
|
+
binding = init_signature.bind(obj, **init_values)
|
455
477
|
metaclass.__init__(*binding.args, **binding.kwargs)
|
456
478
|
|
457
479
|
# Now go back over the members and look for any that weren't declared in __init__
|
@@ -472,7 +494,7 @@ class ConfigParser(tp.Generic[_T]):
|
|
472
494
|
self._error(location, message)
|
473
495
|
|
474
496
|
# Generic members must be declared in __init__ since that is the only way to get the full annotation
|
475
|
-
if isinstance(type(default_value), self.
|
497
|
+
if any(map(lambda _t: isinstance(type(default_value), _t), self.__generic_types)):
|
476
498
|
message = f"Class {metaclass.__name__} does not support config decoding: " + \
|
477
499
|
f"Members with no default value must be declared in __init__: '{member_name}'"
|
478
500
|
self._error(location, message)
|
@@ -498,7 +520,7 @@ class ConfigParser(tp.Generic[_T]):
|
|
498
520
|
|
499
521
|
return obj
|
500
522
|
|
501
|
-
def _parse_generic_class(self, location: str, raw_value: tp.Any,
|
523
|
+
def _parse_generic_class(self, location: str, raw_value: tp.Any, metaclass: type):
|
502
524
|
|
503
525
|
origin = _util.get_origin(metaclass)
|
504
526
|
args = _util.get_args(metaclass)
|
@@ -511,7 +533,7 @@ class ConfigParser(tp.Generic[_T]):
|
|
511
533
|
return self._error(location, f"Expected a list, got {type(raw_value)}")
|
512
534
|
|
513
535
|
return [
|
514
|
-
self._parse_value(self._child_location(location,
|
536
|
+
self._parse_value(self._child_location(location, idx), item, list_type)
|
515
537
|
for (idx, item) in enumerate(raw_value)]
|
516
538
|
|
517
539
|
if origin == tp.Dict or origin == dict:
|
@@ -542,12 +564,14 @@ class ConfigParser(tp.Generic[_T]):
|
|
542
564
|
return None
|
543
565
|
|
544
566
|
@staticmethod
|
545
|
-
def _child_location(parent_location: str, item: str):
|
567
|
+
def _child_location(parent_location: str, item: tp.Union[str, int]):
|
546
568
|
|
547
569
|
if parent_location is None or parent_location == "":
|
548
570
|
return item
|
571
|
+
elif isinstance(item, int):
|
572
|
+
return f"{parent_location}[{item}]"
|
549
573
|
else:
|
550
|
-
return parent_location
|
574
|
+
return f"{parent_location}.{item}"
|
551
575
|
|
552
576
|
|
553
577
|
class ConfigQuoter:
|
@@ -37,13 +37,14 @@ except ModuleNotFoundError:
|
|
37
37
|
import tracdap.rt.api.experimental as _api
|
38
38
|
import tracdap.rt.metadata as _meta
|
39
39
|
import tracdap.rt.exceptions as _ex
|
40
|
-
import tracdap.rt._impl.logging as _log
|
40
|
+
import tracdap.rt._impl.core.logging as _log
|
41
41
|
|
42
42
|
|
43
43
|
@dc.dataclass(frozen=True)
|
44
44
|
class DataSpec:
|
45
45
|
|
46
46
|
object_type: _meta.ObjectType
|
47
|
+
schema_type: _meta.SchemaType
|
47
48
|
data_item: str
|
48
49
|
|
49
50
|
data_def: _meta.DataDefinition
|
@@ -58,8 +59,15 @@ class DataSpec:
|
|
58
59
|
storage_def: _meta.StorageDefinition,
|
59
60
|
schema_def: tp.Optional[_meta.SchemaDefinition] = None) -> "DataSpec":
|
60
61
|
|
62
|
+
if schema_def:
|
63
|
+
schema_type = schema_def.schemaType
|
64
|
+
elif data_def.schema:
|
65
|
+
schema_type = data_def.schema.schemaType
|
66
|
+
else:
|
67
|
+
schema_type = _meta.SchemaType.SCHEMA_TYPE_NOT_SET
|
68
|
+
|
61
69
|
return DataSpec(
|
62
|
-
_meta.ObjectType.DATA, data_item,
|
70
|
+
_meta.ObjectType.DATA, schema_type, data_item,
|
63
71
|
data_def,
|
64
72
|
storage_def=storage_def,
|
65
73
|
schema_def=schema_def,
|
@@ -72,15 +80,15 @@ class DataSpec:
|
|
72
80
|
storage_def: _meta.StorageDefinition) -> "DataSpec":
|
73
81
|
|
74
82
|
return DataSpec(
|
75
|
-
_meta.ObjectType.FILE, data_item,
|
83
|
+
_meta.ObjectType.FILE, _meta.SchemaType.SCHEMA_TYPE_NOT_SET, data_item,
|
76
84
|
file_def=file_def,
|
77
85
|
storage_def=storage_def,
|
78
86
|
data_def=None,
|
79
87
|
schema_def=None)
|
80
88
|
|
81
89
|
@staticmethod
|
82
|
-
def create_empty_spec(object_type: _meta.ObjectType):
|
83
|
-
return DataSpec(object_type, None, None, None, None, None)
|
90
|
+
def create_empty_spec(object_type: _meta.ObjectType, schema_type: _meta.SchemaType):
|
91
|
+
return DataSpec(object_type, schema_type, None, None, None, None, None)
|
84
92
|
|
85
93
|
def is_empty(self):
|
86
94
|
return self.data_item is None or len(self.data_item) == 0
|
@@ -100,32 +108,54 @@ class DataPartKey:
|
|
100
108
|
class DataItem:
|
101
109
|
|
102
110
|
object_type: _meta.ObjectType
|
111
|
+
schema_type: _meta.SchemaType
|
112
|
+
|
113
|
+
content: tp.Any = None
|
114
|
+
content_type: tp.Type = None
|
115
|
+
content_func: tp.Callable[[], tp.Any] = None
|
116
|
+
|
117
|
+
trac_schema: _meta.SchemaDefinition = None
|
118
|
+
native_schema: tp.Any = None
|
103
119
|
|
120
|
+
# TODO: Remove legacy API and use content / native_schema instead
|
104
121
|
schema: pa.Schema = None
|
105
122
|
table: tp.Optional[pa.Table] = None
|
106
|
-
batches: tp.Optional[tp.List[pa.RecordBatch]] = None
|
107
123
|
|
108
|
-
|
109
|
-
|
124
|
+
def is_empty(self) -> bool:
|
125
|
+
return self.content is None
|
110
126
|
|
111
|
-
|
127
|
+
@staticmethod
|
128
|
+
def create_empty(
|
129
|
+
object_type: _meta.ObjectType = _meta.ObjectType.DATA,
|
130
|
+
schema_type: _meta.SchemaType = _meta.SchemaType.TABLE) -> "DataItem":
|
112
131
|
|
113
|
-
|
114
|
-
|
115
|
-
return self.raw_bytes is None or len(self.raw_bytes) == 0
|
132
|
+
if object_type == _meta.ObjectType.DATA and schema_type == _meta.SchemaType.TABLE:
|
133
|
+
return DataItem(_meta.ObjectType.DATA, _meta.SchemaType.TABLE, schema=pa.schema([]))
|
116
134
|
else:
|
117
|
-
return
|
135
|
+
return DataItem(object_type, schema_type)
|
118
136
|
|
119
137
|
@staticmethod
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
138
|
+
def for_table(table: pa.Table, schema: pa.Schema, trac_schema: _meta.SchemaDefinition) -> "DataItem":
|
139
|
+
|
140
|
+
return DataItem(
|
141
|
+
_meta.ObjectType.DATA, _meta.SchemaType.TABLE,
|
142
|
+
content=table, content_type=pa.Table,
|
143
|
+
trac_schema=trac_schema, native_schema=schema,
|
144
|
+
table=table, schema=schema)
|
145
|
+
|
146
|
+
@staticmethod
|
147
|
+
def for_struct(content: tp.Any):
|
148
|
+
|
149
|
+
return DataItem(
|
150
|
+
_meta.ObjectType.DATA, _meta.SchemaType.STRUCT,
|
151
|
+
content=content, content_type=type(content))
|
125
152
|
|
126
153
|
@staticmethod
|
127
|
-
def for_file_content(
|
128
|
-
|
154
|
+
def for_file_content(content: bytes):
|
155
|
+
|
156
|
+
return DataItem(
|
157
|
+
_meta.ObjectType.FILE, _meta.SchemaType.SCHEMA_TYPE_NOT_SET,
|
158
|
+
content=content, content_type=bytes)
|
129
159
|
|
130
160
|
|
131
161
|
@dc.dataclass(frozen=True)
|
@@ -148,8 +178,11 @@ class DataView:
|
|
148
178
|
|
149
179
|
@staticmethod
|
150
180
|
def for_trac_schema(trac_schema: _meta.SchemaDefinition):
|
151
|
-
|
152
|
-
|
181
|
+
if trac_schema.schemaType == _meta.SchemaType.TABLE:
|
182
|
+
arrow_schema = DataMapping.trac_to_arrow_schema(trac_schema)
|
183
|
+
return DataView(_meta.ObjectType.DATA, trac_schema, arrow_schema, dict())
|
184
|
+
else:
|
185
|
+
return DataView(_meta.ObjectType.DATA, trac_schema, parts = dict())
|
153
186
|
|
154
187
|
@staticmethod
|
155
188
|
def for_file_item(file_item: DataItem):
|
@@ -381,29 +414,27 @@ class DataMapping:
|
|
381
414
|
if not deltas:
|
382
415
|
raise _ex.ETracInternal(f"Data view for part [{part.opaque_key}] does not contain any items")
|
383
416
|
|
417
|
+
# For a single delta, use the existing Arrow content
|
384
418
|
if len(deltas) == 1:
|
385
419
|
return cls.item_to_arrow(deltas[0])
|
386
420
|
|
387
|
-
|
421
|
+
# For multiple deltas, construct a new table by assembling the record batches
|
422
|
+
# Atm no consideration is given to overwriting records based on business key
|
423
|
+
batches = iter(
|
388
424
|
batch
|
389
425
|
for delta in deltas
|
390
|
-
for batch in (
|
391
|
-
delta.batches
|
392
|
-
if delta.batches
|
393
|
-
else delta.table.to_batches())}
|
426
|
+
for batch in cls.item_to_arrow(delta).to_batches())
|
394
427
|
|
395
428
|
return pa.Table.from_batches(batches) # noqa
|
396
429
|
|
397
430
|
@classmethod
|
398
431
|
def item_to_arrow(cls, item: DataItem) -> pa.Table:
|
399
432
|
|
400
|
-
if item.
|
401
|
-
|
402
|
-
|
403
|
-
if item.batches is not None:
|
404
|
-
return pa.Table.from_batches(item.batches, item.schema) # noqa
|
433
|
+
if item.content_type != pa.Table:
|
434
|
+
detail = f"expected Arrow table, got [{item.content_type}]"
|
435
|
+
raise _ex.ETracInternal(f"Data item does not contain tabular data ({detail})")
|
405
436
|
|
406
|
-
|
437
|
+
return item.content
|
407
438
|
|
408
439
|
@classmethod
|
409
440
|
def arrow_to_pandas(
|
@@ -25,12 +25,12 @@ import tracdap.rt.metadata as _meta
|
|
25
25
|
import tracdap.rt.config as _cfg
|
26
26
|
import tracdap.rt.exceptions as _ex
|
27
27
|
|
28
|
-
import tracdap.rt._impl.logging as _logging
|
29
|
-
import tracdap.rt._impl.repos as _repos
|
30
|
-
import tracdap.rt._impl.shim as _shim
|
31
|
-
import tracdap.rt._impl.type_system as _types
|
32
|
-
import tracdap.rt._impl.util as _util
|
33
|
-
import tracdap.rt._impl.validation as _val
|
28
|
+
import tracdap.rt._impl.core.logging as _logging
|
29
|
+
import tracdap.rt._impl.core.repos as _repos
|
30
|
+
import tracdap.rt._impl.core.shim as _shim
|
31
|
+
import tracdap.rt._impl.core.type_system as _types
|
32
|
+
import tracdap.rt._impl.core.util as _util
|
33
|
+
import tracdap.rt._impl.core.validation as _val
|
34
34
|
|
35
35
|
|
36
36
|
class ModelLoader:
|
@@ -18,7 +18,7 @@ import typing as _tp
|
|
18
18
|
import tracdap.rt.ext.plugins as plugins
|
19
19
|
import tracdap.rt.config as cfg
|
20
20
|
import tracdap.rt.exceptions as ex
|
21
|
-
import tracdap.rt._impl.logging as _logging
|
21
|
+
import tracdap.rt._impl.core.logging as _logging
|
22
22
|
|
23
23
|
# Import repo interfaces
|
24
24
|
from tracdap.rt.ext.repos import *
|
@@ -21,10 +21,10 @@ import pyarrow as pa
|
|
21
21
|
|
22
22
|
import tracdap.rt.metadata as _meta
|
23
23
|
import tracdap.rt.exceptions as _ex
|
24
|
-
import tracdap.rt._impl.data as _data
|
25
|
-
import tracdap.rt._impl.logging as _log
|
26
|
-
import tracdap.rt._impl.storage as _storage
|
27
|
-
import tracdap.rt._impl.shim as _shim
|
24
|
+
import tracdap.rt._impl.core.data as _data
|
25
|
+
import tracdap.rt._impl.core.logging as _log
|
26
|
+
import tracdap.rt._impl.core.storage as _storage
|
27
|
+
import tracdap.rt._impl.core.shim as _shim
|
28
28
|
|
29
29
|
|
30
30
|
class SchemaLoader:
|
@@ -30,9 +30,9 @@ import importlib.machinery as _ilm
|
|
30
30
|
import importlib.resources as _ilr
|
31
31
|
|
32
32
|
import tracdap.rt.exceptions as _ex
|
33
|
-
import tracdap.rt._impl.guard_rails as _guard
|
34
|
-
import tracdap.rt._impl.logging as _log
|
35
|
-
import tracdap.rt._impl.util as _util
|
33
|
+
import tracdap.rt._impl.core.guard_rails as _guard
|
34
|
+
import tracdap.rt._impl.core.logging as _log
|
35
|
+
import tracdap.rt._impl.core.util as _util
|
36
36
|
|
37
37
|
|
38
38
|
class _Shim:
|
@@ -29,10 +29,10 @@ import tracdap.rt.metadata as _meta
|
|
29
29
|
import tracdap.rt.config as _cfg
|
30
30
|
import tracdap.rt.exceptions as _ex
|
31
31
|
import tracdap.rt.ext.plugins as plugins
|
32
|
-
import tracdap.rt._impl.data as _data
|
33
|
-
import tracdap.rt._impl.logging as _logging
|
34
|
-
import tracdap.rt._impl.util as _util
|
35
|
-
import tracdap.rt._impl.validation as _val
|
32
|
+
import tracdap.rt._impl.core.data as _data
|
33
|
+
import tracdap.rt._impl.core.logging as _logging
|
34
|
+
import tracdap.rt._impl.core.util as _util
|
35
|
+
import tracdap.rt._impl.core.validation as _val
|
36
36
|
|
37
37
|
# Import storage interfaces (using the internal version, it has extra bits that are not public)
|
38
38
|
from tracdap.rt._impl.ext.storage import *
|
@@ -496,7 +496,10 @@ class CommonFileStorage(IFileStorage):
|
|
496
496
|
|
497
497
|
# For successful write streams, log the total size written
|
498
498
|
if is_write and not error:
|
499
|
-
|
499
|
+
if not stream.closed:
|
500
|
+
file_size = _util.format_file_size(stream.tell())
|
501
|
+
else:
|
502
|
+
file_size = self._fs.get_file_info(storage_path).size
|
500
503
|
self._log.info(f"File size [{self._key}]: {file_size} [{storage_path}]")
|
501
504
|
|
502
505
|
# Close the stream - this may take time for write streams that are not flushed
|