tracdap-runtime 0.7.0rc1__py3-none-any.whl → 0.8.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.
Files changed (88) hide show
  1. tracdap/rt/_impl/core/__init__.py +14 -0
  2. tracdap/rt/_impl/{config_parser.py → core/config_parser.py} +61 -36
  3. tracdap/rt/_impl/{data.py → core/data.py} +136 -32
  4. tracdap/rt/_impl/core/logging.py +195 -0
  5. tracdap/rt/_impl/{models.py → core/models.py} +15 -12
  6. tracdap/rt/_impl/{repos.py → core/repos.py} +12 -3
  7. tracdap/rt/_impl/{schemas.py → core/schemas.py} +5 -5
  8. tracdap/rt/_impl/{shim.py → core/shim.py} +5 -4
  9. tracdap/rt/_impl/{storage.py → core/storage.py} +21 -10
  10. tracdap/rt/_impl/core/struct.py +547 -0
  11. tracdap/rt/_impl/{type_system.py → core/type_system.py} +73 -33
  12. tracdap/rt/_impl/{util.py → core/util.py} +1 -111
  13. tracdap/rt/_impl/{validation.py → core/validation.py} +99 -31
  14. tracdap/rt/_impl/exec/__init__.py +14 -0
  15. tracdap/rt/{_exec → _impl/exec}/actors.py +12 -14
  16. tracdap/rt/{_exec → _impl/exec}/context.py +228 -82
  17. tracdap/rt/{_exec → _impl/exec}/dev_mode.py +176 -89
  18. tracdap/rt/{_exec → _impl/exec}/engine.py +230 -105
  19. tracdap/rt/{_exec → _impl/exec}/functions.py +191 -100
  20. tracdap/rt/{_exec → _impl/exec}/graph.py +24 -36
  21. tracdap/rt/{_exec → _impl/exec}/graph_builder.py +252 -115
  22. tracdap/rt/_impl/grpc/codec.py +1 -1
  23. tracdap/rt/{_exec → _impl/grpc}/server.py +7 -6
  24. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.py +3 -3
  25. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2_grpc.py +1 -1
  26. tracdap/rt/_impl/grpc/tracdap/metadata/common_pb2.py +1 -1
  27. tracdap/rt/_impl/grpc/tracdap/metadata/config_pb2.py +40 -0
  28. tracdap/rt/_impl/grpc/tracdap/metadata/config_pb2.pyi +62 -0
  29. tracdap/rt/_impl/grpc/tracdap/metadata/custom_pb2.py +1 -1
  30. tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.py +32 -20
  31. tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.pyi +48 -2
  32. tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.py +4 -2
  33. tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.pyi +8 -0
  34. tracdap/rt/_impl/grpc/tracdap/metadata/flow_pb2.py +1 -1
  35. tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.py +65 -63
  36. tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.pyi +16 -2
  37. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.py +28 -26
  38. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.pyi +14 -4
  39. tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.py +4 -4
  40. tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.pyi +6 -0
  41. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.py +9 -7
  42. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.pyi +12 -4
  43. tracdap/rt/_impl/grpc/tracdap/metadata/resource_pb2.py +18 -5
  44. tracdap/rt/_impl/grpc/tracdap/metadata/resource_pb2.pyi +42 -2
  45. tracdap/rt/_impl/grpc/tracdap/metadata/search_pb2.py +1 -1
  46. tracdap/rt/_impl/grpc/tracdap/metadata/{stoarge_pb2.py → storage_pb2.py} +4 -4
  47. tracdap/rt/_impl/grpc/tracdap/metadata/tag_pb2.py +1 -1
  48. tracdap/rt/_impl/grpc/tracdap/metadata/tag_update_pb2.py +1 -1
  49. tracdap/rt/_impl/grpc/tracdap/metadata/type_pb2.py +1 -1
  50. tracdap/rt/{_exec → _impl}/runtime.py +32 -18
  51. tracdap/rt/_impl/static_api.py +66 -38
  52. tracdap/rt/_plugins/format_csv.py +1 -1
  53. tracdap/rt/_plugins/repo_git.py +56 -11
  54. tracdap/rt/_plugins/storage_sql.py +13 -6
  55. tracdap/rt/_version.py +1 -1
  56. tracdap/rt/api/__init__.py +5 -24
  57. tracdap/rt/api/constants.py +57 -0
  58. tracdap/rt/api/experimental.py +32 -0
  59. tracdap/rt/api/hook.py +26 -7
  60. tracdap/rt/api/model_api.py +16 -0
  61. tracdap/rt/api/static_api.py +265 -127
  62. tracdap/rt/config/__init__.py +11 -11
  63. tracdap/rt/config/common.py +2 -26
  64. tracdap/rt/config/dynamic.py +28 -0
  65. tracdap/rt/config/platform.py +17 -31
  66. tracdap/rt/config/runtime.py +2 -0
  67. tracdap/rt/ext/embed.py +2 -2
  68. tracdap/rt/ext/plugins.py +3 -3
  69. tracdap/rt/launch/launch.py +12 -14
  70. tracdap/rt/metadata/__init__.py +31 -21
  71. tracdap/rt/metadata/config.py +95 -0
  72. tracdap/rt/metadata/data.py +40 -0
  73. tracdap/rt/metadata/file.py +10 -0
  74. tracdap/rt/metadata/job.py +16 -0
  75. tracdap/rt/metadata/model.py +12 -2
  76. tracdap/rt/metadata/object.py +9 -1
  77. tracdap/rt/metadata/object_id.py +6 -0
  78. tracdap/rt/metadata/resource.py +41 -1
  79. {tracdap_runtime-0.7.0rc1.dist-info → tracdap_runtime-0.8.0.dist-info}/METADATA +33 -27
  80. tracdap_runtime-0.8.0.dist-info/RECORD +129 -0
  81. {tracdap_runtime-0.7.0rc1.dist-info → tracdap_runtime-0.8.0.dist-info}/WHEEL +1 -1
  82. tracdap/rt/_exec/__init__.py +0 -0
  83. tracdap_runtime-0.7.0rc1.dist-info/RECORD +0 -121
  84. /tracdap/rt/_impl/{guard_rails.py → core/guard_rails.py} +0 -0
  85. /tracdap/rt/_impl/grpc/tracdap/metadata/{stoarge_pb2.pyi → storage_pb2.pyi} +0 -0
  86. /tracdap/rt/metadata/{stoarge.py → storage.py} +0 -0
  87. {tracdap_runtime-0.7.0rc1.dist-info → tracdap_runtime-0.8.0.dist-info/licenses}/LICENSE +0 -0
  88. {tracdap_runtime-0.7.0rc1.dist-info → tracdap_runtime-0.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,195 @@
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.
15
+
16
+ import io as _io
17
+ import sys as _sys
18
+ import typing as _tp
19
+
20
+ from logging import *
21
+
22
+
23
+ class PlainFormatter(Formatter):
24
+
25
+ FORMAT = f"%(asctime)s [%(threadName)s] %(levelname)s %(name)s" + \
26
+ f" - %(message)s"
27
+
28
+ def __init__(self):
29
+ super().__init__(self.FORMAT)
30
+
31
+
32
+ class ColorFormatter(Formatter):
33
+
34
+ _BLACK, _RED, _GREEN, _YELLOW, _BLUE, _MAGENTA, _CYAN, _WHITE, _DEFAULT_WHITE = range(9)
35
+ _DARK_BASE = 30
36
+ _LIGHT_BASE = 90
37
+
38
+ # DARK_BASE + WHITE = light grey
39
+ # DARK_BASE + DEFAULT_WHITE = regular console white
40
+ # LIGHT_BASE + WHITE = bright white (0xffffff), very bright!
41
+
42
+ def __init__(self, is_bright: bool):
43
+
44
+ super().__init__(self._base_fmt(is_bright))
45
+ self._level_colors = self._make_level_colors(is_bright)
46
+ self._default_color = self._make_default_color(is_bright)
47
+
48
+ def format(self, record):
49
+
50
+ level_name = record.levelname
51
+ level_color = self._level_colors.get(level_name)
52
+
53
+ if level_color:
54
+ record.levelname = level_color
55
+ else:
56
+ record.levelname = self._default_color + level_name
57
+
58
+ return Formatter.format(self, record)
59
+
60
+ def _base_fmt(self, is_bright: bool):
61
+
62
+ if is_bright:
63
+ base_color = self._make_ansi_code(self._DARK_BASE, self._DEFAULT_WHITE, is_bold=False)
64
+ message_color = self._make_ansi_code(self._LIGHT_BASE, self._CYAN, is_bold=False)
65
+ else:
66
+ base_color = self._make_ansi_code(self._DARK_BASE, self._WHITE, is_bold=False)
67
+ message_color = self._make_ansi_code(self._DARK_BASE, self._CYAN, is_bold=False)
68
+
69
+ return f"{base_color}%(asctime)s [%(threadName)s] %(levelname)s{base_color} %(name)s" + \
70
+ f" - {message_color}%(message)s"
71
+
72
+ def _make_level_colors(self, is_bright: bool):
73
+
74
+ base_code = self._LIGHT_BASE if is_bright else self._DARK_BASE
75
+
76
+ green = self._make_ansi_code(base_code, self._GREEN, is_bold=is_bright)
77
+ yellow = self._make_ansi_code(base_code, self._YELLOW, is_bold=is_bright)
78
+ red = self._make_ansi_code(base_code, self._RED, is_bold=is_bright)
79
+
80
+ level_colors = {
81
+ 'CRITICAL': f"{red}CRITICAL",
82
+ 'ERROR': f"{red}ERROR",
83
+ 'WARNING': f"{yellow}WARNING",
84
+ 'INFO': f"{green}INFO"
85
+ }
86
+
87
+ return level_colors
88
+
89
+ def _make_default_color(self, is_bright: bool):
90
+
91
+ base_code = self._LIGHT_BASE if is_bright else self._DARK_BASE
92
+ blue = self._make_ansi_code(base_code, self._BLUE, is_bold=is_bright)
93
+
94
+ return blue
95
+
96
+ @classmethod
97
+ def _make_ansi_code(cls, base_code: int, color_offset: int, is_bold: bool):
98
+ return f"\033[{1 if is_bold else 0};{base_code + color_offset}m"
99
+
100
+
101
+ def configure_logging(enable_debug=False):
102
+
103
+ root_logger = getLogger()
104
+ log_level = DEBUG if enable_debug else INFO
105
+
106
+ if not root_logger.hasHandlers():
107
+
108
+ console_formatter = ColorFormatter(is_bright=True)
109
+ console_handler = StreamHandler(_sys.stdout)
110
+ console_handler.setFormatter(console_formatter)
111
+ console_handler.setLevel(INFO)
112
+ root_logger.addHandler(console_handler)
113
+ root_logger.setLevel(log_level)
114
+
115
+ # Use is_bright=False for logs from the TRAC runtime, so model logs stand out
116
+
117
+ trac_logger = getLogger("tracdap.rt")
118
+
119
+ console_formatter = ColorFormatter(is_bright=False)
120
+ console_handler = StreamHandler(_sys.stdout)
121
+ console_handler.setFormatter(console_formatter)
122
+ console_handler.setLevel(log_level)
123
+ trac_logger.addHandler(console_handler)
124
+ trac_logger.propagate = False
125
+
126
+
127
+ def logger_for_object(obj: object) -> Logger:
128
+ return logger_for_class(obj.__class__)
129
+
130
+
131
+ def logger_for_class(clazz: type) -> Logger:
132
+ qualified_class_name = f"{clazz.__module__}.{clazz.__name__}"
133
+ return getLogger(qualified_class_name)
134
+
135
+
136
+ def logger_for_namespace(namespace: str) -> Logger:
137
+ return getLogger(namespace)
138
+
139
+
140
+ class JobLogger(Logger):
141
+
142
+ def __init__(self, sys_log: Logger, *handlers: Handler):
143
+
144
+ super().__init__(sys_log.name, sys_log.level)
145
+ self._sys_log = sys_log._log
146
+ self._job_log = super()._log
147
+
148
+ for handler in handlers:
149
+ self.addHandler(handler)
150
+
151
+ def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False, stacklevel=1):
152
+
153
+ self._sys_log(level, msg, args, exc_info, extra, stack_info, stacklevel)
154
+ self._job_log(level, msg, args, exc_info, extra, stack_info, stacklevel)
155
+
156
+
157
+ class LogProvider:
158
+
159
+ def logger_for_object(self, obj: object) -> Logger:
160
+ return logger_for_object(obj)
161
+
162
+ def logger_for_class(self, clazz: type) -> Logger:
163
+ return logger_for_class(clazz)
164
+
165
+ def logger_for_namespace(self, namespace: str) -> Logger:
166
+ return logger_for_namespace(namespace)
167
+
168
+
169
+ class JobLogProvider(LogProvider):
170
+
171
+ def __init__(self, *handlers: Handler):
172
+ self.__handlers = handlers
173
+
174
+ def logger_for_object(self, obj: object) -> Logger:
175
+ base_logger = logger_for_object(obj)
176
+ return JobLogger(base_logger, *self.__handlers)
177
+
178
+ def logger_for_class(self, clazz: type) -> Logger:
179
+ base_logger = logger_for_class(clazz)
180
+ return JobLogger(base_logger, *self.__handlers)
181
+
182
+ def logger_for_namespace(self, namespace: str) -> Logger:
183
+ base_logger = logger_for_namespace(namespace)
184
+ return JobLogger(base_logger, *self.__handlers)
185
+
186
+
187
+ def job_log_provider(target: _tp.BinaryIO) -> JobLogProvider:
188
+
189
+ stream = _io.TextIOWrapper(target, newline="\r\n")
190
+ formatter = PlainFormatter()
191
+
192
+ handler = StreamHandler(stream)
193
+ handler.setFormatter(formatter)
194
+
195
+ return JobLogProvider(handler)
@@ -25,11 +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.type_system as _types
29
- import tracdap.rt._impl.repos as _repos
30
- import tracdap.rt._impl.shim as _shim
31
- import tracdap.rt._impl.util as _util
32
- 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
33
34
 
34
35
 
35
36
  class ModelLoader:
@@ -43,7 +44,7 @@ class ModelLoader:
43
44
 
44
45
  def __init__(self, sys_config: _cfg.RuntimeConfig, scratch_dir: pathlib.Path):
45
46
 
46
- self.__log = _util.logger_for_object(self)
47
+ self.__log = _logging.logger_for_object(self)
47
48
 
48
49
  self.__scratch_dir = scratch_dir.joinpath("models")
49
50
  self.__repos = _repos.RepositoryManager(sys_config)
@@ -226,13 +227,15 @@ class ModelLoader:
226
227
  self.__log.info(f"Parameter [{name}] - {param.paramType.basicType.name}")
227
228
  param.paramProps = self._encoded_props(param.paramProps, "parameter", name)
228
229
 
229
- for name, schema in model_def.inputs.items():
230
- self.__log.info(f"Input [{name}] - {schema.schema.schemaType.name}")
231
- schema.inputProps = self._encoded_props(schema.inputProps, "input", name)
230
+ for name, input_def in model_def.inputs.items():
231
+ input_type = input_def.schema.schemaType.name if input_def.objectType == _meta.ObjectType.DATA else input_def.objectType.name
232
+ self.__log.info(f"Input [{name}] - {input_type}")
233
+ input_def.inputProps = self._encoded_props(input_def.inputProps, "input", name)
232
234
 
233
- for name, schema in model_def.outputs.items():
234
- self.__log.info(f"Output [{name}] - {schema.schema.schemaType.name}")
235
- schema.outputProps = self._encoded_props(schema.outputProps, "input", name)
235
+ for name, output_def in model_def.outputs.items():
236
+ output_type = output_def.schema.schemaType.name if output_def.objectType == _meta.ObjectType.DATA else output_def.objectType.name
237
+ self.__log.info(f"Output [{name}] - {output_type}")
238
+ output_def.outputProps = self._encoded_props(output_def.outputProps, "input", name)
236
239
 
237
240
  return model_def
238
241
 
@@ -13,10 +13,12 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import typing as _tp
17
+
16
18
  import tracdap.rt.ext.plugins as plugins
17
19
  import tracdap.rt.config as cfg
18
20
  import tracdap.rt.exceptions as ex
19
- import tracdap.rt._impl.util as util
21
+ import tracdap.rt._impl.core.logging as _logging
20
22
 
21
23
  # Import repo interfaces
22
24
  from tracdap.rt.ext.repos import *
@@ -26,8 +28,8 @@ class RepositoryManager:
26
28
 
27
29
  def __init__(self, sys_config: cfg.RuntimeConfig):
28
30
 
29
- self._log = util.logger_for_object(self)
30
- self._repos: tp.Dict[str, IModelRepository] = dict()
31
+ self._log = _logging.logger_for_object(self)
32
+ self._repos: _tp.Dict[str, IModelRepository] = dict()
31
33
 
32
34
  # Initialize all repos in the system config
33
35
  # Any errors for missing repo types (plugins) will be raised during startup
@@ -36,6 +38,13 @@ class RepositoryManager:
36
38
 
37
39
  try:
38
40
 
41
+ # Add global properties related to the repo protocol
42
+ related_props = {
43
+ k: v for (k, v) in sys_config.properties.items()
44
+ if k.startswith(f"{repo_config.protocol}.")}
45
+
46
+ repo_config.properties.update(related_props)
47
+
39
48
  self._repos[repo_name] = plugins.PluginManager.load_plugin(IModelRepository, repo_config)
40
49
 
41
50
  except ex.EPluginNotAvailable as e:
@@ -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.storage as _storage
26
- import tracdap.rt._impl.shim as _shim
27
- import tracdap.rt._impl.util as _util
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:
@@ -169,4 +169,4 @@ class SchemaLoader:
169
169
  raise _ex.EDataConformance(err)
170
170
 
171
171
 
172
- SchemaLoader._log = _util.logger_for_class(SchemaLoader)
172
+ SchemaLoader._log = _log.logger_for_class(SchemaLoader)
@@ -30,8 +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.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
35
36
 
36
37
 
37
38
  class _Shim:
@@ -138,7 +139,7 @@ class _NamespaceShimFinder(_ila.MetaPathFinder):
138
139
  def __init__(self, shim_map: tp.Dict[str, _Shim], active_shim: _ActiveShim):
139
140
  self.__shim_map = shim_map
140
141
  self.__active_shim = active_shim
141
- self._log = _util.logger_for_class(ShimLoader)
142
+ self._log = _log.logger_for_class(ShimLoader)
142
143
 
143
144
  def find_spec(
144
145
  self, fullname: str,
@@ -561,5 +562,5 @@ class ShimLoader:
561
562
  raise _ex.ERuntimeValidation(err)
562
563
 
563
564
 
564
- ShimLoader._log = _util.logger_for_class(ShimLoader)
565
+ ShimLoader._log = _log.logger_for_class(ShimLoader)
565
566
  ShimLoader._init() # noqa
@@ -29,9 +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.util as _util
34
- 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
35
36
 
36
37
  # Import storage interfaces (using the internal version, it has extra bits that are not public)
37
38
  from tracdap.rt._impl.ext.storage import *
@@ -76,11 +77,11 @@ class StorageManager:
76
77
 
77
78
  def __init__(self, sys_config: _cfg.RuntimeConfig):
78
79
 
79
- self.__log = _util.logger_for_object(self)
80
+ self.__log = _logging.logger_for_object(self)
80
81
  self.__file_storage: tp.Dict[str, IFileStorage] = dict()
81
82
  self.__data_storage: tp.Dict[str, IDataStorage] = dict()
82
83
  self.__external: tp.List[str] = list()
83
- self.__settings = sys_config.storage
84
+ self.__sys_config = sys_config
84
85
 
85
86
  for storage_key, storage_config in sys_config.storage.buckets.items():
86
87
  self.create_storage(storage_key, storage_config)
@@ -92,13 +93,20 @@ class StorageManager:
92
93
  self.create_storage(storage_key, storage_config)
93
94
 
94
95
  def default_storage_key(self):
95
- return self.__settings.defaultBucket
96
+ return self.__sys_config.storage.defaultBucket
96
97
 
97
98
  def default_storage_format(self):
98
- return self.__settings.defaultFormat
99
+ return self.__sys_config.storage.defaultFormat
99
100
 
100
101
  def create_storage(self, storage_key: str, storage_config: _cfg.PluginConfig):
101
102
 
103
+ # Add global properties related to the storage protocol
104
+ related_props = {
105
+ k: v for (k, v) in self.__sys_config.properties.items()
106
+ if k.startswith(f"{storage_config.protocol}.")}
107
+
108
+ storage_config.properties.update(related_props)
109
+
102
110
  if plugins.PluginManager.is_plugin_available(IStorageProvider, storage_config.protocol):
103
111
  self._create_storage_from_provider(storage_key, storage_config)
104
112
  else:
@@ -224,7 +232,7 @@ class CommonFileStorage(IFileStorage):
224
232
 
225
233
  def __init__(self, storage_key: str, storage_config: _cfg.PluginConfig, fs: pa_fs.SubTreeFileSystem):
226
234
 
227
- self._log = _util.logger_for_object(self)
235
+ self._log = _logging.logger_for_object(self)
228
236
  self._key = storage_key
229
237
  self._config = storage_config
230
238
  self._fs = fs
@@ -495,7 +503,10 @@ class CommonFileStorage(IFileStorage):
495
503
 
496
504
  # For successful write streams, log the total size written
497
505
  if is_write and not error:
498
- file_size = _util.format_file_size(stream.tell())
506
+ if not stream.closed:
507
+ file_size = _util.format_file_size(stream.tell())
508
+ else:
509
+ file_size = self._fs.get_file_info(storage_path).size
499
510
  self._log.info(f"File size [{self._key}]: {file_size} [{storage_path}]")
500
511
 
501
512
  # Close the stream - this may take time for write streams that are not flushed
@@ -731,7 +742,7 @@ class CommonDataStorage(IDataStorage):
731
742
  self, config: _cfg.PluginConfig, file_storage: IFileStorage,
732
743
  pushdown_pandas: bool = False, pushdown_spark: bool = False):
733
744
 
734
- self.__log = _util.logger_for_object(self)
745
+ self.__log = _logging.logger_for_object(self)
735
746
 
736
747
  self.__config = config
737
748
  self.__file_storage = file_storage