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.
Files changed (102) hide show
  1. tracdap/rt/_exec/actors.py +87 -10
  2. tracdap/rt/_exec/context.py +25 -1
  3. tracdap/rt/_exec/dev_mode.py +277 -221
  4. tracdap/rt/_exec/engine.py +79 -14
  5. tracdap/rt/_exec/functions.py +37 -8
  6. tracdap/rt/_exec/graph.py +2 -0
  7. tracdap/rt/_exec/graph_builder.py +118 -56
  8. tracdap/rt/_exec/runtime.py +108 -37
  9. tracdap/rt/_exec/server.py +345 -0
  10. tracdap/rt/_impl/config_parser.py +219 -49
  11. tracdap/rt/_impl/data.py +14 -0
  12. tracdap/rt/_impl/grpc/__init__.py +13 -0
  13. tracdap/rt/_impl/grpc/codec.py +99 -0
  14. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.py +51 -0
  15. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.pyi +61 -0
  16. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2_grpc.py +183 -0
  17. tracdap/rt/_impl/grpc/tracdap/metadata/common_pb2.py +33 -0
  18. tracdap/rt/_impl/grpc/tracdap/metadata/common_pb2.pyi +34 -0
  19. tracdap/rt/{metadata → _impl/grpc/tracdap/metadata}/custom_pb2.py +5 -5
  20. tracdap/rt/_impl/grpc/tracdap/metadata/custom_pb2.pyi +15 -0
  21. tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.py +51 -0
  22. tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.pyi +115 -0
  23. tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.py +28 -0
  24. tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.pyi +22 -0
  25. tracdap/rt/_impl/grpc/tracdap/metadata/flow_pb2.py +59 -0
  26. tracdap/rt/_impl/grpc/tracdap/metadata/flow_pb2.pyi +109 -0
  27. tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.py +76 -0
  28. tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.pyi +177 -0
  29. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.py +63 -0
  30. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.pyi +119 -0
  31. tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.py +32 -0
  32. tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.pyi +68 -0
  33. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.py +40 -0
  34. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.pyi +46 -0
  35. tracdap/rt/_impl/grpc/tracdap/metadata/search_pb2.py +39 -0
  36. tracdap/rt/_impl/grpc/tracdap/metadata/search_pb2.pyi +83 -0
  37. tracdap/rt/_impl/grpc/tracdap/metadata/stoarge_pb2.py +50 -0
  38. tracdap/rt/_impl/grpc/tracdap/metadata/stoarge_pb2.pyi +89 -0
  39. tracdap/rt/_impl/grpc/tracdap/metadata/tag_pb2.py +34 -0
  40. tracdap/rt/_impl/grpc/tracdap/metadata/tag_pb2.pyi +26 -0
  41. tracdap/rt/_impl/grpc/tracdap/metadata/tag_update_pb2.py +30 -0
  42. tracdap/rt/_impl/grpc/tracdap/metadata/tag_update_pb2.pyi +34 -0
  43. tracdap/rt/_impl/grpc/tracdap/metadata/type_pb2.py +47 -0
  44. tracdap/rt/_impl/grpc/tracdap/metadata/type_pb2.pyi +101 -0
  45. tracdap/rt/_impl/guard_rails.py +26 -6
  46. tracdap/rt/_impl/models.py +25 -0
  47. tracdap/rt/_impl/static_api.py +27 -9
  48. tracdap/rt/_impl/type_system.py +17 -0
  49. tracdap/rt/_impl/validation.py +10 -0
  50. tracdap/rt/_plugins/config_local.py +49 -0
  51. tracdap/rt/_version.py +1 -1
  52. tracdap/rt/api/hook.py +10 -3
  53. tracdap/rt/api/model_api.py +22 -0
  54. tracdap/rt/api/static_api.py +79 -19
  55. tracdap/rt/config/__init__.py +3 -3
  56. tracdap/rt/config/common.py +10 -0
  57. tracdap/rt/config/platform.py +9 -19
  58. tracdap/rt/config/runtime.py +2 -0
  59. tracdap/rt/ext/config.py +34 -0
  60. tracdap/rt/ext/embed.py +1 -3
  61. tracdap/rt/ext/plugins.py +47 -6
  62. tracdap/rt/launch/cli.py +7 -5
  63. tracdap/rt/launch/launch.py +49 -12
  64. tracdap/rt/metadata/__init__.py +24 -24
  65. tracdap/rt/metadata/common.py +7 -7
  66. tracdap/rt/metadata/custom.py +2 -0
  67. tracdap/rt/metadata/data.py +28 -5
  68. tracdap/rt/metadata/file.py +2 -0
  69. tracdap/rt/metadata/flow.py +66 -4
  70. tracdap/rt/metadata/job.py +56 -16
  71. tracdap/rt/metadata/model.py +10 -0
  72. tracdap/rt/metadata/object.py +3 -0
  73. tracdap/rt/metadata/object_id.py +9 -9
  74. tracdap/rt/metadata/search.py +35 -13
  75. tracdap/rt/metadata/stoarge.py +64 -6
  76. tracdap/rt/metadata/tag_update.py +21 -7
  77. tracdap/rt/metadata/type.py +28 -13
  78. {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/METADATA +22 -19
  79. tracdap_runtime-0.6.3.dist-info/RECORD +112 -0
  80. {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/WHEEL +1 -1
  81. tracdap/rt/config/common_pb2.py +0 -55
  82. tracdap/rt/config/job_pb2.py +0 -42
  83. tracdap/rt/config/platform_pb2.py +0 -71
  84. tracdap/rt/config/result_pb2.py +0 -37
  85. tracdap/rt/config/runtime_pb2.py +0 -42
  86. tracdap/rt/ext/_guard.py +0 -37
  87. tracdap/rt/metadata/common_pb2.py +0 -33
  88. tracdap/rt/metadata/data_pb2.py +0 -51
  89. tracdap/rt/metadata/file_pb2.py +0 -28
  90. tracdap/rt/metadata/flow_pb2.py +0 -55
  91. tracdap/rt/metadata/job_pb2.py +0 -76
  92. tracdap/rt/metadata/model_pb2.py +0 -51
  93. tracdap/rt/metadata/object_id_pb2.py +0 -32
  94. tracdap/rt/metadata/object_pb2.py +0 -35
  95. tracdap/rt/metadata/search_pb2.py +0 -39
  96. tracdap/rt/metadata/stoarge_pb2.py +0 -50
  97. tracdap/rt/metadata/tag_pb2.py +0 -34
  98. tracdap/rt/metadata/tag_update_pb2.py +0 -30
  99. tracdap/rt/metadata/type_pb2.py +0 -48
  100. tracdap_runtime-0.6.1.dev3.dist-info/RECORD +0 -96
  101. {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/LICENSE +0 -0
  102. {tracdap_runtime-0.6.1.dev3.dist-info → tracdap_runtime-0.6.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,101 @@
1
+ from google.protobuf.internal import containers as _containers
2
+ from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
3
+ from google.protobuf import descriptor as _descriptor
4
+ from google.protobuf import message as _message
5
+ from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
6
+
7
+ DESCRIPTOR: _descriptor.FileDescriptor
8
+
9
+ class BasicType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
10
+ __slots__ = ()
11
+ BASIC_TYPE_NOT_SET: _ClassVar[BasicType]
12
+ BOOLEAN: _ClassVar[BasicType]
13
+ INTEGER: _ClassVar[BasicType]
14
+ FLOAT: _ClassVar[BasicType]
15
+ STRING: _ClassVar[BasicType]
16
+ DECIMAL: _ClassVar[BasicType]
17
+ DATE: _ClassVar[BasicType]
18
+ DATETIME: _ClassVar[BasicType]
19
+ ARRAY: _ClassVar[BasicType]
20
+ MAP: _ClassVar[BasicType]
21
+ BASIC_TYPE_NOT_SET: BasicType
22
+ BOOLEAN: BasicType
23
+ INTEGER: BasicType
24
+ FLOAT: BasicType
25
+ STRING: BasicType
26
+ DECIMAL: BasicType
27
+ DATE: BasicType
28
+ DATETIME: BasicType
29
+ ARRAY: BasicType
30
+ MAP: BasicType
31
+
32
+ class TypeDescriptor(_message.Message):
33
+ __slots__ = ("basicType", "arrayType", "mapType")
34
+ BASICTYPE_FIELD_NUMBER: _ClassVar[int]
35
+ ARRAYTYPE_FIELD_NUMBER: _ClassVar[int]
36
+ MAPTYPE_FIELD_NUMBER: _ClassVar[int]
37
+ basicType: BasicType
38
+ arrayType: TypeDescriptor
39
+ mapType: TypeDescriptor
40
+ def __init__(self, basicType: _Optional[_Union[BasicType, str]] = ..., arrayType: _Optional[_Union[TypeDescriptor, _Mapping]] = ..., mapType: _Optional[_Union[TypeDescriptor, _Mapping]] = ...) -> None: ...
41
+
42
+ class DecimalValue(_message.Message):
43
+ __slots__ = ("decimal",)
44
+ DECIMAL_FIELD_NUMBER: _ClassVar[int]
45
+ decimal: str
46
+ def __init__(self, decimal: _Optional[str] = ...) -> None: ...
47
+
48
+ class DateValue(_message.Message):
49
+ __slots__ = ("isoDate",)
50
+ ISODATE_FIELD_NUMBER: _ClassVar[int]
51
+ isoDate: str
52
+ def __init__(self, isoDate: _Optional[str] = ...) -> None: ...
53
+
54
+ class DatetimeValue(_message.Message):
55
+ __slots__ = ("isoDatetime",)
56
+ ISODATETIME_FIELD_NUMBER: _ClassVar[int]
57
+ isoDatetime: str
58
+ def __init__(self, isoDatetime: _Optional[str] = ...) -> None: ...
59
+
60
+ class Value(_message.Message):
61
+ __slots__ = ("type", "booleanValue", "integerValue", "floatValue", "stringValue", "decimalValue", "dateValue", "datetimeValue", "arrayValue", "mapValue")
62
+ TYPE_FIELD_NUMBER: _ClassVar[int]
63
+ BOOLEANVALUE_FIELD_NUMBER: _ClassVar[int]
64
+ INTEGERVALUE_FIELD_NUMBER: _ClassVar[int]
65
+ FLOATVALUE_FIELD_NUMBER: _ClassVar[int]
66
+ STRINGVALUE_FIELD_NUMBER: _ClassVar[int]
67
+ DECIMALVALUE_FIELD_NUMBER: _ClassVar[int]
68
+ DATEVALUE_FIELD_NUMBER: _ClassVar[int]
69
+ DATETIMEVALUE_FIELD_NUMBER: _ClassVar[int]
70
+ ARRAYVALUE_FIELD_NUMBER: _ClassVar[int]
71
+ MAPVALUE_FIELD_NUMBER: _ClassVar[int]
72
+ type: TypeDescriptor
73
+ booleanValue: bool
74
+ integerValue: int
75
+ floatValue: float
76
+ stringValue: str
77
+ decimalValue: DecimalValue
78
+ dateValue: DateValue
79
+ datetimeValue: DatetimeValue
80
+ arrayValue: ArrayValue
81
+ mapValue: MapValue
82
+ def __init__(self, type: _Optional[_Union[TypeDescriptor, _Mapping]] = ..., booleanValue: bool = ..., integerValue: _Optional[int] = ..., floatValue: _Optional[float] = ..., stringValue: _Optional[str] = ..., decimalValue: _Optional[_Union[DecimalValue, _Mapping]] = ..., dateValue: _Optional[_Union[DateValue, _Mapping]] = ..., datetimeValue: _Optional[_Union[DatetimeValue, _Mapping]] = ..., arrayValue: _Optional[_Union[ArrayValue, _Mapping]] = ..., mapValue: _Optional[_Union[MapValue, _Mapping]] = ...) -> None: ...
83
+
84
+ class ArrayValue(_message.Message):
85
+ __slots__ = ("items",)
86
+ ITEMS_FIELD_NUMBER: _ClassVar[int]
87
+ items: _containers.RepeatedCompositeFieldContainer[Value]
88
+ def __init__(self, items: _Optional[_Iterable[_Union[Value, _Mapping]]] = ...) -> None: ...
89
+
90
+ class MapValue(_message.Message):
91
+ __slots__ = ("entries",)
92
+ class EntriesEntry(_message.Message):
93
+ __slots__ = ("key", "value")
94
+ KEY_FIELD_NUMBER: _ClassVar[int]
95
+ VALUE_FIELD_NUMBER: _ClassVar[int]
96
+ key: str
97
+ value: Value
98
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ...) -> None: ...
99
+ ENTRIES_FIELD_NUMBER: _ClassVar[int]
100
+ entries: _containers.MessageMap[str, Value]
101
+ def __init__(self, entries: _Optional[_Mapping[str, Value]] = ...) -> None: ...
@@ -46,6 +46,27 @@ def _get_package_path(module_name):
46
46
  return module_path.parents[depth]
47
47
 
48
48
 
49
+ def run_model_guard(operation: str = None):
50
+
51
+ # A simple guard method to block model code from accessing parts of the TRAC runtime framework
52
+ # To blocks calls to the Python stdlib or 3rd party libs, use PythonGuardRails instead
53
+
54
+ stack = inspect.stack()
55
+ frame = stack[-1]
56
+
57
+ if operation is None:
58
+ operation = f"Calling {frame.function}()"
59
+
60
+ for frame_index in range(len(stack) - 2, 0, -1):
61
+
62
+ parent_frame = frame
63
+ frame = stack[frame_index]
64
+
65
+ if frame.function == "run_model" and parent_frame.function == "_execute":
66
+ err = f"{operation} is not allowed inside run_model()"
67
+ raise ex.ERuntimeValidation(err)
68
+
69
+
49
70
  class PythonGuardRails:
50
71
 
51
72
  DANGEROUS_BUILTIN_FUNCTIONS = ["exec", "eval", "compile", "open", "input", "memoryview"]
@@ -258,14 +279,13 @@ class PythonGuardRails:
258
279
  @classmethod
259
280
  def is_debug(cls):
260
281
 
261
- get_trace_func = getattr(sys, 'gettrace', None)
282
+ has_trace = hasattr(sys, 'gettrace') and sys.gettrace() is not None
283
+ has_breakpoint = sys.breakpointhook.__module__ != "sys"
262
284
 
263
- if get_trace_func is None:
264
- return False
285
+ if has_trace or has_breakpoint:
286
+ return True
265
287
 
266
- else:
267
- trace = get_trace_func()
268
- return trace is not None
288
+ return False
269
289
 
270
290
  @classmethod
271
291
  def is_import(cls):
@@ -215,12 +215,15 @@ class ModelLoader:
215
215
 
216
216
  for name, param in model_def.parameters.items():
217
217
  self.__log.info(f"Parameter [{name}] - {param.paramType.basicType.name}")
218
+ param.paramProps = self._encoded_props(param.paramProps, "parameter", name)
218
219
 
219
220
  for name, schema in model_def.inputs.items():
220
221
  self.__log.info(f"Input [{name}] - {schema.schema.schemaType.name}")
222
+ schema.inputProps = self._encoded_props(schema.inputProps, "input", name)
221
223
 
222
224
  for name, schema in model_def.outputs.items():
223
225
  self.__log.info(f"Output [{name}] - {schema.schema.schemaType.name}")
226
+ schema.outputProps = self._encoded_props(schema.outputProps, "input", name)
224
227
 
225
228
  return model_def
226
229
 
@@ -231,3 +234,25 @@ class ModelLoader:
231
234
 
232
235
  self.__log.error(msg, exc_info=True)
233
236
  raise _ex.EModelValidation(msg) from e
237
+
238
+ @staticmethod
239
+ def _encoded_props(
240
+ raw_props: tp.Dict[str, tp.Any],
241
+ item_type: str, item_name: str) \
242
+ -> tp.Dict[str, _meta.Value]:
243
+
244
+ if raw_props is None:
245
+ return dict()
246
+
247
+ encoded_props = dict()
248
+
249
+ for key, raw_value in raw_props.items():
250
+
251
+ if raw_value is None:
252
+ raise _ex.EModelValidation(f"Invalid null property [{key}] for {item_type} [{item_name}]")
253
+ elif isinstance(raw_value, _meta.Value):
254
+ encoded_props[key] = raw_value
255
+ else:
256
+ encoded_props[key] = _types.MetadataCodec.encode_value(raw_value)
257
+
258
+ return encoded_props
@@ -71,10 +71,14 @@ class StaticApiImpl(_StaticApiHook):
71
71
 
72
72
  def define_parameter(
73
73
  self, param_name: str, param_type: _tp.Union[_meta.TypeDescriptor, _meta.BasicType],
74
- label: str, default_value: _tp.Optional[_tp.Any] = None) \
74
+ label: str, default_value: _tp.Optional[_tp.Any] = None,
75
+ *, param_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
75
76
  -> _Named[_meta.ModelParameter]:
76
77
 
77
- _val.validate_signature(self.define_parameter, param_name, param_type, label, default_value)
78
+ _val.validate_signature(
79
+ self.define_parameter,
80
+ param_name, param_type, label, default_value,
81
+ param_props=param_props)
78
82
 
79
83
  if isinstance(param_type, _meta.TypeDescriptor):
80
84
  param_type_descriptor = param_type
@@ -88,7 +92,9 @@ class StaticApiImpl(_StaticApiHook):
88
92
  msg = f"Default value for parameter [{param_name}] does not match the declared type"
89
93
  raise _ex.EModelValidation(msg) from e
90
94
 
91
- return _Named(param_name, _meta.ModelParameter(param_type_descriptor, label, default_value))
95
+ return _Named(param_name, _meta.ModelParameter(
96
+ param_type_descriptor, label, default_value,
97
+ paramProps=param_props))
92
98
 
93
99
  def define_parameters(
94
100
  self, *params: _tp.Union[_Named[_meta.ModelParameter], _tp.List[_Named[_meta.ModelParameter]]]) \
@@ -147,22 +153,34 @@ class StaticApiImpl(_StaticApiHook):
147
153
  return _schemas.SchemaLoader.load_schema(package, schema_file)
148
154
 
149
155
  def define_input_table(
150
- self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]], label: _tp.Optional[str] = None) \
156
+ self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
157
+ label: _tp.Optional[str] = None,
158
+ optional: bool = False,
159
+ input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
151
160
  -> _meta.ModelInputSchema:
152
161
 
153
- _val.validate_signature(self.define_input_table, *fields, label=label)
162
+ _val.validate_signature(
163
+ self.define_input_table, *fields,
164
+ label=label, optional=optional,
165
+ input_props=input_props)
154
166
 
155
167
  schema_def = self.define_schema(*fields, schema_type=_meta.SchemaType.TABLE)
156
- return _meta.ModelInputSchema(schema=schema_def, label=label)
168
+ return _meta.ModelInputSchema(schema=schema_def, label=label, optional=optional, inputProps=input_props)
157
169
 
158
170
  def define_output_table(
159
- self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]], label: _tp.Optional[str] = None) \
171
+ self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
172
+ label: _tp.Optional[str] = None,
173
+ optional: bool = False,
174
+ output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
160
175
  -> _meta.ModelOutputSchema:
161
176
 
162
- _val.validate_signature(self.define_output_table, *fields, label=label)
177
+ _val.validate_signature(
178
+ self.define_output_table, *fields,
179
+ label=label, optional=optional,
180
+ output_props=output_props)
163
181
 
164
182
  schema_def = self.define_schema(*fields, schema_type=_meta.SchemaType.TABLE)
165
- return _meta.ModelOutputSchema(schema=schema_def, label=label)
183
+ return _meta.ModelOutputSchema(schema=schema_def, label=label, optional=optional, outputProps=output_props)
166
184
 
167
185
  @staticmethod
168
186
  def _build_named_dict(
@@ -171,6 +171,23 @@ class MetadataCodec:
171
171
  type_desc = _meta.TypeDescriptor(_meta.BasicType.DATE)
172
172
  return _meta.Value(type_desc, dateValue=_meta.DateValue(value.isoformat()))
173
173
 
174
+ if isinstance(value, list):
175
+
176
+ if len(value) == 0:
177
+ raise _ex.ETracInternal("Cannot encode an empty list")
178
+
179
+ array_raw_type = type(value[0])
180
+ array_trac_type = TypeMapping.python_to_trac(array_raw_type)
181
+
182
+ if any(map(lambda x: type(x) != array_raw_type, value)):
183
+ raise _ex.ETracInternal("Cannot encode a list with values of different types")
184
+
185
+ encoded_items = list(map(lambda x: cls.convert_value(x, array_trac_type), value))
186
+
187
+ return _meta.Value(
188
+ _meta.TypeDescriptor(_meta.BasicType.ARRAY, arrayType=array_trac_type),
189
+ arrayValue=_meta.ArrayValue(encoded_items))
190
+
174
191
  raise _ex.ETracInternal(f"Value type [{type(value)}] is not supported yet")
175
192
 
176
193
  @classmethod
@@ -320,6 +320,9 @@ class _StaticValidator:
320
320
  else:
321
321
  cls._check_label(param.label, param_name)
322
322
 
323
+ if param.paramProps is not None:
324
+ cls._valid_identifiers(param.paramProps.keys(), "entry in param props")
325
+
323
326
  @classmethod
324
327
  def _check_inputs_or_outputs(cls, inputs_or_outputs):
325
328
 
@@ -340,6 +343,13 @@ class _StaticValidator:
340
343
  label = input_schema.label
341
344
  cls._check_label(label, input_name)
342
345
 
346
+ if isinstance(input_schema, meta.ModelInputSchema):
347
+ if input_schema.inputProps is not None:
348
+ cls._valid_identifiers(input_schema.inputProps.keys(), "entry in input props")
349
+ else:
350
+ if input_schema.outputProps is not None:
351
+ cls._valid_identifiers(input_schema.outputProps.keys(), "entry in output props")
352
+
343
353
  @classmethod
344
354
  def _check_single_field(cls, field: meta.FieldSchema, property_type):
345
355
 
@@ -0,0 +1,49 @@
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 pathlib as pathlib
16
+ import typing as tp
17
+
18
+ import tracdap.rt.ext.plugins as plugins
19
+ import tracdap.rt.exceptions as ex
20
+
21
+ from tracdap.rt.ext.config import *
22
+
23
+
24
+ class LocalConfigLoader(IConfigLoader):
25
+
26
+ # Properties dict will be empty for config plugins
27
+ def __init__(self, properties: tp.Dict[str, str]): # noqa
28
+ pass
29
+
30
+ def has_config_file(self, config_url: str) -> bool:
31
+ if config_url.startswith("file:"):
32
+ config_url = config_url[5:]
33
+ config_path = pathlib.Path(config_url).resolve()
34
+ return config_path.exists() and config_path.is_file()
35
+
36
+ def load_config_file(self, config_url: str) -> bytes:
37
+ if config_url.startswith("file:"):
38
+ config_url = config_url[5:]
39
+ config_path = pathlib.Path(config_url).resolve()
40
+ return config_path.read_bytes()
41
+
42
+ def has_config_dict(self, config_url: str) -> bool:
43
+ return False
44
+
45
+ def load_config_dict(self, config_url: str) -> dict:
46
+ raise ex.ETracInternal("Local config loader does not support loading objects")
47
+
48
+
49
+ plugins.PluginManager.register_plugin(IConfigLoader, LocalConfigLoader, ["LOCAL", "file"])
tracdap/rt/_version.py CHANGED
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "0.6.1.dev3"
15
+ __version__ = "0.6.3"
tracdap/rt/api/hook.py CHANGED
@@ -80,7 +80,8 @@ class _StaticApiHook:
80
80
  @_abc.abstractmethod
81
81
  def define_parameter(
82
82
  self, param_name: str, param_type: _tp.Union[_meta.TypeDescriptor, _meta.BasicType],
83
- label: str, default_value: _tp.Optional[_tp.Any] = None) \
83
+ label: str, default_value: _tp.Optional[_tp.Any] = None,
84
+ *, param_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
84
85
  -> _Named[_meta.ModelParameter]:
85
86
 
86
87
  pass
@@ -119,14 +120,20 @@ class _StaticApiHook:
119
120
 
120
121
  @_abc.abstractmethod
121
122
  def define_input_table(
122
- self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]], label: _tp.Optional[str] = None) \
123
+ self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
124
+ label: _tp.Optional[str] = None,
125
+ optional: bool = False,
126
+ input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
123
127
  -> _meta.ModelInputSchema:
124
128
 
125
129
  pass
126
130
 
127
131
  @_abc.abstractmethod
128
132
  def define_output_table(
129
- self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]], label: _tp.Optional[str] = None) \
133
+ self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
134
+ label: _tp.Optional[str] = None,
135
+ optional: bool = False,
136
+ output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
130
137
  -> _meta.ModelOutputSchema:
131
138
 
132
139
  pass
@@ -72,6 +72,28 @@ class TracContext:
72
72
 
73
73
  pass
74
74
 
75
+ @_abc.abstractmethod
76
+ def has_dataset(self, dataset_name: str) -> bool:
77
+
78
+ """
79
+ Check whether a dataset is available in the current context
80
+
81
+ This method can be used to check whether optional model inputs have been supplied or not.
82
+ Models should use this method before calling get methods on optional inputs.
83
+ For inputs not marked as optional, this method will always return true. For outputs,
84
+ this method will return true after the model calls a put method for the dataset.
85
+
86
+ A runtime validation error will be raised if the dataset name is not defined
87
+ as a model input or output.
88
+
89
+ :param dataset_name: The name of the dataset to check
90
+ :return: True if the dataset exists in the current context, False otherwise
91
+ :rtype: bool
92
+ :raises: :py:class:`ERuntimeValidation <tracdap.rt.exceptions.ERuntimeValidation>`
93
+ """
94
+
95
+ pass
96
+
75
97
  @_abc.abstractmethod
76
98
  def get_schema(self, dataset_name: str) -> SchemaDefinition:
77
99