tracdap-runtime 0.6.2__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 (51) hide show
  1. tracdap/rt/_exec/actors.py +87 -10
  2. tracdap/rt/_exec/dev_mode.py +9 -17
  3. tracdap/rt/_exec/engine.py +79 -14
  4. tracdap/rt/_exec/runtime.py +83 -40
  5. tracdap/rt/_exec/server.py +306 -29
  6. tracdap/rt/_impl/config_parser.py +219 -49
  7. tracdap/rt/_impl/grpc/codec.py +60 -5
  8. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.py +19 -19
  9. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.pyi +11 -9
  10. tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2_grpc.py +25 -25
  11. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.py +28 -16
  12. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.pyi +33 -6
  13. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.py +8 -3
  14. tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.pyi +13 -2
  15. tracdap/rt/_impl/guard_rails.py +21 -0
  16. tracdap/rt/_impl/models.py +25 -0
  17. tracdap/rt/_impl/static_api.py +23 -9
  18. tracdap/rt/_impl/type_system.py +17 -0
  19. tracdap/rt/_impl/validation.py +10 -0
  20. tracdap/rt/_plugins/config_local.py +49 -0
  21. tracdap/rt/_version.py +1 -1
  22. tracdap/rt/api/hook.py +6 -3
  23. tracdap/rt/api/static_api.py +71 -21
  24. tracdap/rt/config/__init__.py +4 -4
  25. tracdap/rt/config/common.py +10 -0
  26. tracdap/rt/config/platform.py +0 -10
  27. tracdap/rt/config/runtime.py +2 -0
  28. tracdap/rt/ext/config.py +34 -0
  29. tracdap/rt/ext/embed.py +1 -3
  30. tracdap/rt/ext/plugins.py +47 -6
  31. tracdap/rt/launch/cli.py +4 -0
  32. tracdap/rt/launch/launch.py +34 -9
  33. tracdap/rt/metadata/__init__.py +17 -17
  34. tracdap/rt/metadata/model.py +6 -0
  35. tracdap/rt/metadata/object.py +3 -0
  36. {tracdap_runtime-0.6.2.dist-info → tracdap_runtime-0.6.3.dist-info}/METADATA +4 -4
  37. {tracdap_runtime-0.6.2.dist-info → tracdap_runtime-0.6.3.dist-info}/RECORD +40 -49
  38. {tracdap_runtime-0.6.2.dist-info → tracdap_runtime-0.6.3.dist-info}/WHEEL +1 -1
  39. tracdap/rt/_impl/grpc/tracdap/config/common_pb2.py +0 -55
  40. tracdap/rt/_impl/grpc/tracdap/config/common_pb2.pyi +0 -103
  41. tracdap/rt/_impl/grpc/tracdap/config/job_pb2.py +0 -42
  42. tracdap/rt/_impl/grpc/tracdap/config/job_pb2.pyi +0 -44
  43. tracdap/rt/_impl/grpc/tracdap/config/platform_pb2.py +0 -71
  44. tracdap/rt/_impl/grpc/tracdap/config/platform_pb2.pyi +0 -197
  45. tracdap/rt/_impl/grpc/tracdap/config/result_pb2.py +0 -37
  46. tracdap/rt/_impl/grpc/tracdap/config/result_pb2.pyi +0 -35
  47. tracdap/rt/_impl/grpc/tracdap/config/runtime_pb2.py +0 -42
  48. tracdap/rt/_impl/grpc/tracdap/config/runtime_pb2.pyi +0 -46
  49. tracdap/rt/ext/_guard.py +0 -37
  50. {tracdap_runtime-0.6.2.dist-info → tracdap_runtime-0.6.3.dist-info}/LICENSE +0 -0
  51. {tracdap_runtime-0.6.2.dist-info → tracdap_runtime-0.6.3.dist-info}/top_level.txt +0 -0
@@ -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]]]) \
@@ -149,24 +155,32 @@ class StaticApiImpl(_StaticApiHook):
149
155
  def define_input_table(
150
156
  self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
151
157
  label: _tp.Optional[str] = None,
152
- optional: bool = False) \
158
+ optional: bool = False,
159
+ input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
153
160
  -> _meta.ModelInputSchema:
154
161
 
155
- _val.validate_signature(self.define_input_table, *fields, label=label, optional=optional)
162
+ _val.validate_signature(
163
+ self.define_input_table, *fields,
164
+ label=label, optional=optional,
165
+ input_props=input_props)
156
166
 
157
167
  schema_def = self.define_schema(*fields, schema_type=_meta.SchemaType.TABLE)
158
- return _meta.ModelInputSchema(schema=schema_def, label=label, optional=optional)
168
+ return _meta.ModelInputSchema(schema=schema_def, label=label, optional=optional, inputProps=input_props)
159
169
 
160
170
  def define_output_table(
161
171
  self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
162
172
  label: _tp.Optional[str] = None,
163
- optional: bool = False) \
173
+ optional: bool = False,
174
+ output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
164
175
  -> _meta.ModelOutputSchema:
165
176
 
166
- _val.validate_signature(self.define_output_table, *fields, label=label, optional=optional)
177
+ _val.validate_signature(
178
+ self.define_output_table, *fields,
179
+ label=label, optional=optional,
180
+ output_props=output_props)
167
181
 
168
182
  schema_def = self.define_schema(*fields, schema_type=_meta.SchemaType.TABLE)
169
- return _meta.ModelOutputSchema(schema=schema_def, label=label, optional=optional)
183
+ return _meta.ModelOutputSchema(schema=schema_def, label=label, optional=optional, outputProps=output_props)
170
184
 
171
185
  @staticmethod
172
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.2"
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
@@ -121,7 +122,8 @@ class _StaticApiHook:
121
122
  def define_input_table(
122
123
  self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
123
124
  label: _tp.Optional[str] = None,
124
- optional: bool = False) \
125
+ optional: bool = False,
126
+ input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
125
127
  -> _meta.ModelInputSchema:
126
128
 
127
129
  pass
@@ -130,7 +132,8 @@ class _StaticApiHook:
130
132
  def define_output_table(
131
133
  self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
132
134
  label: _tp.Optional[str] = None,
133
- optional: bool = False) \
135
+ optional: bool = False,
136
+ output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
134
137
  -> _meta.ModelOutputSchema:
135
138
 
136
139
  pass
@@ -14,6 +14,7 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ import sys
17
18
  import typing as _tp
18
19
  import types as _ts
19
20
 
@@ -111,7 +112,8 @@ def A( # noqa
111
112
 
112
113
  def define_parameter(
113
114
  param_name: str, param_type: _tp.Union[TypeDescriptor, BasicType],
114
- label: str, default_value: _tp.Optional[_tp.Any] = None) \
115
+ label: str, default_value: _tp.Optional[_tp.Any] = None,
116
+ *, param_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
115
117
  -> _Named[ModelParameter]:
116
118
 
117
119
  """
@@ -128,6 +130,10 @@ def define_parameter(
128
130
  the model. TRAC will apply type coercion where possible to ensure the default value matches the parameter type,
129
131
  if the default value cannot be coerced to match the parameter type then model validation will fail.
130
132
 
133
+ You can use param_props to associate arbitrary key-value properties with this model parameter.
134
+ These properties are not used by the TRAC engine, but are stored in the model metadata for
135
+ the parameter and can be used as needed in 3rd-party applications.
136
+
131
137
  Once defined model parameters can be passed to :py:func:`define_parameters`,
132
138
  either as a list or as individual arguments, to create the set of parameters for a model.
133
139
 
@@ -135,6 +141,7 @@ def define_parameter(
135
141
  :param param_type: The parameter type, expressed in the TRAC type system
136
142
  :param label: A descriptive label for the parameter (required)
137
143
  :param default_value: A default value to use if no explicit value is supplied (optional)
144
+ :param param_props: Associate key-value properties with this parameter (not used by the TRAC engine)
138
145
  :return: A named model parameter, suitable for passing to :py:func:`define_parameters`
139
146
 
140
147
  :type param_name: str
@@ -142,11 +149,12 @@ def define_parameter(
142
149
  :py:class:`BasicType <tracdap.rt.metadata.BasicType>`
143
150
  :type label: str
144
151
  :type default_value: Optional[Any]
152
+ :type param_props: Optional[Dict[str, Any]]
145
153
  :rtype: _Named[:py:class:`ModelParameter <tracdap.rt.metadata.ModelParameter>`]
146
154
  """
147
155
 
148
156
  sa = _StaticApiHook.get_instance()
149
- return sa.define_parameter(param_name, param_type, label, default_value)
157
+ return sa.define_parameter(param_name, param_type, label, default_value, param_props=param_props)
150
158
 
151
159
 
152
160
  def declare_parameter(
@@ -160,6 +168,9 @@ def declare_parameter(
160
168
  .. deprecated:: 0.4.4
161
169
  Use :py:func:`define_parameter` or :py:func:`P` instead.
162
170
 
171
+ This function is deprecated and will be removed in a future version.
172
+ Please use :py:func:`define_parameter() <tracdap.rt.api.define_parameter>` instead.
173
+
163
174
  :type param_name: str
164
175
  :type param_type: :py:class:`TypeDescriptor <tracdap.rt.metadata.TypeDescriptor>` |
165
176
  :py:class:`BasicType <tracdap.rt.metadata.BasicType>`
@@ -168,6 +179,8 @@ def declare_parameter(
168
179
  :rtype: _Named[:py:class:`ModelParameter <tracdap.rt.metadata.ModelParameter>`]
169
180
  """
170
181
 
182
+ print("TRAC Warning: declare_parameter() is deprecated, please use define_parameter()", file=sys.stderr)
183
+
171
184
  return define_parameter(param_name, param_type, label, default_value)
172
185
 
173
186
 
@@ -175,7 +188,8 @@ def P( # noqa
175
188
  param_name: str,
176
189
  param_type: _tp.Union[TypeDescriptor, BasicType],
177
190
  label: str,
178
- default_value: _tp.Optional[_tp.Any] = None) \
191
+ default_value: _tp.Optional[_tp.Any] = None,
192
+ *, param_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
179
193
  -> _Named[ModelParameter]:
180
194
 
181
195
  """
@@ -186,12 +200,11 @@ def P( # noqa
186
200
  :py:class:`BasicType <tracdap.rt.metadata.BasicType>`
187
201
  :type label: str
188
202
  :type default_value: Optional[Any]
203
+ :type param_props: Optional[Dict[str, Any]]
189
204
  :rtype: _Named[:py:class:`ModelParameter <tracdap.rt.metadata.ModelParameter>`]
190
205
  """
191
206
 
192
- return declare_parameter(
193
- param_name, param_type, label,
194
- default_value)
207
+ return define_parameter(param_name, param_type, label, default_value, param_props=param_props)
195
208
 
196
209
 
197
210
  def define_parameters(
@@ -226,11 +239,16 @@ def declare_parameters(
226
239
  .. deprecated:: 0.4.4
227
240
  Use :py:func:`define_parameters` instead.
228
241
 
242
+ This function is deprecated and will be removed in a future version.
243
+ Please use :py:func:`define_parameters() <tracdap.rt.api.define_parameters>` instead.
244
+
229
245
  :type params: _Named[:py:class:`ModelParameter <tracdap.rt.metadata.ModelParameter>`] |
230
246
  List[_Named[:py:class:`ModelParameter <tracdap.rt.metadata.ModelParameter>`]]
231
247
  :rtype: Dict[str, :py:class:`ModelParameter <tracdap.rt.metadata.ModelParameter>`]
232
248
  """
233
249
 
250
+ print("TRAC Warning: declare_parameters() is deprecated, please use define_parameters()", file=sys.stderr)
251
+
234
252
  return define_parameters(*params)
235
253
 
236
254
 
@@ -278,9 +296,9 @@ def define_field(
278
296
  :type label: str
279
297
  :type business_key: bool
280
298
  :type categorical: bool
281
- :type not_null: _tp.Optional[bool]
282
- :type format_code: _tp.Optional[str]
283
- :type field_order: _tp.Optional[int]
299
+ :type not_null: Optional[bool]
300
+ :type format_code: Optional[str]
301
+ :type field_order: Optional[int]
284
302
  :rtype: :py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`
285
303
  """
286
304
 
@@ -307,17 +325,22 @@ def declare_field(
307
325
  .. deprecated:: 0.4.4
308
326
  Use :py:func:`define_field` or :py:func:`F` instead.
309
327
 
328
+ This function is deprecated and will be removed in a future version.
329
+ Please use :py:func:`define_field() <tracdap.rt.api.define_field>` instead.
330
+
310
331
  :type field_name: str
311
332
  :type field_type: :py:class:`BasicType <tracdap.rt.metadata.BasicType>`
312
333
  :type label: str
313
334
  :type business_key: bool
314
335
  :type categorical: bool
315
- :type not_null: _tp.Optional[bool]
316
- :type format_code: _tp.Optional[str]
317
- :type field_order: _tp.Optional[int]
336
+ :type not_null: Optional[bool]
337
+ :type format_code: Optional[str]
338
+ :type field_order: Optional[int]
318
339
  :rtype: :py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`
319
340
  """
320
341
 
342
+ print("TRAC Warning: declare_field() is deprecated, please use define_field()", file=sys.stderr)
343
+
321
344
  return define_field(
322
345
  field_name, field_type, label,
323
346
  business_key, categorical, not_null,
@@ -343,9 +366,9 @@ def F( # noqa
343
366
  :type label: str
344
367
  :type business_key: bool
345
368
  :type categorical: bool
346
- :type not_null: _tp.Optional[bool]
347
- :type format_code: _tp.Optional[str]
348
- :type field_order: _tp.Optional[int]
369
+ :type not_null: Optional[bool]
370
+ :type format_code: Optional[str]
371
+ :type field_order: Optional[int]
349
372
  :rtype: :py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`
350
373
  """
351
374
 
@@ -429,7 +452,8 @@ def load_schema(
429
452
  def define_input_table(
430
453
  *fields: _tp.Union[FieldSchema, _tp.List[FieldSchema]],
431
454
  label: _tp.Optional[str] = None,
432
- optional: bool = False) \
455
+ optional: bool = False,
456
+ input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
433
457
  -> ModelInputSchema:
434
458
 
435
459
  """
@@ -438,20 +462,26 @@ def define_input_table(
438
462
  Fields can be supplied either as individual arguments to this function or as a list.
439
463
  Individual fields should be defined using :py:func:`define_field` or the shorthand alias :py:func:`F`.
440
464
 
465
+ You can use input_props to associate arbitrary key-value properties with this model input.
466
+ These properties are not used by the TRAC engine, but are stored in the model metadata for
467
+ the input and can be used as needed in 3rd-party applications.
468
+
441
469
  :param fields: A set of fields to make up a :py:class:`TableSchema <tracdap.rt.metadata.TableSchema>`
442
470
  :param label: An optional label (of type str) for a model input schema. Default value: None.
443
471
  :param optional: Mark this input as an optional model input
472
+ :param input_props: Associate key-value properties with this input (not used by the TRAC engine)
444
473
  :return: A model input schema, suitable for returning from :py:meth:`TracModel.define_inputs`
445
474
 
446
475
  :type fields: :py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>` |
447
476
  List[:py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`]
448
- :type label: _tp.Optional[str]
477
+ :type label: Optional[str]
449
478
  :type optional: bool
479
+ :type input_props: Optional[Dict[str, Any]]
450
480
  :rtype: :py:class:`ModelInputSchema <tracdap.rt.metadata.ModelInputSchema>`
451
481
  """
452
482
 
453
483
  sa = _StaticApiHook.get_instance()
454
- return sa.define_input_table(*fields, label=label, optional=optional)
484
+ return sa.define_input_table(*fields, label=label, optional=optional, input_props=input_props)
455
485
 
456
486
 
457
487
  def declare_input_table(
@@ -462,18 +492,24 @@ def declare_input_table(
462
492
  .. deprecated:: 0.4.4
463
493
  Use :py:func:`define_input_table` instead.
464
494
 
495
+ This function is deprecated and will be removed in a future version.
496
+ Please use :py:func:`define_input_table() <tracdap.rt.api.define_input_table>` instead.
497
+
465
498
  :type fields: :py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>` |
466
499
  List[:py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`]
467
500
  :rtype: :py:class:`ModelInputSchema <tracdap.rt.metadata.ModelInputSchema>`
468
501
  """
469
502
 
503
+ print("TRAC Warning: declare_input_table() is deprecated, please use define_input_table()", file=sys.stderr)
504
+
470
505
  return define_input_table(*fields)
471
506
 
472
507
 
473
508
  def define_output_table(
474
509
  *fields: _tp.Union[FieldSchema, _tp.List[FieldSchema]],
475
510
  label: _tp.Optional[str] = None,
476
- optional: bool = False) \
511
+ optional: bool = False,
512
+ output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
477
513
  -> ModelOutputSchema:
478
514
 
479
515
  """
@@ -482,20 +518,26 @@ def define_output_table(
482
518
  Fields can be supplied either as individual arguments to this function or as a list.
483
519
  Individual fields should be defined using :py:func:`define_field` or the shorthand alias :py:func:`F`.
484
520
 
521
+ You can use output_props to associate arbitrary key-value properties with this model output.
522
+ These properties are not used by the TRAC engine, but are stored in the model metadata for
523
+ the output and can be used as needed in 3rd-party applications.
524
+
485
525
  :param fields: A set of fields to make up a :py:class:`TableSchema <tracdap.rt.metadata.TableSchema>`
486
526
  :param label: An optional label (of type str) for a model output schema. Default value: None.
487
527
  :param optional: Mark this output as an optional model output
528
+ :param output_props: Associate key-value properties with this output (not used by the TRAC engine)
488
529
  :return: A model output schema, suitable for returning from :py:meth:`TracModel.define_outputs`
489
530
 
490
531
  :type fields: :py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>` |
491
532
  List[:py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`]
492
- :type label: _tp.Optional[str]
533
+ :type label: Optional[str]
493
534
  :type optional: bool
535
+ :type output_props: Optional[Dict[str, Any]]
494
536
  :rtype: :py:class:`ModelOutputSchema <tracdap.rt.metadata.ModelOutputSchema>`
495
537
  """
496
538
 
497
539
  sa = _StaticApiHook.get_instance()
498
- return sa.define_output_table(*fields, label=label, optional=optional)
540
+ return sa.define_output_table(*fields, label=label, optional=optional, output_props=output_props)
499
541
 
500
542
 
501
543
  def declare_output_table(
@@ -506,9 +548,17 @@ def declare_output_table(
506
548
  .. deprecated:: 0.4.4
507
549
  Use :py:func:`define_output_table` instead.
508
550
 
551
+ This function is deprecated and will be removed in a future version.
552
+ Please use :py:func:`define_output_table() <tracdap.rt.api.define_output_table>` instead.
553
+
554
+ This function is deprecated and will be removed in a future version.
555
+ Please use define_output_table() instead.
556
+
509
557
  :type fields: :py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>` |
510
558
  List[:py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`]
511
559
  :rtype: :py:class:`ModelOutputSchema <tracdap.rt.metadata.ModelOutputSchema>`
512
560
  """
513
561
 
562
+ print("TRAC Warning: declare_output_table() is deprecated, please use define_output_table()", file==sys.stderr)
563
+
514
564
  return define_output_table(*fields)
@@ -5,13 +5,11 @@ from .common import PluginConfig
5
5
  from .common import PlatformInfo
6
6
  from .common import AuthenticationConfig
7
7
  from .common import StorageConfig
8
+ from .common import ServiceConfig
8
9
 
9
10
  from .runtime import RuntimeConfig
10
11
  from .runtime import SparkSettings
11
12
 
12
- from .result import TagUpdateList
13
- from .result import JobResult
14
-
15
13
  from .platform import RoutingProtocol
16
14
  from .platform import DeploymentLayout
17
15
  from .platform import PlatformConfig
@@ -24,7 +22,9 @@ from .platform import GatewayConfig
24
22
  from .platform import RouteConfig
25
23
  from .platform import RoutingMatch
26
24
  from .platform import RoutingTarget
27
- from .platform import ServiceConfig
28
25
  from .platform import DeploymentConfig
29
26
 
30
27
  from .job import JobConfig
28
+
29
+ from .result import TagUpdateList
30
+ from .result import JobResult
@@ -66,3 +66,13 @@ class StorageConfig:
66
66
  defaultBucket: str = None
67
67
 
68
68
  defaultFormat: str = None
69
+
70
+
71
+ @_dc.dataclass
72
+ class ServiceConfig:
73
+
74
+ enabled: _tp.Optional[bool] = None
75
+
76
+ alias: str = None
77
+
78
+ port: int = None
@@ -153,16 +153,6 @@ class RoutingTarget:
153
153
  path: str = None
154
154
 
155
155
 
156
- @_dc.dataclass
157
- class ServiceConfig:
158
-
159
- enabled: _tp.Optional[bool] = None
160
-
161
- alias: str = None
162
-
163
- port: int = None
164
-
165
-
166
156
  @_dc.dataclass
167
157
  class DeploymentConfig:
168
158
 
@@ -20,6 +20,8 @@ class RuntimeConfig:
20
20
 
21
21
  sparkSettings: SparkSettings = None
22
22
 
23
+ runtimeApi: ServiceConfig = None
24
+
23
25
 
24
26
  @_dc.dataclass
25
27
  class SparkSettings:
@@ -0,0 +1,34 @@
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 abc as _abc
16
+
17
+
18
+ class IConfigLoader:
19
+
20
+ @_abc.abstractmethod
21
+ def has_config_file(self, config_url: str) -> bool:
22
+ pass
23
+
24
+ @_abc.abstractmethod
25
+ def load_config_file(self, config_url: str) -> bytes:
26
+ pass
27
+
28
+ @_abc.abstractmethod
29
+ def has_config_dict(self, config_url: str) -> bool:
30
+ pass
31
+
32
+ @_abc.abstractmethod
33
+ def load_config_dict(self, config_url: str) -> dict:
34
+ pass
tracdap/rt/ext/embed.py CHANGED
@@ -13,9 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import tracdap.rt.config as _cfg
16
- import tracdap.rt.ext._guard as _guard
17
-
18
- # Dependency back into the main runtime implementation
16
+ import tracdap.rt._impl.guard_rails as _guard # noqa
19
17
  import tracdap.rt._exec.runtime as _rt # noqa
20
18
 
21
19
 
tracdap/rt/ext/plugins.py CHANGED
@@ -19,7 +19,8 @@ import importlib as _il
19
19
 
20
20
  import tracdap.rt.config as _cfg
21
21
  import tracdap.rt.exceptions as _ex
22
- import tracdap.rt.ext._guard as _guard
22
+ import tracdap.rt._impl.guard_rails as _guard # noqa
23
+ from tracdap.rt.exceptions import EStartup
23
24
 
24
25
 
25
26
  class PluginManager:
@@ -29,6 +30,8 @@ class PluginManager:
29
30
  __log = _log.getLogger(f"{__name__}.PluginManager")
30
31
 
31
32
  __core_registered = False
33
+ __3rd_party_registered = list()
34
+
32
35
  __plugins = {}
33
36
 
34
37
  @classmethod
@@ -40,17 +43,42 @@ class PluginManager:
40
43
  return
41
44
 
42
45
  cls.__log.info("Register core plugins...")
46
+ cls.__register_plugin_package("tracdap.rt._plugins")
47
+
48
+ cls.__core_registered = True
49
+
50
+ @classmethod
51
+ def register_plugin_package(cls, plugin_package_name: str):
52
+
53
+ _guard.run_model_guard()
43
54
 
44
- plugins_package = _il.import_module("tracdap.rt._plugins")
55
+ if plugin_package_name in cls.__3rd_party_registered:
56
+ return
57
+
58
+ if plugin_package_name.startswith("tracdap."):
59
+ raise EStartup("3rd party plugins cannot be registered from the tracdap namespace")
60
+
61
+ cls.__log.info(f"Register plugins from package [{plugin_package_name}]...")
62
+ cls.__register_plugin_package(plugin_package_name)
63
+
64
+ cls.__3rd_party_registered.append(plugin_package_name)
65
+
66
+ @classmethod
67
+ def __register_plugin_package(cls, plugin_package_name: str):
68
+
69
+ _guard.run_model_guard()
70
+
71
+ plugins_package = _il.import_module(plugin_package_name)
45
72
 
46
73
  for module in _pkg.iter_modules(plugins_package.__path__):
74
+
75
+ module_name = f"{plugin_package_name}.{module.name}"
76
+
47
77
  try:
48
- module_name = f"tracdap.rt._plugins.{module.name}"
49
78
  _il.import_module(module_name)
50
79
  except ImportError:
51
- pass # Ignore plugins that fail to load
52
-
53
- cls.__core_registered = True
80
+ # It is not a fatal error if some plugins fail to load
81
+ cls.__log.warning(f"Failed to load plugins from module [{module_name}]")
54
82
 
55
83
  @classmethod
56
84
  def register_plugin(
@@ -94,3 +122,16 @@ class PluginManager:
94
122
  plugin = plugin_class(config.properties)
95
123
 
96
124
  return plugin
125
+
126
+ @classmethod
127
+ def load_config_plugin(cls,
128
+ service_type: _tp.Type[T_SERVICE],
129
+ config: _cfg.PluginConfig) \
130
+ -> T_SERVICE:
131
+
132
+ # Currently config plugins are loaded the same way as regular plugins
133
+ # However, regular plugins can be modified to take ConfigManager as an init parameter
134
+ # This is useful for loading secondary config files needed in particularly plugins
135
+ # Config plugins can never do this, because the config manager is not yet initialized
136
+
137
+ return cls.load_plugin(service_type, config)