tracdap-runtime 0.6.3__py3-none-any.whl → 0.6.5__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 (52) hide show
  1. tracdap/rt/_exec/context.py +572 -112
  2. tracdap/rt/_exec/dev_mode.py +166 -97
  3. tracdap/rt/_exec/engine.py +120 -9
  4. tracdap/rt/_exec/functions.py +137 -35
  5. tracdap/rt/_exec/graph.py +38 -13
  6. tracdap/rt/_exec/graph_builder.py +120 -9
  7. tracdap/rt/_impl/data.py +183 -52
  8. tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.py +18 -18
  9. tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.py +74 -30
  10. tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.pyi +120 -2
  11. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.py +20 -18
  12. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.pyi +22 -6
  13. tracdap/rt/_impl/grpc/tracdap/metadata/resource_pb2.py +29 -0
  14. tracdap/rt/_impl/grpc/tracdap/metadata/resource_pb2.pyi +16 -0
  15. tracdap/rt/_impl/models.py +8 -0
  16. tracdap/rt/_impl/static_api.py +42 -10
  17. tracdap/rt/_impl/storage.py +37 -25
  18. tracdap/rt/_impl/validation.py +113 -11
  19. tracdap/rt/_plugins/repo_git.py +1 -1
  20. tracdap/rt/_version.py +1 -1
  21. tracdap/rt/api/experimental.py +220 -0
  22. tracdap/rt/api/hook.py +6 -4
  23. tracdap/rt/api/model_api.py +98 -13
  24. tracdap/rt/api/static_api.py +14 -6
  25. tracdap/rt/config/__init__.py +2 -2
  26. tracdap/rt/config/common.py +23 -17
  27. tracdap/rt/config/job.py +2 -2
  28. tracdap/rt/config/platform.py +25 -25
  29. tracdap/rt/config/result.py +2 -2
  30. tracdap/rt/config/runtime.py +3 -3
  31. tracdap/rt/launch/cli.py +7 -4
  32. tracdap/rt/launch/launch.py +19 -3
  33. tracdap/rt/metadata/__init__.py +25 -20
  34. tracdap/rt/metadata/common.py +2 -2
  35. tracdap/rt/metadata/custom.py +3 -3
  36. tracdap/rt/metadata/data.py +12 -12
  37. tracdap/rt/metadata/file.py +6 -6
  38. tracdap/rt/metadata/flow.py +6 -6
  39. tracdap/rt/metadata/job.py +62 -8
  40. tracdap/rt/metadata/model.py +33 -11
  41. tracdap/rt/metadata/object_id.py +8 -8
  42. tracdap/rt/metadata/resource.py +24 -0
  43. tracdap/rt/metadata/search.py +5 -5
  44. tracdap/rt/metadata/stoarge.py +6 -6
  45. tracdap/rt/metadata/tag.py +1 -1
  46. tracdap/rt/metadata/tag_update.py +1 -1
  47. tracdap/rt/metadata/type.py +4 -4
  48. {tracdap_runtime-0.6.3.dist-info → tracdap_runtime-0.6.5.dist-info}/METADATA +3 -1
  49. {tracdap_runtime-0.6.3.dist-info → tracdap_runtime-0.6.5.dist-info}/RECORD +52 -48
  50. {tracdap_runtime-0.6.3.dist-info → tracdap_runtime-0.6.5.dist-info}/LICENSE +0 -0
  51. {tracdap_runtime-0.6.3.dist-info → tracdap_runtime-0.6.5.dist-info}/WHEEL +0 -0
  52. {tracdap_runtime-0.6.3.dist-info → tracdap_runtime-0.6.5.dist-info}/top_level.txt +0 -0
@@ -12,8 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from __future__ import annotations
16
-
17
15
  import abc as _abc
18
16
  import typing as _tp
19
17
  import logging as _logging
@@ -22,8 +20,18 @@ import logging as _logging
22
20
  # This significantly improves type hinting, inline documentation and auto-complete in JetBrains IDEs
23
21
  from tracdap.rt.metadata import * # DOCGEN_REMOVE
24
22
 
23
+
25
24
  if _tp.TYPE_CHECKING:
26
- import pandas
25
+
26
+ try:
27
+ import pandas
28
+ except ModuleNotFoundError:
29
+ pass
30
+
31
+ try:
32
+ import polars
33
+ except ModuleNotFoundError:
34
+ pass
27
35
 
28
36
 
29
37
  class TracContext:
@@ -100,13 +108,26 @@ class TracContext:
100
108
  """
101
109
  Get the schema of a model input or output
102
110
 
103
- The schema of an input or output can be retrieved and examined at runtime using this method.
104
- Inputs must be defined in :py:meth:`TracModel.define_inputs`
105
- and outputs in :py:meth:`TracModel.define_outputs`.
106
- Input and output names are case-sensitive.
107
-
108
- In the current version of the runtime all model inputs and outputs are defined statically,
109
- :py:meth:`get_schema` will return the schema as it was defined.
111
+ Use this method to get the :py:class:`SchemaDefinition <tracdap.rt.metadata.SchemaDefinition>`
112
+ for any input or output of the current model.
113
+ For datasets with static schemas, this will be the same schema that was defined in the
114
+ :py:class:`TracModel <tracdap.rt.api.TracModel>` methods
115
+ :py:meth:`define_inputs() <tracdap.rt.api.TracModel.define_inputs>` and
116
+ :py:meth:`define_outputs() <tracdap.rt.api.TracModel.define_outputs>`.
117
+
118
+ For inputs with dynamic schemas, the schema of the provided input dataset will be returned.
119
+ For outputs with dynamic schemas the schema must be set by calling
120
+ :py:meth:`put_schema() <tracdap.rt.api.TracContext.put_schema>`, after which this method
121
+ will return that schema. Calling :py:meth:`get_schema() <tracdap.rt.api.TracContext.get_schema>`
122
+ for a dynamic output before the schema is set will result in a runtime validation error.
123
+
124
+ For optional inputs, use :py:meth:`has_dataset() <tracdap.rt.api.TracContext.has_dataset>`
125
+ to check whether the input was provided. Calling :py:meth:`get_schema() <tracdap.rt.api.TracContext.get_schema>`
126
+ for an optional input that was not provided will always result in a validation error,
127
+ regardless of whether the input using a static or dynamic schema. For optional outputs
128
+ :py:meth:`get_schema() <tracdap.rt.api.TracContext.get_schema>` can be called, with the
129
+ normal proviso that dynamic schemas must first be set by calling
130
+ :py:meth:`put_schema() <tracdap.rt.api.TracContext.put_schema>`.
110
131
 
111
132
  Attempting to retrieve the schema for a dataset that is not defined as a model input or output
112
133
  will result in a runtime validation error, even if that dataset exists in the job config and
@@ -121,7 +142,8 @@ class TracContext:
121
142
  pass
122
143
 
123
144
  @_abc.abstractmethod
124
- def get_pandas_table(self, dataset_name: str, use_temporal_objects: _tp.Optional[bool] = None) -> pandas.DataFrame:
145
+ def get_pandas_table(self, dataset_name: str, use_temporal_objects: _tp.Optional[bool] = None) \
146
+ -> "pandas.DataFrame":
125
147
 
126
148
  """
127
149
  Get the data for a model input or output as a Pandas dataframe
@@ -153,7 +175,53 @@ class TracContext:
153
175
  pass
154
176
 
155
177
  @_abc.abstractmethod
156
- def put_pandas_table(self, dataset_name: str, dataset: pandas.DataFrame):
178
+ def get_polars_table(self, dataset_name: str) -> "polars.DataFrame":
179
+
180
+ """
181
+ Get the data for a model input or output as a Polars dataframe
182
+
183
+ This method has equivalent semantics to :py:meth:`get_pandas_table`, but returns
184
+ a Polars dataframe.
185
+
186
+ :param dataset_name: The name of the model input or output to get data for
187
+ :return: A polars dataframe containing the data for the named dataset
188
+ :raises: :py:class:`ERuntimeValidation <tracdap.rt.exceptions.ERuntimeValidation>`
189
+ """
190
+
191
+ pass
192
+
193
+ @_abc.abstractmethod
194
+ def put_schema(self, dataset_name: str, schema: SchemaDefinition):
195
+
196
+ """
197
+ Set the schema of a dynamic model output
198
+
199
+ For outputs marked as dynamic, a :py:class:`SchemaDefinition <tracdap.rt.metadata.SchemaDefinition>`
200
+ must be supplied before attempting to save the data. TRAC API functions are available to help with
201
+ building schemas, such as :py:func:`trac.F() <tracdap.rt.api.F>` to define fields or
202
+ :py:func:`load_schema() <tracdap.rt.api.load_schema>` to load predefined schemas.
203
+ Once a schema has been set, it can be retrieved by calling
204
+ :py:meth:`get_schema() <tracdap.rt.api.TracContext.get_schema>` as normal.
205
+ If :py:meth:`put_schema() <tracdap.rt.api.TracContext.put_schema>` is called for an optional
206
+ output the model must also supply data for that output, otherwise TRAC will report a runtime
207
+ validation error after the model completes.
208
+
209
+ Each schema can only be set once and the schema will be validated using the normal
210
+ validation rules. If validation fails this method will raise
211
+ :py:class:`ERuntimeValidation <tracdap.rt.exceptions.ERuntimeValidation>`.
212
+ Attempting to set the schema for a dataset that is not defined as a dynamic model output
213
+ for the current model will result in a runtime validation error.
214
+
215
+ :param dataset_name: The name of the output to set the schema for
216
+ :param schema: A TRAC schema definition to use for the named output
217
+ :type schema: :py:class:`SchemaDefinition <tracdap.rt.metadata.SchemaDefinition>`
218
+ :raises: :py:class:`ERuntimeValidation <tracdap.rt.exceptions.ERuntimeValidation>`
219
+ """
220
+
221
+ pass
222
+
223
+ @_abc.abstractmethod
224
+ def put_pandas_table(self, dataset_name: str, dataset: "pandas.DataFrame"):
157
225
 
158
226
  """
159
227
  Save the data for a model output as a Pandas dataframe
@@ -174,7 +242,24 @@ class TracContext:
174
242
  :param dataset_name: The name of the model output to save data for
175
243
  :param dataset: A pandas dataframe containing the data for the named dataset
176
244
  :raises: :py:class:`ERuntimeValidation <tracdap.rt.exceptions.ERuntimeValidation>`,
177
- :py:class:`EDataValidation <tracdap.rt.exceptions.EDataValidation>`
245
+ :py:class:`EDataConformance <tracdap.rt.exceptions.EDataConformance>`
246
+ """
247
+
248
+ pass
249
+
250
+ @_abc.abstractmethod
251
+ def put_polars_table(self, dataset_name: str, dataset: "polars.DataFrame"):
252
+
253
+ """
254
+ Save the data for a model output as a Polars dataframe
255
+
256
+ This method has equivalent semantics to :py:meth:`put_pandas_table`, but accepts
257
+ a Polars dataframe.
258
+
259
+ :param dataset_name: The name of the model output to save data for
260
+ :param dataset: A polars dataframe containing the data for the named dataset
261
+ :raises: :py:class:`ERuntimeValidation <tracdap.rt.exceptions.ERuntimeValidation>`,
262
+ :py:class:`EDataConformance <tracdap.rt.exceptions.EDataConformance>`
178
263
  """
179
264
 
180
265
  pass
@@ -451,8 +451,7 @@ def load_schema(
451
451
 
452
452
  def define_input_table(
453
453
  *fields: _tp.Union[FieldSchema, _tp.List[FieldSchema]],
454
- label: _tp.Optional[str] = None,
455
- optional: bool = False,
454
+ label: _tp.Optional[str] = None, optional: bool = False, dynamic: bool = False,
456
455
  input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
457
456
  -> ModelInputSchema:
458
457
 
@@ -469,6 +468,7 @@ def define_input_table(
469
468
  :param fields: A set of fields to make up a :py:class:`TableSchema <tracdap.rt.metadata.TableSchema>`
470
469
  :param label: An optional label (of type str) for a model input schema. Default value: None.
471
470
  :param optional: Mark this input as an optional model input
471
+ :param dynamic: Mark this input as a dynamic model input (the list of fields must be empty)
472
472
  :param input_props: Associate key-value properties with this input (not used by the TRAC engine)
473
473
  :return: A model input schema, suitable for returning from :py:meth:`TracModel.define_inputs`
474
474
 
@@ -476,12 +476,16 @@ def define_input_table(
476
476
  List[:py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`]
477
477
  :type label: Optional[str]
478
478
  :type optional: bool
479
+ :type dynamic: bool
479
480
  :type input_props: Optional[Dict[str, Any]]
480
481
  :rtype: :py:class:`ModelInputSchema <tracdap.rt.metadata.ModelInputSchema>`
481
482
  """
482
483
 
483
484
  sa = _StaticApiHook.get_instance()
484
- return sa.define_input_table(*fields, label=label, optional=optional, input_props=input_props)
485
+
486
+ return sa.define_input_table(
487
+ *fields, label=label, optional=optional, dynamic=dynamic,
488
+ input_props=input_props)
485
489
 
486
490
 
487
491
  def declare_input_table(
@@ -507,8 +511,7 @@ def declare_input_table(
507
511
 
508
512
  def define_output_table(
509
513
  *fields: _tp.Union[FieldSchema, _tp.List[FieldSchema]],
510
- label: _tp.Optional[str] = None,
511
- optional: bool = False,
514
+ label: _tp.Optional[str] = None, optional: bool = False, dynamic: bool = False,
512
515
  output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
513
516
  -> ModelOutputSchema:
514
517
 
@@ -525,6 +528,7 @@ def define_output_table(
525
528
  :param fields: A set of fields to make up a :py:class:`TableSchema <tracdap.rt.metadata.TableSchema>`
526
529
  :param label: An optional label (of type str) for a model output schema. Default value: None.
527
530
  :param optional: Mark this output as an optional model output
531
+ :param dynamic: Mark this output as a dynamic model output (the list of fields must be empty)
528
532
  :param output_props: Associate key-value properties with this output (not used by the TRAC engine)
529
533
  :return: A model output schema, suitable for returning from :py:meth:`TracModel.define_outputs`
530
534
 
@@ -532,12 +536,16 @@ def define_output_table(
532
536
  List[:py:class:`FieldSchema <tracdap.rt.metadata.FieldSchema>`]
533
537
  :type label: Optional[str]
534
538
  :type optional: bool
539
+ :type dynamic: bool
535
540
  :type output_props: Optional[Dict[str, Any]]
536
541
  :rtype: :py:class:`ModelOutputSchema <tracdap.rt.metadata.ModelOutputSchema>`
537
542
  """
538
543
 
539
544
  sa = _StaticApiHook.get_instance()
540
- return sa.define_output_table(*fields, label=label, optional=optional, output_props=output_props)
545
+
546
+ return sa.define_output_table(
547
+ *fields, label=label, optional=optional, dynamic=dynamic,
548
+ output_props=output_props)
541
549
 
542
550
 
543
551
  def declare_output_table(
@@ -10,6 +10,8 @@ from .common import ServiceConfig
10
10
  from .runtime import RuntimeConfig
11
11
  from .runtime import SparkSettings
12
12
 
13
+ from .job import JobConfig
14
+
13
15
  from .platform import RoutingProtocol
14
16
  from .platform import DeploymentLayout
15
17
  from .platform import PlatformConfig
@@ -24,7 +26,5 @@ from .platform import RoutingMatch
24
26
  from .platform import RoutingTarget
25
27
  from .platform import DeploymentConfig
26
28
 
27
- from .job import JobConfig
28
-
29
29
  from .result import TagUpdateList
30
30
  from .result import JobResult
@@ -15,7 +15,9 @@ class _ConfigFile:
15
15
  @_dc.dataclass
16
16
  class PluginConfig:
17
17
 
18
- protocol: str = None
18
+ protocol: str = ""
19
+
20
+ publicProperties: _tp.Dict[str, str] = _dc.field(default_factory=dict)
19
21
 
20
22
  properties: _tp.Dict[str, str] = _dc.field(default_factory=dict)
21
23
 
@@ -25,9 +27,9 @@ class PluginConfig:
25
27
  @_dc.dataclass
26
28
  class PlatformInfo:
27
29
 
28
- environment: str = None
30
+ environment: str = ""
29
31
 
30
- production: bool = None
32
+ production: bool = False
31
33
 
32
34
  deploymentInfo: _tp.Dict[str, str] = _dc.field(default_factory=dict)
33
35
 
@@ -35,27 +37,27 @@ class PlatformInfo:
35
37
  @_dc.dataclass
36
38
  class AuthenticationConfig:
37
39
 
38
- jwtIssuer: str = None
40
+ jwtIssuer: str = ""
39
41
 
40
- jwtExpiry: int = None
42
+ jwtExpiry: int = 0
41
43
 
42
- jwtLimit: int = None
44
+ jwtLimit: int = 0
43
45
 
44
- jwtRefresh: int = None
46
+ jwtRefresh: int = 0
45
47
 
46
48
  provider: _tp.Optional[PluginConfig] = None
47
49
 
48
- disableAuth: bool = None
50
+ disableAuth: bool = False
49
51
 
50
- disableSigning: bool = None
52
+ disableSigning: bool = False
51
53
 
52
- systemUserId: str = None
54
+ systemUserId: str = ""
53
55
 
54
- systemUserName: str = None
56
+ systemUserName: str = ""
55
57
 
56
- systemTicketDuration: int = None
58
+ systemTicketDuration: int = 0
57
59
 
58
- systemTicketRefresh: int = None
60
+ systemTicketRefresh: int = 0
59
61
 
60
62
 
61
63
  @_dc.dataclass
@@ -63,9 +65,13 @@ class StorageConfig:
63
65
 
64
66
  buckets: _tp.Dict[str, PluginConfig] = _dc.field(default_factory=dict)
65
67
 
66
- defaultBucket: str = None
68
+ """TODO: Rename "buckets" as "internal" for 0.7"""
69
+
70
+ external: _tp.Dict[str, PluginConfig] = _dc.field(default_factory=dict)
71
+
72
+ defaultBucket: str = ""
67
73
 
68
- defaultFormat: str = None
74
+ defaultFormat: str = ""
69
75
 
70
76
 
71
77
  @_dc.dataclass
@@ -73,6 +79,6 @@ class ServiceConfig:
73
79
 
74
80
  enabled: _tp.Optional[bool] = None
75
81
 
76
- alias: str = None
82
+ alias: str = ""
77
83
 
78
- port: int = None
84
+ port: int = 0
tracdap/rt/config/job.py CHANGED
@@ -12,9 +12,9 @@ import tracdap.rt.metadata as metadata
12
12
  @_dc.dataclass
13
13
  class JobConfig:
14
14
 
15
- jobId: metadata.TagHeader = None
15
+ jobId: metadata.TagHeader = _dc.field(default_factory=lambda: metadata.TagHeader())
16
16
 
17
- job: metadata.JobDefinition = None
17
+ job: metadata.JobDefinition = _dc.field(default_factory=lambda: metadata.JobDefinition())
18
18
 
19
19
  resources: _tp.Dict[str, metadata.ObjectDefinition] = _dc.field(default_factory=dict)
20
20
 
@@ -38,19 +38,19 @@ class PlatformConfig:
38
38
 
39
39
  config: _tp.Dict[str, str] = _dc.field(default_factory=dict)
40
40
 
41
- platformInfo: PlatformInfo = None
41
+ platformInfo: PlatformInfo = _dc.field(default_factory=lambda: PlatformInfo())
42
42
 
43
- authentication: AuthenticationConfig = None
43
+ authentication: AuthenticationConfig = _dc.field(default_factory=lambda: AuthenticationConfig())
44
44
 
45
- metadata: MetadataConfig = None
45
+ metadata: MetadataConfig = _dc.field(default_factory=lambda: MetadataConfig())
46
46
 
47
- storage: StorageConfig = None
47
+ storage: StorageConfig = _dc.field(default_factory=lambda: StorageConfig())
48
48
 
49
49
  repositories: _tp.Dict[str, PluginConfig] = _dc.field(default_factory=dict)
50
50
 
51
- executor: PluginConfig = None
51
+ executor: PluginConfig = _dc.field(default_factory=lambda: PluginConfig())
52
52
 
53
- jobCache: PluginConfig = None
53
+ jobCache: PluginConfig = _dc.field(default_factory=lambda: PluginConfig())
54
54
 
55
55
  tenants: _tp.Dict[str, TenantConfig] = _dc.field(default_factory=dict)
56
56
 
@@ -60,13 +60,13 @@ class PlatformConfig:
60
60
 
61
61
  services: _tp.Dict[str, ServiceConfig] = _dc.field(default_factory=dict)
62
62
 
63
- deployment: DeploymentConfig = None
63
+ deployment: DeploymentConfig = _dc.field(default_factory=lambda: DeploymentConfig())
64
64
 
65
65
 
66
66
  @_dc.dataclass
67
67
  class MetadataConfig:
68
68
 
69
- database: PluginConfig = None
69
+ database: PluginConfig = _dc.field(default_factory=lambda: PluginConfig())
70
70
 
71
71
  format: metadata.MetadataFormat = metadata.MetadataFormat.METADATA_FORMAT_NOT_SET
72
72
 
@@ -82,9 +82,9 @@ class TenantConfig:
82
82
  @_dc.dataclass
83
83
  class WebServerConfig:
84
84
 
85
- enabled: bool = None
85
+ enabled: bool = False
86
86
 
87
- contentRoot: PluginConfig = None
87
+ contentRoot: PluginConfig = _dc.field(default_factory=lambda: PluginConfig())
88
88
 
89
89
  rewriteRules: _tp.List[WebServerRewriteRule] = _dc.field(default_factory=list)
90
90
 
@@ -94,25 +94,25 @@ class WebServerConfig:
94
94
  @_dc.dataclass
95
95
  class WebServerRewriteRule:
96
96
 
97
- source: str = None
97
+ source: str = ""
98
98
 
99
- target: str = None
99
+ target: str = ""
100
100
 
101
101
 
102
102
  @_dc.dataclass
103
103
  class WebServerRedirect:
104
104
 
105
- source: str = None
105
+ source: str = ""
106
106
 
107
- target: str = None
107
+ target: str = ""
108
108
 
109
- status: int = None
109
+ status: int = 0
110
110
 
111
111
 
112
112
  @_dc.dataclass
113
113
  class GatewayConfig:
114
114
 
115
- idleTimeout: int = None
115
+ idleTimeout: int = 0
116
116
 
117
117
  routes: _tp.List[RouteConfig] = _dc.field(default_factory=list)
118
118
 
@@ -122,35 +122,35 @@ class GatewayConfig:
122
122
  @_dc.dataclass
123
123
  class RouteConfig:
124
124
 
125
- routeName: str = None
125
+ routeName: str = ""
126
126
 
127
127
  routeType: RoutingProtocol = RoutingProtocol.PROTOCOL_NOT_SET
128
128
 
129
129
  protocols: _tp.List[RoutingProtocol] = _dc.field(default_factory=list)
130
130
 
131
- match: RoutingMatch = None
131
+ match: RoutingMatch = _dc.field(default_factory=lambda: RoutingMatch())
132
132
 
133
- target: RoutingTarget = None
133
+ target: RoutingTarget = _dc.field(default_factory=lambda: RoutingTarget())
134
134
 
135
135
 
136
136
  @_dc.dataclass
137
137
  class RoutingMatch:
138
138
 
139
- host: str = None
139
+ host: str = ""
140
140
 
141
- path: str = None
141
+ path: str = ""
142
142
 
143
143
 
144
144
  @_dc.dataclass
145
145
  class RoutingTarget:
146
146
 
147
- scheme: str = None
147
+ scheme: str = ""
148
148
 
149
- host: str = None
149
+ host: str = ""
150
150
 
151
- port: int = None
151
+ port: int = 0
152
152
 
153
- path: str = None
153
+ path: str = ""
154
154
 
155
155
 
156
156
  @_dc.dataclass
@@ -18,10 +18,10 @@ class TagUpdateList:
18
18
  @_dc.dataclass
19
19
  class JobResult:
20
20
 
21
- jobId: metadata.TagHeader = None
21
+ jobId: metadata.TagHeader = _dc.field(default_factory=lambda: metadata.TagHeader())
22
22
 
23
23
  statusCode: metadata.JobStatusCode = metadata.JobStatusCode.JOB_STATUS_CODE_NOT_SET
24
24
 
25
- statusMessage: str = None
25
+ statusMessage: str = ""
26
26
 
27
27
  results: _tp.Dict[str, metadata.ObjectDefinition] = _dc.field(default_factory=dict)
@@ -14,13 +14,13 @@ class RuntimeConfig:
14
14
 
15
15
  config: _tp.Dict[str, str] = _dc.field(default_factory=dict)
16
16
 
17
- storage: StorageConfig = None
17
+ storage: StorageConfig = _dc.field(default_factory=lambda: StorageConfig())
18
18
 
19
19
  repositories: _tp.Dict[str, PluginConfig] = _dc.field(default_factory=dict)
20
20
 
21
- sparkSettings: SparkSettings = None
21
+ sparkSettings: SparkSettings = _dc.field(default_factory=lambda: SparkSettings())
22
22
 
23
- runtimeApi: ServiceConfig = None
23
+ runtimeApi: ServiceConfig = _dc.field(default_factory=lambda: ServiceConfig())
24
24
 
25
25
 
26
26
  @_dc.dataclass
tracdap/rt/launch/cli.py CHANGED
@@ -16,18 +16,18 @@ import argparse
16
16
  import pathlib
17
17
 
18
18
 
19
- def _cli_args():
19
+ def _cli_args(programmatic_args = None):
20
20
 
21
21
  parser = argparse.ArgumentParser(
22
22
  prog="python -m tracdap.rt.launch",
23
23
  description="TRAC D.A.P. Runtime for Python")
24
24
 
25
25
  parser.add_argument(
26
- "--sys-config", dest="sys_config", type=pathlib.Path, required=True,
26
+ "--sys-config", dest="sys_config", type=str, required=True,
27
27
  help="Path to the system configuration file for the TRAC runtime")
28
28
 
29
29
  parser.add_argument(
30
- "--job-config", dest="job_config", type=pathlib.Path, required=True,
30
+ "--job-config", dest="job_config", type=str, required=True,
31
31
  help="Path to the job configuration for the job to be executed")
32
32
 
33
33
  parser.add_argument(
@@ -55,4 +55,7 @@ def _cli_args():
55
55
  "--plugin-package", dest="plugin_packages", type=str, action="append",
56
56
  help="Do not clean up the scratch location on exit")
57
57
 
58
- return parser.parse_args()
58
+ if programmatic_args:
59
+ return parser.parse_args(programmatic_args)
60
+ else:
61
+ return parser.parse_args()
@@ -29,7 +29,15 @@ from .cli import _cli_args
29
29
  def _resolve_config_file(
30
30
  config_path: _tp.Union[str, _pathlib.Path],
31
31
  model_dir: _tp.Optional[_pathlib.Path] = None) \
32
- -> _pathlib.Path:
32
+ -> _tp.Union[_pathlib.Path, str]:
33
+
34
+ # If the config path is a URL, do not convert it into a path
35
+ if isinstance(config_path, str):
36
+ scheme_sep = config_path.find(":")
37
+ # Single letter scheme is a Windows file path (C:\...)
38
+ scheme = scheme = config_path[:scheme_sep] if scheme_sep > 1 else "file"
39
+ if scheme != "file":
40
+ return config_path
33
41
 
34
42
  if _pathlib.Path(config_path).is_absolute():
35
43
  return config_path
@@ -136,13 +144,21 @@ def launch_job(
136
144
  rt.wait_for_job(job.jobId)
137
145
 
138
146
 
139
- def launch_cli():
147
+ def launch_cli(programmatic_args: _tp.Optional[_tp.List[str]] = None):
140
148
 
141
149
  """
142
150
  Launch the TRAC runtime using the command line interface
151
+
152
+ CLI arguments are read from the process command line by default. To pass CLI args
153
+ explicitly, provide the list of arguments using the programmatic_args parameter.
154
+
155
+ :param programmatic_args: Optional parameter to pass CLI args explicitly in code
143
156
  """
144
157
 
145
- launch_args = _cli_args()
158
+ if programmatic_args:
159
+ launch_args = _cli_args(programmatic_args)
160
+ else:
161
+ launch_args = _cli_args()
146
162
 
147
163
  _sys_config = _resolve_config_file(launch_args.sys_config, None)
148
164
 
@@ -21,30 +21,12 @@ from .data import SchemaDefinition
21
21
  from .data import PartKey
22
22
  from .data import DataDefinition
23
23
 
24
- from .stoarge import CopyStatus
25
- from .stoarge import IncarnationStatus
26
- from .stoarge import StorageCopy
27
- from .stoarge import StorageIncarnation
28
- from .stoarge import StorageItem
29
- from .stoarge import StorageDefinition
30
-
24
+ from .model import ModelType
31
25
  from .model import ModelParameter
32
26
  from .model import ModelInputSchema
33
27
  from .model import ModelOutputSchema
34
28
  from .model import ModelDefinition
35
29
 
36
- from .tag_update import TagOperation
37
- from .tag_update import TagUpdate
38
-
39
- from .job import JobType
40
- from .job import JobStatusCode
41
- from .job import JobDefinition
42
- from .job import RunModelJob
43
- from .job import RunFlowJob
44
- from .job import ImportModelJob
45
-
46
- from .file import FileDefinition
47
-
48
30
  from .search import SearchOperator
49
31
  from .search import LogicalOperator
50
32
  from .search import SearchTerm
@@ -52,18 +34,41 @@ from .search import LogicalExpression
52
34
  from .search import SearchExpression
53
35
  from .search import SearchParameters
54
36
 
37
+ from .tag_update import TagOperation
38
+ from .tag_update import TagUpdate
39
+
55
40
  from .flow import FlowNodeType
56
41
  from .flow import FlowNode
57
42
  from .flow import FlowSocket
58
43
  from .flow import FlowEdge
59
44
  from .flow import FlowDefinition
60
45
 
46
+ from .job import JobType
47
+ from .job import JobStatusCode
48
+ from .job import JobDefinition
49
+ from .job import RunModelJob
50
+ from .job import RunFlowJob
51
+ from .job import ImportModelJob
52
+ from .job import ImportDataJob
53
+ from .job import ExportDataJob
54
+
55
+ from .file import FileDefinition
56
+
61
57
  from .custom import CustomDefinition
62
58
 
59
+ from .stoarge import CopyStatus
60
+ from .stoarge import IncarnationStatus
61
+ from .stoarge import StorageCopy
62
+ from .stoarge import StorageIncarnation
63
+ from .stoarge import StorageItem
64
+ from .stoarge import StorageDefinition
65
+
63
66
  from .object import ObjectDefinition
64
67
 
65
- from .tag import Tag
68
+ from .resource import ResourceType
66
69
 
67
70
  from .common import MetadataFormat
68
71
  from .common import MetadataVersion
69
72
  from .common import TenantInfo
73
+
74
+ from .tag import Tag
@@ -49,10 +49,10 @@ class TenantInfo:
49
49
 
50
50
  """Information about a tenant that is set up on the TRAC platform."""
51
51
 
52
- tenantCode: str = None
52
+ tenantCode: str = ""
53
53
 
54
54
  """* Unique code used to identify the tenant, required by most API calls."""
55
55
 
56
- description: str = None
56
+ description: str = ""
57
57
 
58
58
  """* A short description of the tenant, suitable for displaying to users in lists."""
@@ -11,8 +11,8 @@ class CustomDefinition:
11
11
 
12
12
  """Define a custom object that can be stored and managed in the TRAC metadata store"""
13
13
 
14
- customSchemaType: str = None
14
+ customSchemaType: str = ""
15
15
 
16
- customSchemaVersion: int = None
16
+ customSchemaVersion: int = 0
17
17
 
18
- customData: bytes = None
18
+ customData: bytes = b""