tracdap-runtime 0.6.5__tar.gz → 0.6.6__tar.gz

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 (127) hide show
  1. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/PKG-INFO +3 -1
  2. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/setup.cfg +4 -1
  3. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/context.py +272 -105
  4. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/dev_mode.py +231 -138
  5. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/engine.py +217 -59
  6. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/functions.py +25 -1
  7. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/graph.py +9 -0
  8. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/graph_builder.py +295 -198
  9. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/runtime.py +7 -5
  10. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/config_parser.py +11 -4
  11. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/data.py +278 -167
  12. tracdap_runtime-0.6.6/src/tracdap/rt/_impl/ext/sql.py +116 -0
  13. tracdap_runtime-0.6.6/src/tracdap/rt/_impl/ext/storage.py +57 -0
  14. tracdap_runtime-0.6.6/src/tracdap/rt/_impl/grpc/__init__.py +13 -0
  15. tracdap_runtime-0.6.6/src/tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.py +128 -0
  16. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.pyi +37 -2
  17. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/static_api.py +24 -11
  18. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/storage.py +2 -2
  19. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/util.py +10 -0
  20. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/validation.py +66 -13
  21. tracdap_runtime-0.6.6/src/tracdap/rt/_plugins/storage_sql.py +417 -0
  22. tracdap_runtime-0.6.6/src/tracdap/rt/_plugins/storage_sql_dialects.py +117 -0
  23. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_version.py +1 -1
  24. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/api/experimental.py +79 -32
  25. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/api/hook.py +10 -0
  26. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/__init__.py +4 -0
  27. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/job.py +45 -0
  28. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/tracdap_runtime.egg-info/PKG-INFO +3 -1
  29. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/tracdap_runtime.egg-info/SOURCES.txt +5 -0
  30. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/tracdap_runtime.egg-info/requires.txt +3 -0
  31. tracdap_runtime-0.6.5/src/tracdap/rt/_impl/grpc/tracdap/metadata/job_pb2.py +0 -120
  32. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/LICENSE +0 -0
  33. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/README.md +0 -0
  34. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/pyproject.toml +0 -0
  35. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/__init__.py +0 -0
  36. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/__init__.py +0 -0
  37. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/actors.py +0 -0
  38. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_exec/server.py +0 -0
  39. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/__init__.py +0 -0
  40. {tracdap_runtime-0.6.5/src/tracdap/rt/_impl/grpc → tracdap_runtime-0.6.6/src/tracdap/rt/_impl/ext}/__init__.py +0 -0
  41. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/codec.py +0 -0
  42. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.py +0 -0
  43. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2.pyi +0 -0
  44. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/api/internal/runtime_pb2_grpc.py +0 -0
  45. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/common_pb2.py +0 -0
  46. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/common_pb2.pyi +0 -0
  47. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/custom_pb2.py +0 -0
  48. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/custom_pb2.pyi +0 -0
  49. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.py +0 -0
  50. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/data_pb2.pyi +0 -0
  51. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.py +0 -0
  52. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/file_pb2.pyi +0 -0
  53. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/flow_pb2.py +0 -0
  54. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/flow_pb2.pyi +0 -0
  55. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.py +0 -0
  56. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/model_pb2.pyi +0 -0
  57. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.py +0 -0
  58. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/object_id_pb2.pyi +0 -0
  59. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.py +0 -0
  60. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/object_pb2.pyi +0 -0
  61. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/resource_pb2.py +0 -0
  62. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/resource_pb2.pyi +0 -0
  63. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/search_pb2.py +0 -0
  64. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/search_pb2.pyi +0 -0
  65. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/stoarge_pb2.py +0 -0
  66. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/stoarge_pb2.pyi +0 -0
  67. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/tag_pb2.py +0 -0
  68. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/tag_pb2.pyi +0 -0
  69. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/tag_update_pb2.py +0 -0
  70. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/tag_update_pb2.pyi +0 -0
  71. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/type_pb2.py +0 -0
  72. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/grpc/tracdap/metadata/type_pb2.pyi +0 -0
  73. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/guard_rails.py +0 -0
  74. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/models.py +0 -0
  75. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/repos.py +0 -0
  76. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/schemas.py +0 -0
  77. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/shim.py +0 -0
  78. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_impl/type_system.py +0 -0
  79. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/__init__.py +0 -0
  80. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/_helpers.py +0 -0
  81. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/config_local.py +0 -0
  82. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/format_arrow.py +0 -0
  83. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/format_csv.py +0 -0
  84. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/format_parquet.py +0 -0
  85. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/repo_git.py +0 -0
  86. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/repo_local.py +0 -0
  87. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/repo_pypi.py +0 -0
  88. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/storage_aws.py +0 -0
  89. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/storage_azure.py +0 -0
  90. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/storage_gcp.py +0 -0
  91. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/_plugins/storage_local.py +0 -0
  92. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/api/__init__.py +0 -0
  93. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/api/model_api.py +0 -0
  94. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/api/static_api.py +0 -0
  95. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/config/__init__.py +0 -0
  96. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/config/common.py +0 -0
  97. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/config/job.py +0 -0
  98. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/config/platform.py +0 -0
  99. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/config/result.py +0 -0
  100. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/config/runtime.py +0 -0
  101. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/exceptions.py +0 -0
  102. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/ext/__init__.py +0 -0
  103. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/ext/config.py +0 -0
  104. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/ext/embed.py +0 -0
  105. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/ext/plugins.py +0 -0
  106. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/ext/repos.py +0 -0
  107. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/ext/storage.py +0 -0
  108. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/launch/__init__.py +0 -0
  109. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/launch/__main__.py +0 -0
  110. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/launch/cli.py +0 -0
  111. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/launch/launch.py +0 -0
  112. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/common.py +0 -0
  113. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/custom.py +0 -0
  114. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/data.py +0 -0
  115. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/file.py +0 -0
  116. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/flow.py +0 -0
  117. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/model.py +0 -0
  118. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/object.py +0 -0
  119. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/object_id.py +0 -0
  120. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/resource.py +0 -0
  121. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/search.py +0 -0
  122. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/stoarge.py +0 -0
  123. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/tag.py +0 -0
  124. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/tag_update.py +0 -0
  125. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/src/tracdap/rt/metadata/type.py +0 -0
  126. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/tracdap_runtime.egg-info/dependency_links.txt +0 -0
  127. {tracdap_runtime-0.6.5 → tracdap_runtime-0.6.6}/tracdap_runtime.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tracdap-runtime
3
- Version: 0.6.5
3
+ Version: 0.6.6
4
4
  Summary: Runtime package for building models on the TRAC Data & Analytics Platform
5
5
  Home-page: https://tracdap.finos.org/
6
6
  Author: Martin Traverse
@@ -30,6 +30,8 @@ Provides-Extra: polars
30
30
  Requires-Dist: polars<2.0.0,>=1.0.0; extra == "polars"
31
31
  Provides-Extra: spark
32
32
  Requires-Dist: pyspark<3.6.0,>=3.0.0; extra == "spark"
33
+ Provides-Extra: sql
34
+ Requires-Dist: sqlalchemy<2.1.0,>=2.0.0; extra == "sql"
33
35
  Provides-Extra: aws
34
36
  Requires-Dist: botocore==1.34.93; extra == "aws"
35
37
  Requires-Dist: boto3==1.34.93; extra == "aws"
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = tracdap-runtime
3
- version = 0.6.5
3
+ version = 0.6.6
4
4
  description = Runtime package for building models on the TRAC Data & Analytics Platform
5
5
  long_description = file: README.md
6
6
  long_description_content_type = text/markdown
@@ -28,6 +28,7 @@ packages =
28
28
  tracdap.rt.ext
29
29
  tracdap.rt._exec
30
30
  tracdap.rt._impl
31
+ tracdap.rt._impl.ext
31
32
  tracdap.rt._impl.grpc
32
33
  tracdap.rt._impl.grpc.tracdap
33
34
  tracdap.rt._impl.grpc.tracdap.metadata
@@ -55,6 +56,8 @@ polars =
55
56
  polars >= 1.0.0, < 2.0.0
56
57
  spark =
57
58
  pyspark >= 3.0.0, < 3.6.0
59
+ sql =
60
+ sqlalchemy >= 2.0.0, < 2.1.0
58
61
  aws =
59
62
  botocore == 1.34.93
60
63
  boto3 == 1.34.93
@@ -55,8 +55,6 @@ class TracContextImpl(_api.TracContext):
55
55
  Output views will contain schemas but no data.
56
56
  """
57
57
 
58
- __DEFAULT_TEMPORAL_OBJECTS = False
59
-
60
58
  def __init__(self,
61
59
  model_def: _meta.ModelDefinition,
62
60
  model_class: _api.TracModel.__class__,
@@ -134,53 +132,22 @@ class TracContextImpl(_api.TracContext):
134
132
  else:
135
133
  return copy.deepcopy(data_view.trac_schema)
136
134
 
137
- def get_table(self, dataset_name: str, framework, **kwargs) -> _eapi._DATA_FRAMEWORK: # noqa
138
-
139
- # Support the experimental API data framework syntax
140
-
141
- if framework == _eapi.PANDAS:
142
- return self.get_pandas_table(dataset_name, **kwargs)
143
- elif framework == _eapi.POLARS:
144
- return self.get_polars_table(dataset_name)
145
- else:
146
- raise _ex.ERuntimeValidation(f"Unsupported data framework [{framework}]")
147
-
148
- def get_pandas_table(self, dataset_name: str, use_temporal_objects: tp.Optional[bool] = None) \
149
- -> "_data.pandas.DataFrame":
150
-
151
- _val.require_package("pandas", _data.pandas)
152
- _val.validate_signature(self.get_pandas_table, dataset_name, use_temporal_objects)
135
+ def get_table(self, dataset_name: str, framework: _eapi.DataFramework[_eapi.DATA_API], **framework_args) -> _eapi.DATA_API:
153
136
 
154
- data_view, schema = self.__get_data_view(dataset_name)
155
- part_key = _data.DataPartKey.for_root()
156
-
157
- if use_temporal_objects is None:
158
- use_temporal_objects = self.__DEFAULT_TEMPORAL_OBJECTS
159
-
160
- return _data.DataMapping.view_to_pandas(data_view, part_key, schema, use_temporal_objects)
161
-
162
- def get_polars_table(self, dataset_name: str) -> "_data.polars.DataFrame":
163
-
164
- _val.require_package("polars", _data.polars)
165
- _val.validate_signature(self.get_polars_table, dataset_name)
166
-
167
- data_view, schema = self.__get_data_view(dataset_name)
168
- part_key = _data.DataPartKey.for_root()
169
-
170
- return _data.DataMapping.view_to_polars(data_view, part_key, schema)
171
-
172
- def __get_data_view(self, dataset_name: str):
173
-
174
- _val.validate_signature(self.__get_data_view, dataset_name)
137
+ _val.validate_signature(self.get_table, dataset_name, framework)
138
+ _val.require_package(framework.protocol_name, framework.api_type)
175
139
 
176
140
  self.__val.check_dataset_valid_identifier(dataset_name)
177
141
  self.__val.check_dataset_defined_in_model(dataset_name)
178
142
  self.__val.check_dataset_available_in_context(dataset_name)
143
+ self.__val.check_data_framework_args(framework, framework_args)
179
144
 
180
145
  static_schema = self.__get_static_schema(self.__model_def, dataset_name)
181
146
  data_view = self.__local_ctx.get(dataset_name)
182
147
  part_key = _data.DataPartKey.for_root()
183
148
 
149
+ converter = _data.DataConverter.for_framework(framework, **framework_args)
150
+
184
151
  self.__val.check_context_object_type(dataset_name, data_view, _data.DataView)
185
152
  self.__val.check_dataset_schema_defined(dataset_name, data_view)
186
153
  self.__val.check_dataset_part_present(dataset_name, data_view, part_key)
@@ -193,7 +160,18 @@ class TracContextImpl(_api.TracContext):
193
160
  else:
194
161
  schema = data_view.arrow_schema
195
162
 
196
- return data_view, schema
163
+ table = _data.DataMapping.view_to_arrow(data_view, part_key)
164
+
165
+ # Data conformance is applied automatically inside the converter, if schema != None
166
+ return converter.from_internal(table, schema)
167
+
168
+ def get_pandas_table(self, dataset_name: str, use_temporal_objects: tp.Optional[bool] = None) -> "_data.pandas.DataFrame":
169
+
170
+ return self.get_table(dataset_name, _eapi.PANDAS, use_temporal_objects=use_temporal_objects)
171
+
172
+ def get_polars_table(self, dataset_name: str) -> "_data.polars.DataFrame":
173
+
174
+ return self.get_table(dataset_name, _eapi.POLARS)
197
175
 
198
176
  def put_schema(self, dataset_name: str, schema: _meta.SchemaDefinition):
199
177
 
@@ -225,57 +203,28 @@ class TracContextImpl(_api.TracContext):
225
203
 
226
204
  self.__local_ctx[dataset_name] = updated_view
227
205
 
228
- def put_table(self, dataset_name: str, dataset: _eapi._DATA_FRAMEWORK, **kwargs): # noqa
229
-
230
- # Support the experimental API data framework syntax
231
-
232
- if _data.pandas and isinstance(dataset, _data.pandas.DataFrame):
233
- self.put_pandas_table(dataset_name, dataset)
234
- elif _data.polars and isinstance(dataset, _data.polars.DataFrame):
235
- self.put_polars_table(dataset_name, dataset)
236
- else:
237
- raise _ex.ERuntimeValidation(f"Unsupported data framework[{type(dataset)}]")
238
-
239
- def put_pandas_table(self, dataset_name: str, dataset: "_data.pandas.DataFrame"):
240
-
241
- _val.require_package("pandas", _data.pandas)
242
- _val.validate_signature(self.put_pandas_table, dataset_name, dataset)
243
-
244
- part_key = _data.DataPartKey.for_root()
245
- data_view, schema = self.__put_data_view(dataset_name, part_key, dataset, _data.pandas.DataFrame)
206
+ def put_table(
207
+ self, dataset_name: str, dataset: _eapi.DATA_API,
208
+ framework: tp.Optional[_eapi.DataFramework[_eapi.DATA_API]] = None,
209
+ **framework_args):
246
210
 
247
- # Data conformance is applied inside these conversion functions
211
+ _val.validate_signature(self.put_table, dataset_name, dataset, framework)
248
212
 
249
- updated_item = _data.DataMapping.pandas_to_item(dataset, schema)
250
- updated_view = _data.DataMapping.add_item_to_view(data_view, part_key, updated_item)
213
+ if framework is None:
214
+ framework = _data.DataConverter.get_framework(dataset)
251
215
 
252
- self.__local_ctx[dataset_name] = updated_view
253
-
254
- def put_polars_table(self, dataset_name: str, dataset: "_data.polars.DataFrame"):
255
-
256
- _val.require_package("polars", _data.polars)
257
- _val.validate_signature(self.put_polars_table, dataset_name, dataset)
258
-
259
- part_key = _data.DataPartKey.for_root()
260
- data_view, schema = self.__put_data_view(dataset_name, part_key, dataset, _data.polars.DataFrame)
261
-
262
- # Data conformance is applied inside these conversion functions
263
-
264
- updated_item = _data.DataMapping.polars_to_item(dataset, schema)
265
- updated_view = _data.DataMapping.add_item_to_view(data_view, part_key, updated_item)
266
-
267
- self.__local_ctx[dataset_name] = updated_view
268
-
269
- def __put_data_view(self, dataset_name: str, part_key: _data.DataPartKey, dataset: tp.Any, framework: type):
270
-
271
- _val.validate_signature(self.__put_data_view, dataset_name, part_key, dataset, framework)
216
+ _val.require_package(framework.protocol_name, framework.api_type)
272
217
 
273
218
  self.__val.check_dataset_valid_identifier(dataset_name)
274
219
  self.__val.check_dataset_is_model_output(dataset_name)
275
- self.__val.check_provided_dataset_type(dataset, framework)
220
+ self.__val.check_provided_dataset_type(dataset, framework.api_type)
221
+ self.__val.check_data_framework_args(framework, framework_args)
276
222
 
277
223
  static_schema = self.__get_static_schema(self.__model_def, dataset_name)
278
224
  data_view = self.__local_ctx.get(dataset_name)
225
+ part_key = _data.DataPartKey.for_root()
226
+
227
+ converter = _data.DataConverter.for_framework(framework)
279
228
 
280
229
  if data_view is None:
281
230
  if static_schema is not None:
@@ -294,7 +243,21 @@ class TracContextImpl(_api.TracContext):
294
243
  else:
295
244
  schema = data_view.arrow_schema
296
245
 
297
- return data_view, schema
246
+ # Data conformance is applied automatically inside the converter, if schema != None
247
+ table = converter.to_internal(dataset, schema)
248
+ item = _data.DataItem(schema, table)
249
+
250
+ updated_view = _data.DataMapping.add_item_to_view(data_view, part_key, item)
251
+
252
+ self.__local_ctx[dataset_name] = updated_view
253
+
254
+ def put_pandas_table(self, dataset_name: str, dataset: "_data.pandas.DataFrame"):
255
+
256
+ self.put_table(dataset_name, dataset, _eapi.PANDAS)
257
+
258
+ def put_polars_table(self, dataset_name: str, dataset: "_data.polars.DataFrame"):
259
+
260
+ self.put_table(dataset_name, dataset, _eapi.POLARS)
298
261
 
299
262
  def log(self) -> logging.Logger:
300
263
 
@@ -335,7 +298,7 @@ class TracDataContextImpl(TracContextImpl, _eapi.TracDataContext):
335
298
  def __init__(
336
299
  self, model_def: _meta.ModelDefinition, model_class: _api.TracModel.__class__,
337
300
  local_ctx: tp.Dict[str, tp.Any], dynamic_outputs: tp.List[str],
338
- storage_map: tp.Dict[str, tp.Union[_eapi.TracFileStorage]],
301
+ storage_map: tp.Dict[str, tp.Union[_eapi.TracFileStorage, _eapi.TracDataStorage]],
339
302
  checkout_directory: pathlib.Path = None):
340
303
 
341
304
  super().__init__(model_def, model_class, local_ctx, dynamic_outputs, checkout_directory)
@@ -358,8 +321,27 @@ class TracDataContextImpl(TracContextImpl, _eapi.TracDataContext):
358
321
 
359
322
  return self.__storage_map[storage_key]
360
323
 
361
- def get_data_storage(self, storage_key: str) -> None:
362
- raise _ex.ERuntimeValidation("Data storage API not available yet")
324
+ def get_data_storage(
325
+ self, storage_key: str,
326
+ framework: _eapi.DataFramework[_eapi.DATA_API],
327
+ **framework_args) -> _eapi.TracDataStorage[_eapi.DATA_API]:
328
+
329
+ _val.validate_signature(self.get_file_storage, storage_key)
330
+
331
+ self.__val.check_storage_valid_identifier(storage_key)
332
+ self.__val.check_storage_available(self.__storage_map, storage_key)
333
+ self.__val.check_storage_type(self.__storage_map, storage_key, _eapi.TracDataStorage)
334
+ self.__val.check_data_framework_args(framework, framework_args)
335
+
336
+ storage = self.__storage_map[storage_key]
337
+ converter = _data.DataConverter.for_framework(framework, **framework_args)
338
+
339
+ # Create a shallow copy of the storage impl with a converter for the requested data framework
340
+ # At some point we will need a storage factory class, bc the internal data API can also be different
341
+ storage = copy.copy(storage)
342
+ storage._TracDataStorageImpl__converter = converter
343
+
344
+ return storage
363
345
 
364
346
  def add_data_import(self, dataset_name: str):
365
347
 
@@ -372,15 +354,30 @@ class TracDataContextImpl(TracContextImpl, _eapi.TracDataContext):
372
354
  self.__local_ctx[dataset_name] = _data.DataView.create_empty()
373
355
  self.__dynamic_outputs.append(dataset_name)
374
356
 
375
- def set_source_metadata(self, dataset_name: str, storage_key: str, source_info: _eapi.FileStat):
357
+ def set_source_metadata(self, dataset_name: str, storage_key: str, source_info: tp.Union[_eapi.FileStat, str]):
376
358
 
377
- _val.validate_signature(self.add_data_import, dataset_name, storage_key, source_info)
359
+ _val.validate_signature(self.set_source_metadata, dataset_name, storage_key, source_info)
360
+
361
+ self.__val.check_dataset_valid_identifier(dataset_name)
362
+ self.__val.check_dataset_available_in_context(dataset_name)
363
+ self.__val.check_storage_valid_identifier(storage_key)
364
+ self.__val.check_storage_available(self.__storage_map, storage_key)
365
+
366
+ storage = self.__storage_map[storage_key]
367
+
368
+ if isinstance(storage, _eapi.TracFileStorage):
369
+ if not isinstance(source_info, _eapi.FileStat):
370
+ self.__val.report_public_error(f"Expected storage_info to be a FileStat, [{storage_key}] refers to file storage")
371
+
372
+ if isinstance(storage, _eapi.TracDataStorage):
373
+ if not isinstance(source_info, str):
374
+ self.__val.report_public_error(f"Expected storage_info to be a table name, [{storage_key}] refers to dadta storage")
378
375
 
379
376
  pass # Not implemented yet, only required when imports are sent back to the platform
380
377
 
381
378
  def set_attribute(self, dataset_name: str, attribute_name: str, value: tp.Any):
382
379
 
383
- _val.validate_signature(self.add_data_import, dataset_name, attribute_name, value)
380
+ _val.validate_signature(self.set_attribute, dataset_name, attribute_name, value)
384
381
 
385
382
  pass # Not implemented yet, only required when imports are sent back to the platform
386
383
 
@@ -531,13 +528,132 @@ class TracFileStorageImpl(_eapi.TracFileStorage):
531
528
  super().write_bytes(storage_path, data)
532
529
 
533
530
 
531
+ class TracDataStorageImpl(_eapi.TracDataStorage[_eapi.DATA_API]):
532
+
533
+ def __init__(
534
+ self, storage_key: str, storage_impl: _storage.IDataStorageBase[_data.T_INTERNAL_DATA, _data.T_INTERNAL_SCHEMA],
535
+ data_converter: _data.DataConverter[_eapi.DATA_API, _data.T_INTERNAL_DATA, _data.T_INTERNAL_SCHEMA],
536
+ write_access: bool, checkout_directory):
537
+
538
+ self.__storage_key = storage_key
539
+ self.__converter = data_converter
540
+
541
+ self.__has_table = lambda tn: storage_impl.has_table(tn)
542
+ self.__list_tables = lambda: storage_impl.list_tables()
543
+ self.__read_table = lambda tn: storage_impl.read_table(tn)
544
+ self.__native_read_query = lambda q, ps: storage_impl.native_read_query(q, **ps)
545
+
546
+ if write_access:
547
+ self.__create_table = lambda tn, s: storage_impl.create_table(tn, s)
548
+ self.__write_table = lambda tn, ds: storage_impl.write_table(tn, ds)
549
+ else:
550
+ self.__create_table = None
551
+ self.__write_table = None
552
+
553
+ self.__log = _util.logger_for_object(self)
554
+ self.__val = TracStorageValidator(self.__log, checkout_directory, self.__storage_key)
555
+
556
+ def has_table(self, table_name: str) -> bool:
557
+
558
+ _val.validate_signature(self.has_table, table_name)
559
+
560
+ self.__val.check_operation_available(self.has_table, self.__has_table)
561
+ self.__val.check_table_name_is_valid(table_name)
562
+ self.__val.check_storage_path_is_valid(table_name)
563
+
564
+ try:
565
+ return self.__has_table(table_name)
566
+ except _ex.EStorageRequest as e:
567
+ self.__val.report_public_error(e)
568
+
569
+ def list_tables(self) -> tp.List[str]:
570
+
571
+ _val.validate_signature(self.list_tables)
572
+
573
+ self.__val.check_operation_available(self.list_tables, self.__list_tables)
574
+
575
+ try:
576
+ return self.__list_tables()
577
+ except _ex.EStorageRequest as e:
578
+ self.__val.report_public_error(e)
579
+
580
+ def create_table(self, table_name: str, schema: _api.SchemaDefinition):
581
+
582
+ _val.validate_signature(self.create_table, table_name, schema)
583
+
584
+ self.__val.check_operation_available(self.create_table, self.__create_table)
585
+ self.__val.check_table_name_is_valid(table_name)
586
+ self.__val.check_storage_path_is_valid(table_name)
587
+
588
+ arrow_schema = _data.DataMapping.trac_to_arrow_schema(schema)
589
+
590
+ try:
591
+ self.__create_table(table_name, arrow_schema)
592
+ except _ex.EStorageRequest as e:
593
+ self.__val.report_public_error(e)
594
+
595
+ def read_table(self, table_name: str) -> _eapi.DATA_API:
596
+
597
+ _val.validate_signature(self.read_table, table_name)
598
+
599
+ self.__val.check_operation_available(self.read_table, self.__read_table)
600
+ self.__val.check_table_name_is_valid(table_name)
601
+ self.__val.check_table_name_not_reserved(table_name)
602
+
603
+ try:
604
+ raw_data = self.__read_table(table_name)
605
+ return self.__converter.from_internal(raw_data)
606
+
607
+ except _ex.EStorageRequest as e:
608
+ self.__val.report_public_error(e)
609
+
610
+ def native_read_query(self, query: str, **parameters) -> _eapi.DATA_API:
611
+
612
+ _val.validate_signature(self.native_read_query, query, **parameters)
613
+
614
+ self.__val.check_operation_available(self.native_read_query, self.__native_read_query)
615
+
616
+ # TODO: validate query and parameters
617
+ # Some validation is performed by the impl
618
+
619
+ try:
620
+ raw_data = self.__native_read_query(query, **parameters)
621
+ return self.__converter.from_internal(raw_data)
622
+
623
+ except _ex.EStorageRequest as e:
624
+ self.__val.report_public_error(e)
625
+
626
+ def write_table(self, table_name: str, dataset: _eapi.DATA_API):
627
+
628
+ _val.validate_signature(self.write_table, table_name, dataset)
629
+
630
+ self.__val.check_operation_available(self.read_table, self.__read_table)
631
+ self.__val.check_table_name_is_valid(table_name)
632
+ self.__val.check_table_name_not_reserved(table_name)
633
+ self.__val.check_provided_dataset_type(dataset, self.__converter.framework.api_type)
634
+
635
+ try:
636
+ raw_data = self.__converter.to_internal(dataset)
637
+ self.__write_table(table_name, raw_data)
638
+
639
+ except _ex.EStorageRequest as e:
640
+ self.__val.report_public_error(e)
641
+
642
+
534
643
  class TracContextErrorReporter:
535
644
 
645
+ _VALID_IDENTIFIER = re.compile("^[a-zA-Z_]\\w*$",)
646
+ _RESERVED_IDENTIFIER = re.compile("^(trac_|_)\\w*")
647
+
536
648
  def __init__(self, log: logging.Logger, checkout_directory: pathlib.Path):
537
649
 
538
650
  self.__log = log
539
651
  self.__checkout_directory = checkout_directory
540
652
 
653
+ def report_public_error(self, exception: Exception):
654
+
655
+ self._report_error(str(exception), exception)
656
+
541
657
  def _report_error(self, message, cause: Exception = None):
542
658
 
543
659
  full_stack = traceback.extract_stack()
@@ -554,11 +670,18 @@ class TracContextErrorReporter:
554
670
  else:
555
671
  raise _ex.ERuntimeValidation(message)
556
672
 
673
+ @staticmethod
674
+ def _type_name(type_: type):
557
675
 
558
- class TracContextValidator(TracContextErrorReporter):
676
+ module = type_.__module__
677
+
678
+ if module is None or module == str.__class__.__module__ or module == tp.__name__:
679
+ return _val.type_name(type_, False)
680
+ else:
681
+ return _val.type_name(type_, True)
559
682
 
560
- __VALID_IDENTIFIER = re.compile("^[a-zA-Z_]\\w*$",)
561
- __RESERVED_IDENTIFIER = re.compile("^(trac_|_)\\w*")
683
+
684
+ class TracContextValidator(TracContextErrorReporter):
562
685
 
563
686
  def __init__(
564
687
  self, log: logging.Logger,
@@ -578,7 +701,7 @@ class TracContextValidator(TracContextErrorReporter):
578
701
  if param_name is None:
579
702
  self._report_error(f"Parameter name is null")
580
703
 
581
- if not self.__VALID_IDENTIFIER.match(param_name):
704
+ if not self._VALID_IDENTIFIER.match(param_name):
582
705
  self._report_error(f"Parameter name {param_name} is not a valid identifier")
583
706
 
584
707
  def check_param_defined_in_model(self, param_name: str):
@@ -596,7 +719,7 @@ class TracContextValidator(TracContextErrorReporter):
596
719
  if dataset_name is None:
597
720
  self._report_error(f"Dataset name is null")
598
721
 
599
- if not self.__VALID_IDENTIFIER.match(dataset_name):
722
+ if not self._VALID_IDENTIFIER.match(dataset_name):
600
723
  self._report_error(f"Dataset name {dataset_name} is not a valid identifier")
601
724
 
602
725
  def check_dataset_not_defined_in_model(self, dataset_name: str):
@@ -710,12 +833,39 @@ class TracContextValidator(TracContextErrorReporter):
710
833
  f"The object referenced by [{item_name}] in the current context has the wrong type" +
711
834
  f" (expected {expected_type_name}, got {actual_type_name})")
712
835
 
836
+ def check_data_framework_args(self, framework: _eapi.DataFramework, framework_args: tp.Dict[str, tp.Any]):
837
+
838
+ expected_args = _data.DataConverter.get_framework_args(framework)
839
+ unexpected_args = list(filter(lambda arg: arg not in expected_args, framework_args.keys()))
840
+
841
+ if any(unexpected_args):
842
+ unknown_args = ", ".join(unexpected_args)
843
+ self._report_error(f"Using [{framework}], some arguments were not recognized: [{unknown_args}]")
844
+
845
+ for arg_name, arg_type in expected_args.items():
846
+
847
+ arg_value = framework_args.get(arg_name)
848
+
849
+ if _val.check_type(arg_type, arg_value):
850
+ continue
851
+
852
+ if arg_value is None:
853
+ self._report_error(f"Using [{framework}], required argument [{arg_name}] is missing")
854
+
855
+ else:
856
+ expected_type_name = self._type_name(arg_type)
857
+ actual_type_name = self._type_name(type(arg_value))
858
+
859
+ self._report_error(
860
+ f"Using [{framework}], argument [{arg_name}] has the wrong type" +
861
+ f" (expected {expected_type_name}, got {actual_type_name})")
862
+
713
863
  def check_storage_valid_identifier(self, storage_key):
714
864
 
715
865
  if storage_key is None:
716
866
  self._report_error(f"Storage key is null")
717
867
 
718
- if not self.__VALID_IDENTIFIER.match(storage_key):
868
+ if not self._VALID_IDENTIFIER.match(storage_key):
719
869
  self._report_error(f"Storage key {storage_key} is not a valid identifier")
720
870
 
721
871
  def check_storage_available(self, storage_map: tp.Dict, storage_key: str):
@@ -737,16 +887,6 @@ class TracContextValidator(TracContextErrorReporter):
737
887
  else:
738
888
  self._report_error(f"Storage key [{storage_key}] refers to file storage, not data storage")
739
889
 
740
- @staticmethod
741
- def _type_name(type_: type):
742
-
743
- module = type_.__module__
744
-
745
- if module is None or module == str.__class__.__module__:
746
- return type_.__qualname__
747
-
748
- return module + '.' + type_.__name__
749
-
750
890
 
751
891
  class TracStorageValidator(TracContextErrorReporter):
752
892
 
@@ -777,3 +917,30 @@ class TracStorageValidator(TracContextErrorReporter):
777
917
 
778
918
  if _val.StorageValidator.storage_path_is_empty(storage_path):
779
919
  self._report_error(f"Storage path [{storage_path}] is not allowed")
920
+
921
+ def check_table_name_is_valid(self, table_name: str):
922
+
923
+ if table_name is None:
924
+ self._report_error(f"Table name is null")
925
+
926
+ if not self._VALID_IDENTIFIER.match(table_name):
927
+ self._report_error(f"Table name {table_name} is not a valid identifier")
928
+
929
+ def check_table_name_not_reserved(self, table_name: str):
930
+
931
+ if self._RESERVED_IDENTIFIER.match(table_name):
932
+ self._report_error(f"Table name {table_name} is a reserved identifier")
933
+
934
+ def check_provided_dataset_type(self, dataset: tp.Any, expected_type: type):
935
+
936
+ if dataset is None:
937
+ self._report_error(f"Provided dataset is null")
938
+
939
+ if not isinstance(dataset, expected_type):
940
+
941
+ expected_type_name = self._type_name(expected_type)
942
+ actual_type_name = self._type_name(type(dataset))
943
+
944
+ self._report_error(
945
+ f"Provided dataset is the wrong type" +
946
+ f" (expected {expected_type_name}, got {actual_type_name})")