tracdap-runtime 0.7.0__py3-none-any.whl → 0.8.0b1__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 (34) hide show
  1. tracdap/rt/_exec/context.py +140 -64
  2. tracdap/rt/_exec/dev_mode.py +144 -69
  3. tracdap/rt/_exec/engine.py +9 -7
  4. tracdap/rt/_exec/functions.py +95 -33
  5. tracdap/rt/_exec/graph.py +22 -15
  6. tracdap/rt/_exec/graph_builder.py +221 -98
  7. tracdap/rt/_exec/runtime.py +19 -6
  8. tracdap/rt/_impl/data.py +86 -13
  9. tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.py +3 -1
  10. tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.pyi +8 -0
  11. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.py +27 -25
  12. tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.pyi +14 -4
  13. tracdap/rt/_impl/models.py +9 -7
  14. tracdap/rt/_impl/static_api.py +53 -33
  15. tracdap/rt/_impl/util.py +1 -1
  16. tracdap/rt/_impl/validation.py +54 -28
  17. tracdap/rt/_version.py +1 -1
  18. tracdap/rt/api/__init__.py +6 -3
  19. tracdap/rt/api/file_types.py +29 -0
  20. tracdap/rt/api/hook.py +15 -7
  21. tracdap/rt/api/model_api.py +16 -0
  22. tracdap/rt/api/static_api.py +211 -125
  23. tracdap/rt/config/__init__.py +6 -6
  24. tracdap/rt/config/common.py +11 -1
  25. tracdap/rt/config/platform.py +4 -6
  26. tracdap/rt/launch/launch.py +9 -11
  27. tracdap/rt/metadata/__init__.py +10 -9
  28. tracdap/rt/metadata/file.py +8 -0
  29. tracdap/rt/metadata/model.py +12 -2
  30. {tracdap_runtime-0.7.0.dist-info → tracdap_runtime-0.8.0b1.dist-info}/METADATA +15 -15
  31. {tracdap_runtime-0.7.0.dist-info → tracdap_runtime-0.8.0b1.dist-info}/RECORD +34 -33
  32. {tracdap_runtime-0.7.0.dist-info → tracdap_runtime-0.8.0b1.dist-info}/WHEEL +1 -1
  33. {tracdap_runtime-0.7.0.dist-info → tracdap_runtime-0.8.0b1.dist-info}/LICENSE +0 -0
  34. {tracdap_runtime-0.7.0.dist-info → tracdap_runtime-0.8.0b1.dist-info}/top_level.txt +0 -0
tracdap/rt/_impl/data.py CHANGED
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
 
16
16
  import abc
17
+ import copy
17
18
  import dataclasses as dc
18
19
  import typing as tp
19
20
  import datetime as dt
@@ -42,11 +43,48 @@ import tracdap.rt._impl.util as _util
42
43
  @dc.dataclass(frozen=True)
43
44
  class DataSpec:
44
45
 
46
+ object_type: _meta.ObjectType
45
47
  data_item: str
48
+
46
49
  data_def: _meta.DataDefinition
50
+ file_def: _meta.FileDefinition
47
51
  storage_def: _meta.StorageDefinition
48
52
  schema_def: tp.Optional[_meta.SchemaDefinition]
49
53
 
54
+ @staticmethod
55
+ def create_data_spec(
56
+ data_item: str,
57
+ data_def: _meta.DataDefinition,
58
+ storage_def: _meta.StorageDefinition,
59
+ schema_def: tp.Optional[_meta.SchemaDefinition] = None) -> "DataSpec":
60
+
61
+ return DataSpec(
62
+ _meta.ObjectType.DATA, data_item,
63
+ data_def,
64
+ storage_def=storage_def,
65
+ schema_def=schema_def,
66
+ file_def=None)
67
+
68
+ @staticmethod
69
+ def create_file_spec(
70
+ data_item: str,
71
+ file_def: _meta.FileDefinition,
72
+ storage_def: _meta.StorageDefinition) -> "DataSpec":
73
+
74
+ return DataSpec(
75
+ _meta.ObjectType.FILE, data_item,
76
+ file_def=file_def,
77
+ storage_def=storage_def,
78
+ data_def=None,
79
+ schema_def=None)
80
+
81
+ @staticmethod
82
+ def create_empty_spec(object_type: _meta.ObjectType):
83
+ return DataSpec(object_type, None, None, None, None, None)
84
+
85
+ def is_empty(self):
86
+ return self.data_item is None or len(self.data_item) == 0
87
+
50
88
 
51
89
  @dc.dataclass(frozen=True)
52
90
  class DataPartKey:
@@ -61,44 +99,79 @@ class DataPartKey:
61
99
  @dc.dataclass(frozen=True)
62
100
  class DataItem:
63
101
 
64
- schema: pa.Schema
102
+ object_type: _meta.ObjectType
103
+
104
+ schema: pa.Schema = None
65
105
  table: tp.Optional[pa.Table] = None
66
106
  batches: tp.Optional[tp.List[pa.RecordBatch]] = None
67
107
 
68
108
  pandas: "tp.Optional[pandas.DataFrame]" = None
69
109
  pyspark: tp.Any = None
70
110
 
111
+ raw_bytes: bytes = None
112
+
71
113
  def is_empty(self) -> bool:
72
- return self.table is None and (self.batches is None or len(self.batches) == 0)
114
+ if self.object_type == _meta.ObjectType.FILE:
115
+ return self.raw_bytes is None or len(self.raw_bytes) == 0
116
+ else:
117
+ return self.table is None and (self.batches is None or len(self.batches) == 0)
73
118
 
74
119
  @staticmethod
75
- def create_empty() -> "DataItem":
76
- return DataItem(pa.schema([]))
120
+ def create_empty(object_type: _meta.ObjectType = _meta.ObjectType.DATA) -> "DataItem":
121
+ if object_type == _meta.ObjectType.DATA:
122
+ return DataItem(_meta.ObjectType.DATA, pa.schema([]))
123
+ else:
124
+ return DataItem(object_type)
125
+
126
+ @staticmethod
127
+ def for_file_content(raw_bytes: bytes):
128
+ return DataItem(_meta.ObjectType.FILE, raw_bytes=raw_bytes)
77
129
 
78
130
 
79
131
  @dc.dataclass(frozen=True)
80
132
  class DataView:
81
133
 
82
- trac_schema: _meta.SchemaDefinition
83
- arrow_schema: pa.Schema
134
+ object_type: _meta.ObjectType
84
135
 
85
- parts: tp.Dict[DataPartKey, tp.List[DataItem]]
136
+ trac_schema: _meta.SchemaDefinition = None
137
+ arrow_schema: pa.Schema = None
138
+
139
+ parts: tp.Dict[DataPartKey, tp.List[DataItem]] = None
140
+ file_item: tp.Optional[DataItem] = None
86
141
 
87
142
  @staticmethod
88
- def create_empty() -> "DataView":
89
- return DataView(_meta.SchemaDefinition(), pa.schema([]), dict())
143
+ def create_empty(object_type: _meta.ObjectType = _meta.ObjectType.DATA) -> "DataView":
144
+ if object_type == _meta.ObjectType.DATA:
145
+ return DataView(object_type, _meta.SchemaDefinition(), pa.schema([]), dict())
146
+ else:
147
+ return DataView(object_type)
90
148
 
91
149
  @staticmethod
92
150
  def for_trac_schema(trac_schema: _meta.SchemaDefinition):
93
151
  arrow_schema = DataMapping.trac_to_arrow_schema(trac_schema)
94
- return DataView(trac_schema, arrow_schema, dict())
152
+ return DataView(_meta.ObjectType.DATA, trac_schema, arrow_schema, dict())
153
+
154
+ @staticmethod
155
+ def for_file_item(file_item: DataItem):
156
+ return DataView(file_item.object_type, file_item=file_item)
95
157
 
96
158
  def with_trac_schema(self, trac_schema: _meta.SchemaDefinition):
97
159
  arrow_schema = DataMapping.trac_to_arrow_schema(trac_schema)
98
- return DataView(trac_schema, arrow_schema, self.parts)
160
+ return DataView(_meta.ObjectType.DATA, trac_schema, arrow_schema, self.parts)
161
+
162
+ def with_part(self, part_key: DataPartKey, part: DataItem):
163
+ new_parts = copy.copy(self.parts)
164
+ new_parts[part_key] = [part]
165
+ return DataView(self.object_type, self.trac_schema, self.arrow_schema, new_parts)
166
+
167
+ def with_file_item(self, file_item: DataItem):
168
+ return DataView(self.object_type, file_item=file_item)
99
169
 
100
170
  def is_empty(self) -> bool:
101
- return self.parts is None or not any(self.parts.values())
171
+ if self.object_type == _meta.ObjectType.FILE:
172
+ return self.file_item is None
173
+ else:
174
+ return self.parts is None or not any(self.parts.values())
102
175
 
103
176
 
104
177
  class _DataInternal:
@@ -293,7 +366,7 @@ class DataMapping:
293
366
  deltas = [*prior_deltas, item]
294
367
  parts = {**view.parts, part: deltas}
295
368
 
296
- return DataView(view.trac_schema, view.arrow_schema, parts)
369
+ return DataView(view.object_type, view.trac_schema, view.arrow_schema, parts=parts)
297
370
 
298
371
  @classmethod
299
372
  def view_to_arrow(cls, view: DataView, part: DataPartKey) -> pa.Table:
@@ -15,7 +15,7 @@ _sym_db = _symbol_database.Default()
15
15
  from tracdap.rt._impl.grpc.tracdap.metadata import object_id_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_object__id__pb2
16
16
 
17
17
 
18
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n1tracdap/rt/_impl/grpc/tracdap/metadata/file.proto\x12\x10tracdap.metadata\x1a\x36tracdap/rt/_impl/grpc/tracdap/metadata/object_id.proto\"\x95\x01\n\x0e\x46ileDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\textension\x18\x02 \x01(\t\x12\x10\n\x08mimeType\x18\x03 \x01(\t\x12\x0c\n\x04size\x18\x04 \x01(\x04\x12\x30\n\tstorageId\x18\x05 \x01(\x0b\x32\x1d.tracdap.metadata.TagSelector\x12\x10\n\x08\x64\x61taItem\x18\x06 \x01(\tB\x1e\n\x1aorg.finos.tracdap.metadataP\x01\x62\x06proto3')
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n1tracdap/rt/_impl/grpc/tracdap/metadata/file.proto\x12\x10tracdap.metadata\x1a\x36tracdap/rt/_impl/grpc/tracdap/metadata/object_id.proto\"\x95\x01\n\x0e\x46ileDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\textension\x18\x02 \x01(\t\x12\x10\n\x08mimeType\x18\x03 \x01(\t\x12\x0c\n\x04size\x18\x04 \x01(\x04\x12\x30\n\tstorageId\x18\x05 \x01(\x0b\x32\x1d.tracdap.metadata.TagSelector\x12\x10\n\x08\x64\x61taItem\x18\x06 \x01(\t\"/\n\x08\x46ileType\x12\x11\n\textension\x18\x01 \x01(\t\x12\x10\n\x08mimeType\x18\x02 \x01(\tB\x1e\n\x1aorg.finos.tracdap.metadataP\x01\x62\x06proto3')
19
19
 
20
20
  _globals = globals()
21
21
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -25,4 +25,6 @@ if _descriptor._USE_C_DESCRIPTORS == False:
25
25
  _globals['DESCRIPTOR']._serialized_options = b'\n\032org.finos.tracdap.metadataP\001'
26
26
  _globals['_FILEDEFINITION']._serialized_start=128
27
27
  _globals['_FILEDEFINITION']._serialized_end=277
28
+ _globals['_FILETYPE']._serialized_start=279
29
+ _globals['_FILETYPE']._serialized_end=326
28
30
  # @@protoc_insertion_point(module_scope)
@@ -20,3 +20,11 @@ class FileDefinition(_message.Message):
20
20
  storageId: _object_id_pb2.TagSelector
21
21
  dataItem: str
22
22
  def __init__(self, name: _Optional[str] = ..., extension: _Optional[str] = ..., mimeType: _Optional[str] = ..., size: _Optional[int] = ..., storageId: _Optional[_Union[_object_id_pb2.TagSelector, _Mapping]] = ..., dataItem: _Optional[str] = ...) -> None: ...
23
+
24
+ class FileType(_message.Message):
25
+ __slots__ = ("extension", "mimeType")
26
+ EXTENSION_FIELD_NUMBER: _ClassVar[int]
27
+ MIMETYPE_FIELD_NUMBER: _ClassVar[int]
28
+ extension: str
29
+ mimeType: str
30
+ def __init__(self, extension: _Optional[str] = ..., mimeType: _Optional[str] = ...) -> None: ...
@@ -13,10 +13,12 @@ _sym_db = _symbol_database.Default()
13
13
 
14
14
 
15
15
  from tracdap.rt._impl.grpc.tracdap.metadata import type_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_type__pb2
16
+ from tracdap.rt._impl.grpc.tracdap.metadata import object_id_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_object__id__pb2
16
17
  from tracdap.rt._impl.grpc.tracdap.metadata import data_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_data__pb2
18
+ from tracdap.rt._impl.grpc.tracdap.metadata import file_pb2 as tracdap_dot_rt_dot___impl_dot_grpc_dot_tracdap_dot_metadata_dot_file__pb2
17
19
 
18
20
 
19
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n2tracdap/rt/_impl/grpc/tracdap/metadata/model.proto\x12\x10tracdap.metadata\x1a\x31tracdap/rt/_impl/grpc/tracdap/metadata/type.proto\x1a\x31tracdap/rt/_impl/grpc/tracdap/metadata/data.proto\"\xab\x02\n\x0eModelParameter\x12\x33\n\tparamType\x18\x01 \x01(\x0b\x32 .tracdap.metadata.TypeDescriptor\x12\r\n\x05label\x18\x02 \x01(\t\x12\x32\n\x0c\x64\x65\x66\x61ultValue\x18\x03 \x01(\x0b\x32\x17.tracdap.metadata.ValueH\x00\x88\x01\x01\x12\x44\n\nparamProps\x18\x04 \x03(\x0b\x32\x30.tracdap.metadata.ModelParameter.ParamPropsEntry\x1aJ\n\x0fParamPropsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\x0f\n\r_defaultValue\"\x9b\x02\n\x10ModelInputSchema\x12\x32\n\x06schema\x18\x01 \x01(\x0b\x32\".tracdap.metadata.SchemaDefinition\x12\x12\n\x05label\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x10\n\x08optional\x18\x03 \x01(\x08\x12\x0f\n\x07\x64ynamic\x18\x05 \x01(\x08\x12\x46\n\ninputProps\x18\x04 \x03(\x0b\x32\x32.tracdap.metadata.ModelInputSchema.InputPropsEntry\x1aJ\n\x0fInputPropsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\x08\n\x06_label\"\xa0\x02\n\x11ModelOutputSchema\x12\x32\n\x06schema\x18\x01 \x01(\x0b\x32\".tracdap.metadata.SchemaDefinition\x12\x12\n\x05label\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x10\n\x08optional\x18\x03 \x01(\x08\x12\x0f\n\x07\x64ynamic\x18\x05 \x01(\x08\x12I\n\x0boutputProps\x18\x04 \x03(\x0b\x32\x34.tracdap.metadata.ModelOutputSchema.OutputPropsEntry\x1aK\n\x10OutputPropsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\x08\n\x06_label\"\xce\x06\n\x0fModelDefinition\x12\x10\n\x08language\x18\x01 \x01(\t\x12\x12\n\nrepository\x18\x02 \x01(\t\x12\x19\n\x0cpackageGroup\x18\n \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07package\x18\x0b \x01(\t\x12\x0f\n\x07version\x18\x06 \x01(\t\x12\x12\n\nentryPoint\x18\x05 \x01(\t\x12\x11\n\x04path\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x45\n\nparameters\x18\x07 \x03(\x0b\x32\x31.tracdap.metadata.ModelDefinition.ParametersEntry\x12=\n\x06inputs\x18\x08 \x03(\x0b\x32-.tracdap.metadata.ModelDefinition.InputsEntry\x12?\n\x07outputs\x18\t \x03(\x0b\x32..tracdap.metadata.ModelDefinition.OutputsEntry\x12Q\n\x10staticAttributes\x18\x0c \x03(\x0b\x32\x37.tracdap.metadata.ModelDefinition.StaticAttributesEntry\x12.\n\tmodelType\x18\r \x01(\x0e\x32\x1b.tracdap.metadata.ModelType\x1aS\n\x0fParametersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .tracdap.metadata.ModelParameter:\x02\x38\x01\x1aQ\n\x0bInputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x31\n\x05value\x18\x02 \x01(\x0b\x32\".tracdap.metadata.ModelInputSchema:\x02\x38\x01\x1aS\n\x0cOutputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.tracdap.metadata.ModelOutputSchema:\x02\x38\x01\x1aP\n\x15StaticAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\x0f\n\r_packageGroupB\x07\n\x05_path*M\n\tModelType\x12\x12\n\x0eSTANDARD_MODEL\x10\x00\x12\x15\n\x11\x44\x41TA_IMPORT_MODEL\x10\x01\x12\x15\n\x11\x44\x41TA_EXPORT_MODEL\x10\x02\x42\x1e\n\x1aorg.finos.tracdap.metadataP\x01\x62\x06proto3')
21
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n2tracdap/rt/_impl/grpc/tracdap/metadata/model.proto\x12\x10tracdap.metadata\x1a\x31tracdap/rt/_impl/grpc/tracdap/metadata/type.proto\x1a\x36tracdap/rt/_impl/grpc/tracdap/metadata/object_id.proto\x1a\x31tracdap/rt/_impl/grpc/tracdap/metadata/data.proto\x1a\x31tracdap/rt/_impl/grpc/tracdap/metadata/file.proto\"\xab\x02\n\x0eModelParameter\x12\x33\n\tparamType\x18\x01 \x01(\x0b\x32 .tracdap.metadata.TypeDescriptor\x12\r\n\x05label\x18\x02 \x01(\t\x12\x32\n\x0c\x64\x65\x66\x61ultValue\x18\x03 \x01(\x0b\x32\x17.tracdap.metadata.ValueH\x00\x88\x01\x01\x12\x44\n\nparamProps\x18\x04 \x03(\x0b\x32\x30.tracdap.metadata.ModelParameter.ParamPropsEntry\x1aJ\n\x0fParamPropsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\x0f\n\r_defaultValue\"\x8e\x03\n\x10ModelInputSchema\x12\x30\n\nobjectType\x18\x06 \x01(\x0e\x32\x1c.tracdap.metadata.ObjectType\x12\x34\n\x06schema\x18\x01 \x01(\x0b\x32\".tracdap.metadata.SchemaDefinitionH\x00\x12.\n\x08\x66ileType\x18\x07 \x01(\x0b\x32\x1a.tracdap.metadata.FileTypeH\x00\x12\x12\n\x05label\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x10\n\x08optional\x18\x03 \x01(\x08\x12\x0f\n\x07\x64ynamic\x18\x05 \x01(\x08\x12\x46\n\ninputProps\x18\x04 \x03(\x0b\x32\x32.tracdap.metadata.ModelInputSchema.InputPropsEntry\x1aJ\n\x0fInputPropsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\r\n\x0brequirementB\x08\n\x06_label\"\x93\x03\n\x11ModelOutputSchema\x12\x30\n\nobjectType\x18\x06 \x01(\x0e\x32\x1c.tracdap.metadata.ObjectType\x12\x34\n\x06schema\x18\x01 \x01(\x0b\x32\".tracdap.metadata.SchemaDefinitionH\x00\x12.\n\x08\x66ileType\x18\x07 \x01(\x0b\x32\x1a.tracdap.metadata.FileTypeH\x00\x12\x12\n\x05label\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x10\n\x08optional\x18\x03 \x01(\x08\x12\x0f\n\x07\x64ynamic\x18\x05 \x01(\x08\x12I\n\x0boutputProps\x18\x04 \x03(\x0b\x32\x34.tracdap.metadata.ModelOutputSchema.OutputPropsEntry\x1aK\n\x10OutputPropsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\r\n\x0brequirementB\x08\n\x06_label\"\xce\x06\n\x0fModelDefinition\x12\x10\n\x08language\x18\x01 \x01(\t\x12\x12\n\nrepository\x18\x02 \x01(\t\x12\x19\n\x0cpackageGroup\x18\n \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07package\x18\x0b \x01(\t\x12\x0f\n\x07version\x18\x06 \x01(\t\x12\x12\n\nentryPoint\x18\x05 \x01(\t\x12\x11\n\x04path\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x45\n\nparameters\x18\x07 \x03(\x0b\x32\x31.tracdap.metadata.ModelDefinition.ParametersEntry\x12=\n\x06inputs\x18\x08 \x03(\x0b\x32-.tracdap.metadata.ModelDefinition.InputsEntry\x12?\n\x07outputs\x18\t \x03(\x0b\x32..tracdap.metadata.ModelDefinition.OutputsEntry\x12Q\n\x10staticAttributes\x18\x0c \x03(\x0b\x32\x37.tracdap.metadata.ModelDefinition.StaticAttributesEntry\x12.\n\tmodelType\x18\r \x01(\x0e\x32\x1b.tracdap.metadata.ModelType\x1aS\n\x0fParametersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .tracdap.metadata.ModelParameter:\x02\x38\x01\x1aQ\n\x0bInputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x31\n\x05value\x18\x02 \x01(\x0b\x32\".tracdap.metadata.ModelInputSchema:\x02\x38\x01\x1aS\n\x0cOutputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.tracdap.metadata.ModelOutputSchema:\x02\x38\x01\x1aP\n\x15StaticAttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.tracdap.metadata.Value:\x02\x38\x01\x42\x0f\n\r_packageGroupB\x07\n\x05_path*M\n\tModelType\x12\x12\n\x0eSTANDARD_MODEL\x10\x00\x12\x15\n\x11\x44\x41TA_IMPORT_MODEL\x10\x01\x12\x15\n\x11\x44\x41TA_EXPORT_MODEL\x10\x02\x42\x1e\n\x1aorg.finos.tracdap.metadataP\x01\x62\x06proto3')
20
22
 
21
23
  _globals = globals()
22
24
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -38,28 +40,28 @@ if _descriptor._USE_C_DESCRIPTORS == False:
38
40
  _globals['_MODELDEFINITION_OUTPUTSENTRY']._serialized_options = b'8\001'
39
41
  _globals['_MODELDEFINITION_STATICATTRIBUTESENTRY']._options = None
40
42
  _globals['_MODELDEFINITION_STATICATTRIBUTESENTRY']._serialized_options = b'8\001'
41
- _globals['_MODELTYPE']._serialized_start=1902
42
- _globals['_MODELTYPE']._serialized_end=1979
43
- _globals['_MODELPARAMETER']._serialized_start=175
44
- _globals['_MODELPARAMETER']._serialized_end=474
45
- _globals['_MODELPARAMETER_PARAMPROPSENTRY']._serialized_start=383
46
- _globals['_MODELPARAMETER_PARAMPROPSENTRY']._serialized_end=457
47
- _globals['_MODELINPUTSCHEMA']._serialized_start=477
48
- _globals['_MODELINPUTSCHEMA']._serialized_end=760
49
- _globals['_MODELINPUTSCHEMA_INPUTPROPSENTRY']._serialized_start=676
50
- _globals['_MODELINPUTSCHEMA_INPUTPROPSENTRY']._serialized_end=750
51
- _globals['_MODELOUTPUTSCHEMA']._serialized_start=763
52
- _globals['_MODELOUTPUTSCHEMA']._serialized_end=1051
53
- _globals['_MODELOUTPUTSCHEMA_OUTPUTPROPSENTRY']._serialized_start=966
54
- _globals['_MODELOUTPUTSCHEMA_OUTPUTPROPSENTRY']._serialized_end=1041
55
- _globals['_MODELDEFINITION']._serialized_start=1054
56
- _globals['_MODELDEFINITION']._serialized_end=1900
57
- _globals['_MODELDEFINITION_PARAMETERSENTRY']._serialized_start=1541
58
- _globals['_MODELDEFINITION_PARAMETERSENTRY']._serialized_end=1624
59
- _globals['_MODELDEFINITION_INPUTSENTRY']._serialized_start=1626
60
- _globals['_MODELDEFINITION_INPUTSENTRY']._serialized_end=1707
61
- _globals['_MODELDEFINITION_OUTPUTSENTRY']._serialized_start=1709
62
- _globals['_MODELDEFINITION_OUTPUTSENTRY']._serialized_end=1792
63
- _globals['_MODELDEFINITION_STATICATTRIBUTESENTRY']._serialized_start=1794
64
- _globals['_MODELDEFINITION_STATICATTRIBUTESENTRY']._serialized_end=1874
43
+ _globals['_MODELTYPE']._serialized_start=2239
44
+ _globals['_MODELTYPE']._serialized_end=2316
45
+ _globals['_MODELPARAMETER']._serialized_start=282
46
+ _globals['_MODELPARAMETER']._serialized_end=581
47
+ _globals['_MODELPARAMETER_PARAMPROPSENTRY']._serialized_start=490
48
+ _globals['_MODELPARAMETER_PARAMPROPSENTRY']._serialized_end=564
49
+ _globals['_MODELINPUTSCHEMA']._serialized_start=584
50
+ _globals['_MODELINPUTSCHEMA']._serialized_end=982
51
+ _globals['_MODELINPUTSCHEMA_INPUTPROPSENTRY']._serialized_start=883
52
+ _globals['_MODELINPUTSCHEMA_INPUTPROPSENTRY']._serialized_end=957
53
+ _globals['_MODELOUTPUTSCHEMA']._serialized_start=985
54
+ _globals['_MODELOUTPUTSCHEMA']._serialized_end=1388
55
+ _globals['_MODELOUTPUTSCHEMA_OUTPUTPROPSENTRY']._serialized_start=1288
56
+ _globals['_MODELOUTPUTSCHEMA_OUTPUTPROPSENTRY']._serialized_end=1363
57
+ _globals['_MODELDEFINITION']._serialized_start=1391
58
+ _globals['_MODELDEFINITION']._serialized_end=2237
59
+ _globals['_MODELDEFINITION_PARAMETERSENTRY']._serialized_start=1878
60
+ _globals['_MODELDEFINITION_PARAMETERSENTRY']._serialized_end=1961
61
+ _globals['_MODELDEFINITION_INPUTSENTRY']._serialized_start=1963
62
+ _globals['_MODELDEFINITION_INPUTSENTRY']._serialized_end=2044
63
+ _globals['_MODELDEFINITION_OUTPUTSENTRY']._serialized_start=2046
64
+ _globals['_MODELDEFINITION_OUTPUTSENTRY']._serialized_end=2129
65
+ _globals['_MODELDEFINITION_STATICATTRIBUTESENTRY']._serialized_start=2131
66
+ _globals['_MODELDEFINITION_STATICATTRIBUTESENTRY']._serialized_end=2211
65
67
  # @@protoc_insertion_point(module_scope)
@@ -1,5 +1,7 @@
1
1
  from tracdap.rt._impl.grpc.tracdap.metadata import type_pb2 as _type_pb2
2
+ from tracdap.rt._impl.grpc.tracdap.metadata import object_id_pb2 as _object_id_pb2
2
3
  from tracdap.rt._impl.grpc.tracdap.metadata import data_pb2 as _data_pb2
4
+ from tracdap.rt._impl.grpc.tracdap.metadata import file_pb2 as _file_pb2
3
5
  from google.protobuf.internal import containers as _containers
4
6
  from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
5
7
  from google.protobuf import descriptor as _descriptor
@@ -37,7 +39,7 @@ class ModelParameter(_message.Message):
37
39
  def __init__(self, paramType: _Optional[_Union[_type_pb2.TypeDescriptor, _Mapping]] = ..., label: _Optional[str] = ..., defaultValue: _Optional[_Union[_type_pb2.Value, _Mapping]] = ..., paramProps: _Optional[_Mapping[str, _type_pb2.Value]] = ...) -> None: ...
38
40
 
39
41
  class ModelInputSchema(_message.Message):
40
- __slots__ = ("schema", "label", "optional", "dynamic", "inputProps")
42
+ __slots__ = ("objectType", "schema", "fileType", "label", "optional", "dynamic", "inputProps")
41
43
  class InputPropsEntry(_message.Message):
42
44
  __slots__ = ("key", "value")
43
45
  KEY_FIELD_NUMBER: _ClassVar[int]
@@ -45,20 +47,24 @@ class ModelInputSchema(_message.Message):
45
47
  key: str
46
48
  value: _type_pb2.Value
47
49
  def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[_type_pb2.Value, _Mapping]] = ...) -> None: ...
50
+ OBJECTTYPE_FIELD_NUMBER: _ClassVar[int]
48
51
  SCHEMA_FIELD_NUMBER: _ClassVar[int]
52
+ FILETYPE_FIELD_NUMBER: _ClassVar[int]
49
53
  LABEL_FIELD_NUMBER: _ClassVar[int]
50
54
  OPTIONAL_FIELD_NUMBER: _ClassVar[int]
51
55
  DYNAMIC_FIELD_NUMBER: _ClassVar[int]
52
56
  INPUTPROPS_FIELD_NUMBER: _ClassVar[int]
57
+ objectType: _object_id_pb2.ObjectType
53
58
  schema: _data_pb2.SchemaDefinition
59
+ fileType: _file_pb2.FileType
54
60
  label: str
55
61
  optional: bool
56
62
  dynamic: bool
57
63
  inputProps: _containers.MessageMap[str, _type_pb2.Value]
58
- def __init__(self, schema: _Optional[_Union[_data_pb2.SchemaDefinition, _Mapping]] = ..., label: _Optional[str] = ..., optional: bool = ..., dynamic: bool = ..., inputProps: _Optional[_Mapping[str, _type_pb2.Value]] = ...) -> None: ...
64
+ def __init__(self, objectType: _Optional[_Union[_object_id_pb2.ObjectType, str]] = ..., schema: _Optional[_Union[_data_pb2.SchemaDefinition, _Mapping]] = ..., fileType: _Optional[_Union[_file_pb2.FileType, _Mapping]] = ..., label: _Optional[str] = ..., optional: bool = ..., dynamic: bool = ..., inputProps: _Optional[_Mapping[str, _type_pb2.Value]] = ...) -> None: ...
59
65
 
60
66
  class ModelOutputSchema(_message.Message):
61
- __slots__ = ("schema", "label", "optional", "dynamic", "outputProps")
67
+ __slots__ = ("objectType", "schema", "fileType", "label", "optional", "dynamic", "outputProps")
62
68
  class OutputPropsEntry(_message.Message):
63
69
  __slots__ = ("key", "value")
64
70
  KEY_FIELD_NUMBER: _ClassVar[int]
@@ -66,17 +72,21 @@ class ModelOutputSchema(_message.Message):
66
72
  key: str
67
73
  value: _type_pb2.Value
68
74
  def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[_type_pb2.Value, _Mapping]] = ...) -> None: ...
75
+ OBJECTTYPE_FIELD_NUMBER: _ClassVar[int]
69
76
  SCHEMA_FIELD_NUMBER: _ClassVar[int]
77
+ FILETYPE_FIELD_NUMBER: _ClassVar[int]
70
78
  LABEL_FIELD_NUMBER: _ClassVar[int]
71
79
  OPTIONAL_FIELD_NUMBER: _ClassVar[int]
72
80
  DYNAMIC_FIELD_NUMBER: _ClassVar[int]
73
81
  OUTPUTPROPS_FIELD_NUMBER: _ClassVar[int]
82
+ objectType: _object_id_pb2.ObjectType
74
83
  schema: _data_pb2.SchemaDefinition
84
+ fileType: _file_pb2.FileType
75
85
  label: str
76
86
  optional: bool
77
87
  dynamic: bool
78
88
  outputProps: _containers.MessageMap[str, _type_pb2.Value]
79
- def __init__(self, schema: _Optional[_Union[_data_pb2.SchemaDefinition, _Mapping]] = ..., label: _Optional[str] = ..., optional: bool = ..., dynamic: bool = ..., outputProps: _Optional[_Mapping[str, _type_pb2.Value]] = ...) -> None: ...
89
+ def __init__(self, objectType: _Optional[_Union[_object_id_pb2.ObjectType, str]] = ..., schema: _Optional[_Union[_data_pb2.SchemaDefinition, _Mapping]] = ..., fileType: _Optional[_Union[_file_pb2.FileType, _Mapping]] = ..., label: _Optional[str] = ..., optional: bool = ..., dynamic: bool = ..., outputProps: _Optional[_Mapping[str, _type_pb2.Value]] = ...) -> None: ...
80
90
 
81
91
  class ModelDefinition(_message.Message):
82
92
  __slots__ = ("language", "repository", "packageGroup", "package", "version", "entryPoint", "path", "parameters", "inputs", "outputs", "staticAttributes", "modelType")
@@ -226,13 +226,15 @@ class ModelLoader:
226
226
  self.__log.info(f"Parameter [{name}] - {param.paramType.basicType.name}")
227
227
  param.paramProps = self._encoded_props(param.paramProps, "parameter", name)
228
228
 
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)
232
-
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)
229
+ for name, input_def in model_def.inputs.items():
230
+ input_type = input_def.schema.schemaType.name if input_def.objectType == _meta.ObjectType.DATA else input_def.objectType.name
231
+ self.__log.info(f"Input [{name}] - {input_type}")
232
+ input_def.inputProps = self._encoded_props(input_def.inputProps, "input", name)
233
+
234
+ for name, output_def in model_def.outputs.items():
235
+ output_type = output_def.schema.schemaType.name if output_def.objectType == _meta.ObjectType.DATA else output_def.objectType.name
236
+ self.__log.info(f"Output [{name}] - {output_type}")
237
+ output_def.outputProps = self._encoded_props(output_def.outputProps, "input", name)
236
238
 
237
239
  return model_def
238
240
 
@@ -152,14 +152,18 @@ class StaticApiImpl(_StaticApiHook):
152
152
 
153
153
  def define_schema(
154
154
  self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
155
- schema_type: _meta.SchemaType = _meta.SchemaType.TABLE) \
155
+ schema_type: _meta.SchemaType = _meta.SchemaType.TABLE, dynamic: bool = False) \
156
156
  -> _meta.SchemaDefinition:
157
157
 
158
- _val.validate_signature(self.define_schema, *fields, schema_type=schema_type)
158
+ _val.validate_signature(self.define_schema, *fields, schema_type=schema_type, dynamic=dynamic)
159
159
 
160
160
  if schema_type == _meta.SchemaType.TABLE:
161
161
 
162
- table_schema = self._build_table_schema(*fields)
162
+ if dynamic and not fields:
163
+ table_schema = None
164
+ else:
165
+ table_schema = self._build_table_schema(*fields)
166
+
163
167
  return _meta.SchemaDefinition(_meta.SchemaType.TABLE, table=table_schema)
164
168
 
165
169
  raise _ex.ERuntimeValidation(f"Invalid schema type [{schema_type.name}]")
@@ -182,51 +186,67 @@ class StaticApiImpl(_StaticApiHook):
182
186
 
183
187
  return converter.infer_schema(dataset)
184
188
 
185
- def define_input_table(
186
- self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
187
- label: _tp.Optional[str] = None, optional: bool = False, dynamic: bool = False,
188
- input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
189
- -> _meta.ModelInputSchema:
189
+ def define_file_type(self, extension: str, mime_type: str) -> _meta.FileType:
190
+
191
+ _val.validate_signature(self.define_file_type, extension, mime_type)
192
+
193
+ return _meta.FileType(extension=extension, mimeType=mime_type)
194
+
195
+ def define_input(
196
+ self, requirement: _tp.Union[_meta.SchemaDefinition, _meta.FileType], *,
197
+ label: _tp.Optional[str] = None,
198
+ optional: bool = False, dynamic: bool = False,
199
+ input_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None):
190
200
 
191
201
  _val.validate_signature(
192
- self.define_input_table, *fields,
202
+ self.define_input, requirement,
193
203
  label=label, optional=optional, dynamic=dynamic,
194
204
  input_props=input_props)
195
205
 
196
- # Do not define details for dynamic schemas
206
+ if isinstance(requirement, _meta.SchemaDefinition):
197
207
 
198
- if dynamic:
199
- schema_def = _meta.SchemaDefinition(_meta.SchemaType.TABLE)
200
- else:
201
- schema_def = self.define_schema(*fields, schema_type=_meta.SchemaType.TABLE)
208
+ return _meta.ModelInputSchema(
209
+ objectType=_meta.ObjectType.DATA, schema=requirement,
210
+ label=label, optional=optional, dynamic=dynamic,
211
+ inputProps=input_props)
202
212
 
203
- return _meta.ModelInputSchema(
204
- schema=schema_def, label=label,
205
- optional=optional, dynamic=dynamic,
206
- inputProps=input_props)
213
+ elif isinstance(requirement, _meta.FileType):
207
214
 
208
- def define_output_table(
209
- self, *fields: _tp.Union[_meta.FieldSchema, _tp.List[_meta.FieldSchema]],
210
- label: _tp.Optional[str] = None, optional: bool = False, dynamic: bool = False,
211
- output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None) \
212
- -> _meta.ModelOutputSchema:
215
+ return _meta.ModelInputSchema(
216
+ objectType=_meta.ObjectType.FILE, fileType=requirement,
217
+ label=label, optional=optional, dynamic=dynamic,
218
+ inputProps=input_props)
219
+
220
+ else:
221
+ raise _ex.EUnexpected()
222
+
223
+ def define_output(
224
+ self, requirement: _tp.Union[_meta.SchemaDefinition, _meta.FileType], *,
225
+ label: _tp.Optional[str] = None,
226
+ optional: bool = False, dynamic: bool = False,
227
+ output_props: _tp.Optional[_tp.Dict[str, _tp.Any]] = None):
213
228
 
214
229
  _val.validate_signature(
215
- self.define_output_table, *fields,
230
+ self.define_output, requirement,
216
231
  label=label, optional=optional, dynamic=dynamic,
217
232
  output_props=output_props)
218
233
 
219
- # Do not define details for dynamic schemas
234
+ if isinstance(requirement, _meta.SchemaDefinition):
220
235
 
221
- if dynamic:
222
- schema_def = _meta.SchemaDefinition(_meta.SchemaType.TABLE)
223
- else:
224
- schema_def = self.define_schema(*fields, schema_type=_meta.SchemaType.TABLE)
236
+ return _meta.ModelOutputSchema(
237
+ objectType=_meta.ObjectType.DATA, schema=requirement,
238
+ label=label, optional=optional, dynamic=dynamic,
239
+ outputProps=output_props)
225
240
 
226
- return _meta.ModelOutputSchema(
227
- schema=schema_def, label=label,
228
- optional=optional, dynamic=dynamic,
229
- outputProps=output_props)
241
+ elif isinstance(requirement, _meta.FileType):
242
+
243
+ return _meta.ModelOutputSchema(
244
+ objectType=_meta.ObjectType.FILE, fileType=requirement,
245
+ label=label, optional=optional, dynamic=dynamic,
246
+ outputProps=output_props)
247
+
248
+ else:
249
+ raise _ex.EUnexpected()
230
250
 
231
251
  @staticmethod
232
252
  def _build_named_dict(
tracdap/rt/_impl/util.py CHANGED
@@ -235,7 +235,7 @@ def get_job_resource(
235
235
  if optional:
236
236
  return None
237
237
 
238
- err = f"Missing required {selector.objectType} resource [{object_key(selector)}]"
238
+ err = f"Missing required {selector.objectType.name} resource [{object_key(selector)}]"
239
239
  raise ex.ERuntimeValidation(err)
240
240
 
241
241
 
@@ -306,6 +306,9 @@ class StaticValidator:
306
306
  __reserved_identifier_pattern = re.compile("\\A(_|trac_)", re.ASCII)
307
307
  __label_length_limit = 4096
308
308
 
309
+ __file_extension_pattern = re.compile('\\A[a-zA-Z0-9]+\\Z')
310
+ __mime_type_pattern = re.compile('\\A\\w+/[-.\\w]+(?:\\+[-.\\w]+)?\\Z')
311
+
309
312
  __PRIMITIVE_TYPES = [
310
313
  meta.BasicType.BOOLEAN,
311
314
  meta.BasicType.INTEGER,
@@ -418,49 +421,72 @@ class StaticValidator:
418
421
  cls._valid_identifiers(param.paramProps.keys(), "entry in param props")
419
422
 
420
423
  @classmethod
421
- def _check_inputs_or_outputs(cls, inputs_or_outputs):
424
+ def _check_inputs_or_outputs(cls, sockets):
422
425
 
423
- for input_name, input_schema in inputs_or_outputs.items():
426
+ for socket_name, socket in sockets.items():
424
427
 
425
- cls._log.info(f"Checking {input_name}")
428
+ if socket.objectType == meta.ObjectType.DATA:
429
+ cls._check_socket_schema(socket_name, socket)
430
+ elif socket.objectType == meta.ObjectType.FILE:
431
+ cls._check_socket_file_type(socket_name, socket)
432
+ else:
433
+ raise ex.EModelValidation(f"Invalid object type [{socket.objectType.name}] for [{socket_name}]")
426
434
 
427
- if input_schema.dynamic:
428
- if input_schema.schema and input_schema.schema.table:
429
- error = "Dynamic schemas must have schema.table = None"
430
- cls._fail(f"Invalid schema for [{input_name}]: {error}")
431
- else:
432
- continue
435
+ label = socket.label
436
+ cls._check_label(label, socket_name)
437
+
438
+ if isinstance(socket, meta.ModelInputSchema):
439
+ if socket.inputProps is not None:
440
+ cls._valid_identifiers(socket.inputProps.keys(), "entry in input props")
441
+ else:
442
+ if socket.outputProps is not None:
443
+ cls._valid_identifiers(socket.outputProps.keys(), "entry in output props")
433
444
 
434
- fields = input_schema.schema.table.fields
435
- field_names = list(map(lambda f: f.fieldName, fields))
436
- property_type = f"field in [{input_name}]"
445
+ @classmethod
446
+ def _check_socket_schema(cls, socket_name, socket):
437
447
 
438
- if len(fields) == 0:
439
- cls._fail(f"Invalid schema for [{input_name}]: No fields defined")
448
+ if socket.schema is None:
449
+ cls._fail(f"Missing schema requirement for [{socket_name}]")
450
+ return
440
451
 
441
- cls._valid_identifiers(field_names, property_type)
442
- cls._case_insensitive_duplicates(field_names, property_type)
452
+ if socket.dynamic:
453
+ if socket.schema and socket.schema.table:
454
+ error = "Dynamic schemas must have schema.table = None"
455
+ cls._fail(f"Invalid schema for [{socket_name}]: {error}")
456
+ else:
457
+ return
443
458
 
444
- for field in fields:
445
- cls._check_single_field(field, property_type)
459
+ fields = socket.schema.table.fields
460
+ field_names = list(map(lambda f: f.fieldName, fields))
461
+ property_type = f"field in [{socket_name}]"
446
462
 
447
- label = input_schema.label
448
- cls._check_label(label, input_name)
463
+ if len(fields) == 0:
464
+ cls._fail(f"Invalid schema for [{socket_name}]: No fields defined")
449
465
 
450
- if isinstance(input_schema, meta.ModelInputSchema):
451
- if input_schema.inputProps is not None:
452
- cls._valid_identifiers(input_schema.inputProps.keys(), "entry in input props")
453
- else:
454
- if input_schema.outputProps is not None:
455
- cls._valid_identifiers(input_schema.outputProps.keys(), "entry in output props")
466
+ cls._valid_identifiers(field_names, property_type)
467
+ cls._case_insensitive_duplicates(field_names, property_type)
468
+
469
+ for field in fields:
470
+ cls._check_single_field(field, property_type)
471
+
472
+ @classmethod
473
+ def _check_socket_file_type(cls, socket_name, socket):
474
+
475
+ if socket.fileType is None:
476
+ cls._fail(f"Missing file type requirement for [{socket_name}]")
477
+ return
478
+
479
+ if not cls.__file_extension_pattern.match(socket.fileType.extension):
480
+ cls._fail(f"Invalid extension [{socket.fileType.extension}] for [{socket_name}]")
481
+
482
+ if not cls.__mime_type_pattern.match(socket.fileType.mimeType):
483
+ cls._fail(f"Invalid mime type [{socket.fileType.mimeType}] for [{socket_name}]")
456
484
 
457
485
  @classmethod
458
486
  def _check_single_field(cls, field: meta.FieldSchema, property_type):
459
487
 
460
488
  # Valid identifier and not trac reserved checked separately
461
489
 
462
- cls._log.info(field.fieldName)
463
-
464
490
  if field.fieldOrder < 0:
465
491
  cls._fail(f"Invalid {property_type}: [{field.fieldName}] fieldOrder < 0")
466
492
 
tracdap/rt/_version.py CHANGED
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- __version__ = "0.7.0"
16
+ __version__ = "0.8.0b1"
@@ -17,13 +17,16 @@
17
17
  TRAC model API for Python
18
18
  """
19
19
 
20
- from .model_api import *
21
- from .static_api import *
22
-
23
20
  # Make metadata classes available to client code when importing the API package
24
21
  # Remove this import when generating docs, so metadata classes are only documented once
25
22
  from tracdap.rt.metadata import * # noqa DOCGEN_REMOVE
26
23
 
24
+ # static_api overrides some metadata types for backwards compatibility with pre-0.8 versions
25
+ # Make sure it is last in the list
26
+ from .file_types import *
27
+ from .model_api import *
28
+ from .static_api import *
29
+
27
30
  # Map basic types into the root of the API package
28
31
 
29
32
  BOOLEAN = BasicType.BOOLEAN