cosmotech-acceleration-library 2.0.0__py3-none-any.whl → 2.1.0rc1__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 (42) hide show
  1. cosmotech/coal/__init__.py +1 -1
  2. cosmotech/coal/azure/__init__.py +5 -5
  3. cosmotech/coal/azure/adx/__init__.py +24 -10
  4. cosmotech/coal/azure/adx/ingestion.py +10 -14
  5. cosmotech/coal/azure/adx/query.py +1 -1
  6. cosmotech/coal/azure/adx/utils.py +2 -2
  7. cosmotech/coal/azure/blob.py +14 -20
  8. cosmotech/coal/cosmotech_api/apis/dataset.py +135 -16
  9. cosmotech/coal/cosmotech_api/apis/runner.py +23 -19
  10. cosmotech/coal/postgresql/runner.py +8 -11
  11. cosmotech/coal/postgresql/store.py +20 -25
  12. cosmotech/coal/postgresql/utils.py +2 -1
  13. cosmotech/coal/singlestore/store.py +3 -2
  14. cosmotech/coal/store/__init__.py +16 -13
  15. cosmotech/coal/store/output/aws_channel.py +12 -11
  16. cosmotech/coal/store/output/az_storage_channel.py +9 -18
  17. cosmotech/coal/store/output/channel_interface.py +15 -0
  18. cosmotech/coal/store/output/channel_spliter.py +11 -5
  19. cosmotech/coal/store/output/postgres_channel.py +7 -10
  20. cosmotech/coal/store/pandas.py +1 -1
  21. cosmotech/coal/store/pyarrow.py +2 -2
  22. cosmotech/coal/store/store.py +4 -7
  23. cosmotech/coal/utils/configuration.py +76 -48
  24. cosmotech/csm_data/commands/adx_send_data.py +1 -1
  25. cosmotech/csm_data/commands/adx_send_runnerdata.py +3 -2
  26. cosmotech/csm_data/commands/api/run_load_data.py +10 -8
  27. cosmotech/csm_data/commands/az_storage_upload.py +3 -2
  28. cosmotech/csm_data/commands/store/dump_to_azure.py +3 -2
  29. cosmotech/csm_data/commands/store/dump_to_postgresql.py +3 -2
  30. cosmotech/csm_data/commands/store/list_tables.py +3 -2
  31. cosmotech/csm_data/commands/store/load_csv_folder.py +10 -4
  32. cosmotech/csm_data/commands/store/load_from_singlestore.py +3 -2
  33. cosmotech/csm_data/commands/store/reset.py +8 -3
  34. cosmotech/csm_data/main.py +4 -4
  35. cosmotech/csm_data/utils/decorators.py +4 -3
  36. cosmotech/translation/coal/en-US/coal/services/dataset.yml +6 -0
  37. {cosmotech_acceleration_library-2.0.0.dist-info → cosmotech_acceleration_library-2.1.0rc1.dist-info}/METADATA +26 -27
  38. {cosmotech_acceleration_library-2.0.0.dist-info → cosmotech_acceleration_library-2.1.0rc1.dist-info}/RECORD +42 -42
  39. {cosmotech_acceleration_library-2.0.0.dist-info → cosmotech_acceleration_library-2.1.0rc1.dist-info}/WHEEL +1 -1
  40. {cosmotech_acceleration_library-2.0.0.dist-info → cosmotech_acceleration_library-2.1.0rc1.dist-info}/entry_points.txt +0 -0
  41. {cosmotech_acceleration_library-2.0.0.dist-info → cosmotech_acceleration_library-2.1.0rc1.dist-info}/licenses/LICENSE +0 -0
  42. {cosmotech_acceleration_library-2.0.0.dist-info → cosmotech_acceleration_library-2.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -12,31 +12,34 @@ This module provides functions for working with the Store,
12
12
  including loading and converting data.
13
13
  """
14
14
 
15
- # Re-export the Store class
16
- from cosmotech.coal.store.store import Store
17
-
18
15
  # Re-export functions from the csv module
19
16
  from cosmotech.coal.store.csv import (
20
- store_csv_file,
21
17
  convert_store_table_to_csv,
18
+ store_csv_file,
22
19
  )
23
20
 
24
21
  # Re-export functions from the native_python module
25
22
  from cosmotech.coal.store.native_python import (
26
- store_pylist,
27
23
  convert_table_as_pylist,
24
+ store_pylist,
28
25
  )
29
-
30
- # Re-export functions from the pandas module (if available)
31
-
32
26
  from cosmotech.coal.store.pandas import (
33
- store_dataframe,
34
27
  convert_store_table_to_dataframe as convert_store_table_to_pandas_dataframe,
35
28
  )
36
-
37
- # Re-export functions from the pyarrow module (if available)
38
-
29
+ from cosmotech.coal.store.pandas import (
30
+ store_dataframe,
31
+ )
39
32
  from cosmotech.coal.store.pyarrow import (
40
- store_table,
41
33
  convert_store_table_to_dataframe as convert_store_table_to_pyarrow_table,
42
34
  )
35
+ from cosmotech.coal.store.pyarrow import (
36
+ store_table,
37
+ )
38
+
39
+ # Re-export the Store class
40
+ from cosmotech.coal.store.store import Store
41
+
42
+ # Re-export functions from the pandas module (if available)
43
+
44
+
45
+ # Re-export functions from the pyarrow module (if available)
@@ -6,28 +6,29 @@ import pyarrow.parquet as pq
6
6
  from cosmotech.orchestrator.utils.translate import T
7
7
 
8
8
  from cosmotech.coal.aws import S3
9
- from cosmotech.coal.store.output.channel_interface import ChannelInterface
9
+ from cosmotech.coal.store.output.channel_interface import (
10
+ ChannelInterface,
11
+ MissingChannelConfigError,
12
+ )
10
13
  from cosmotech.coal.store.store import Store
11
- from cosmotech.coal.utils.configuration import Configuration
14
+ from cosmotech.coal.utils.configuration import Configuration, Dotdict
12
15
  from cosmotech.coal.utils.logger import LOGGER
13
16
 
14
17
 
15
18
  class AwsChannel(ChannelInterface):
16
19
  required_keys = {
17
- "cosmotech": [
18
- "dataset_absolute_path",
19
- ],
20
+ "coal": ["store"],
20
21
  "s3": ["access_key_id", "endpoint_url", "secret_access_key"],
21
22
  }
22
23
  requirement_string = required_keys
23
24
 
24
- def __init__(self, dct: dict = None):
25
- self.configuration = Configuration(dct)
25
+ def __init__(self, dct: Dotdict = None):
26
+ super().__init__(dct)
26
27
  self._s3 = S3(self.configuration)
27
28
 
28
- def send(self, tables_filter: Optional[list[str]] = None) -> bool:
29
+ def send(self, filter: Optional[list[str]] = None) -> bool:
29
30
 
30
- _s = Store(store_location=self.configuration.cosmotech.parameters_absolute_path)
31
+ _s = Store(configuration=self.configuration)
31
32
 
32
33
  if self._s3.output_type not in ("sqlite", "csv", "parquet"):
33
34
  LOGGER.error(T("coal.common.errors.data_invalid_output_type").format(output_type=self._s3.output_type))
@@ -43,8 +44,8 @@ class AwsChannel(ChannelInterface):
43
44
  self._s3.upload_file(_file_path, _uploaded_file_name)
44
45
  else:
45
46
  tables = list(_s.list_tables())
46
- if tables_filter:
47
- tables = [t for t in tables if t in tables_filter]
47
+ if filter:
48
+ tables = [t for t in tables if t in filter]
48
49
 
49
50
  for table_name in tables:
50
51
  _data_stream = BytesIO()
@@ -1,15 +1,16 @@
1
1
  from typing import Optional
2
2
 
3
3
  from cosmotech.coal.azure.blob import dump_store_to_azure
4
- from cosmotech.coal.store.output.channel_interface import ChannelInterface
5
- from cosmotech.coal.utils.configuration import Configuration
4
+ from cosmotech.coal.store.output.channel_interface import (
5
+ ChannelInterface,
6
+ MissingChannelConfigError,
7
+ )
8
+ from cosmotech.coal.utils.configuration import Configuration, Dotdict
6
9
 
7
10
 
8
11
  class AzureStorageChannel(ChannelInterface):
9
12
  required_keys = {
10
- "cosmotech": [
11
- "dataset_absolute_path",
12
- ],
13
+ "coal": ["store"],
13
14
  "azure": [
14
15
  "account_name",
15
16
  "container_name",
@@ -22,20 +23,10 @@ class AzureStorageChannel(ChannelInterface):
22
23
  }
23
24
  requirement_string = required_keys
24
25
 
25
- def __init__(self, dct: dict = None):
26
- self.configuration = Configuration(dct)
27
-
28
- def send(self, tables_filter: Optional[list[str]] = None) -> bool:
26
+ def send(self, filter: Optional[list[str]] = None) -> bool:
29
27
  dump_store_to_azure(
30
- store_folder=self.configuration.cosmotech.dataset_absolute_path,
31
- account_name=self.configuration.azure.account_name,
32
- container_name=self.configuration.azure.container_name,
33
- tenant_id=self.configuration.azure.tenant_id,
34
- client_id=self.configuration.azure.client_id,
35
- client_secret=self.configuration.azure.client_secret,
36
- output_type=self.configuration.azure.output_type,
37
- file_prefix=self.configuration.azure.file_prefix,
38
- selected_tables=tables_filter,
28
+ self.configuration,
29
+ selected_tables=filter,
39
30
  )
40
31
 
41
32
  def delete(self):
@@ -2,11 +2,18 @@ from typing import Optional
2
2
 
3
3
  from cosmotech.orchestrator.utils.translate import T
4
4
 
5
+ from cosmotech.coal.utils.configuration import Configuration, Dotdict
6
+
5
7
 
6
8
  class ChannelInterface:
7
9
  required_keys = {}
8
10
  requirement_string: str = T("coal.store.output.data_interface.requirements")
9
11
 
12
+ def __init__(self, dct: Dotdict = None):
13
+ self.configuration = Configuration(dct)
14
+ if not self.is_available():
15
+ raise MissingChannelConfigError(self)
16
+
10
17
  def send(self, filter: Optional[list[str]] = None) -> bool:
11
18
  raise NotImplementedError()
12
19
 
@@ -21,3 +28,11 @@ class ChannelInterface:
21
28
  )
22
29
  except KeyError:
23
30
  return False
31
+
32
+
33
+ class MissingChannelConfigError(Exception):
34
+ def __init__(self, interface_class):
35
+ self.message = T("coal.store.output.split.requirements").format(
36
+ interface_name=interface_class.__class__.__name__, requirements=interface_class.requirement_string
37
+ )
38
+ super().__init__(self.message)
@@ -6,22 +6,24 @@ from cosmotech.coal.store.output.aws_channel import AwsChannel
6
6
  from cosmotech.coal.store.output.az_storage_channel import AzureStorageChannel
7
7
  from cosmotech.coal.store.output.channel_interface import ChannelInterface
8
8
  from cosmotech.coal.store.output.postgres_channel import PostgresChannel
9
- from cosmotech.coal.utils.configuration import Configuration
9
+ from cosmotech.coal.utils.configuration import Dotdict
10
10
  from cosmotech.coal.utils.logger import LOGGER
11
11
 
12
12
 
13
13
  class ChannelSpliter(ChannelInterface):
14
14
  requirement_string: str = "(Requires any working interface)"
15
- targets = []
15
+ targets = list()
16
16
  available_interfaces: dict[str, ChannelInterface] = {
17
17
  "s3": AwsChannel,
18
18
  "az_storage": AzureStorageChannel,
19
19
  "postgres": PostgresChannel,
20
20
  }
21
21
 
22
- def __init__(self, configuration: Configuration):
23
- self.configuration = configuration
24
- self.targets = []
22
+ def __init__(self, dct: Dotdict = None):
23
+ super().__init__(dct)
24
+ self.targets = list()
25
+ if "outputs" not in self.configuration:
26
+ raise AttributeError(T("coal.store.output.split.no_targets"))
25
27
  for output in self.configuration.outputs:
26
28
  channel = self.available_interfaces[output.type]
27
29
  _i = channel(output.conf)
@@ -43,6 +45,8 @@ class ChannelSpliter(ChannelInterface):
43
45
  any_ok = i.send(filter=filter) or any_ok
44
46
  except Exception:
45
47
  LOGGER.error(T("coal.store.output.split.send.error").format(interface_name=i.__class__.__name__))
48
+ if len(self.targets) < 2:
49
+ raise
46
50
  return any_ok
47
51
 
48
52
  def delete(self, filter: Optional[list[str]] = None) -> bool:
@@ -52,4 +56,6 @@ class ChannelSpliter(ChannelInterface):
52
56
  any_ok = i.delete() or any_ok
53
57
  except Exception:
54
58
  LOGGER.error(T("coal.store.output.split.delete.error").format(interface_name=i.__class__.__name__))
59
+ if len(self.targets) < 2:
60
+ raise
55
61
  return any_ok
@@ -6,15 +6,15 @@ from cosmotech.coal.postgresql.runner import (
6
6
  )
7
7
  from cosmotech.coal.postgresql.store import dump_store_to_postgresql_from_conf
8
8
  from cosmotech.coal.store.output.channel_interface import ChannelInterface
9
- from cosmotech.coal.utils.configuration import Configuration
10
9
 
11
10
 
12
11
  class PostgresChannel(ChannelInterface):
13
12
  required_keys = {
14
- "cosmotech": ["dataset_absolute_path", "organization_id", "workspace_id", "runner_id"],
13
+ "coal": ["store"],
14
+ "cosmotech": ["organization_id", "workspace_id", "runner_id"],
15
15
  "postgres": [
16
16
  "host",
17
- "post",
17
+ "port",
18
18
  "db_name",
19
19
  "db_schema",
20
20
  "user_name",
@@ -23,16 +23,13 @@ class PostgresChannel(ChannelInterface):
23
23
  }
24
24
  requirement_string = required_keys
25
25
 
26
- def __init__(self, dct: dict = None):
27
- self.configuration = Configuration(dct)
28
-
29
- def send(self, tables_filter: Optional[list[str]] = None) -> bool:
26
+ def send(self, filter: Optional[list[str]] = None) -> bool:
30
27
  run_id = send_runner_metadata_to_postgresql(self.configuration)
31
28
  dump_store_to_postgresql_from_conf(
32
- self.configuration,
33
- store_folder=self.configuration.cosmotech.dataset_absolute_path,
34
- selected_tables=tables_filter,
29
+ configuration=self.configuration,
30
+ selected_tables=filter,
35
31
  fk_id=run_id,
32
+ replace=False,
36
33
  )
37
34
 
38
35
  def delete(self):
@@ -5,10 +5,10 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
+ import pandas as pd
8
9
  import pyarrow
9
10
 
10
11
  from cosmotech.coal.store.store import Store
11
- import pandas as pd
12
12
 
13
13
 
14
14
  def store_dataframe(
@@ -5,10 +5,10 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
- from cosmotech.coal.store.store import Store
9
-
10
8
  import pyarrow as pa
11
9
 
10
+ from cosmotech.coal.store.store import Store
11
+
12
12
 
13
13
  def store_table(
14
14
  table_name: str,
@@ -5,14 +5,14 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
- import os
9
8
  import pathlib
10
9
 
11
10
  import pyarrow
12
11
  from adbc_driver_sqlite import dbapi
12
+ from cosmotech.orchestrator.utils.translate import T
13
13
 
14
+ from cosmotech.coal.utils.configuration import Configuration
14
15
  from cosmotech.coal.utils.logger import LOGGER
15
- from cosmotech.orchestrator.utils.translate import T
16
16
 
17
17
 
18
18
  class Store:
@@ -20,11 +20,8 @@ class Store:
20
20
  def sanitize_column(column_name: str) -> str:
21
21
  return column_name.replace(" ", "_")
22
22
 
23
- def __init__(
24
- self,
25
- reset=False,
26
- store_location: pathlib.Path = pathlib.Path(os.environ.get("CSM_PARAMETERS_ABSOLUTE_PATH", ".")),
27
- ):
23
+ def __init__(self, reset=False, configuration: Configuration = Configuration()):
24
+ store_location = configuration.safe_get("coal.store", ".")
28
25
  self.store_location = pathlib.Path(store_location) / ".coal/store"
29
26
  self.store_location.mkdir(parents=True, exist_ok=True)
30
27
  self._tables = dict()
@@ -6,6 +6,10 @@ from cosmotech.orchestrator.utils.translate import T
6
6
  from cosmotech.coal.utils.logger import LOGGER
7
7
 
8
8
 
9
+ class ReferenceKeyError(KeyError):
10
+ pass
11
+
12
+
9
13
  class Dotdict(dict):
10
14
  """dot.notation access to dictionary attributes"""
11
15
 
@@ -17,9 +21,13 @@ class Dotdict(dict):
17
21
  _v = self.__getitem__(key)
18
22
  if isinstance(_v, str) and _v.startswith("$"):
19
23
  _r = self.root
20
- for _p in _v[1:].split("."):
21
- _r = _r[_p]
22
- return _r
24
+ try:
25
+ for _p in _v[1:].split("."):
26
+ _r = _r.__getattr__(_p)
27
+ return _r
28
+ except (KeyError, AttributeError):
29
+ LOGGER.warning(f"dotdict Ref {_v} doesn't exist")
30
+ raise ReferenceKeyError(_v)
23
31
  return _v
24
32
 
25
33
  __delattr__ = dict.__delitem__
@@ -35,48 +43,56 @@ class Dotdict(dict):
35
43
  return data
36
44
 
37
45
  for k, v in dct.items():
38
- self[k] = update(v)
46
+ self.__setattr__(k, update(v))
39
47
 
40
48
  def merge(self, d):
41
49
  for k, v in d.items():
42
50
  if isinstance(v, Dotdict) and k in self:
43
51
  self[k].merge(v)
44
52
  else:
45
- self[k] = v
53
+ # this trigger dict to dotdict conversion at merge
54
+ self.__setattr__(k, v)
46
55
 
47
56
 
48
57
  class Configuration(Dotdict):
49
-
50
- # HARD CODED ENVVAR CONVERSION
51
- CONVERSION_DICT = {
52
- "outputs": [
53
- {
54
- "type": "postgres",
55
- "conf": {
56
- "cosmotech": {
57
- "dataset_absolute_path": "$cosmotech.dataset_absolute_path",
58
- "organization_id": "$cosmotech.organization_id",
59
- "workspace_id": "$cosmotech.workspace_id",
60
- "runner_id": "$cosmotech.runner_id",
61
- },
62
- "postgres": {
63
- "host": "$postgres.host",
64
- "post": "$postgres.post",
65
- "db_name": "$postgres.db_name",
66
- "db_schema": "$postgres.db_schema",
67
- "user_name": "$postgres.user_name",
68
- "user_password": "$postgres.user_password",
69
- },
58
+ # Env var set by the cosmotech api at runtime
59
+ API_ENV_DICT = {
60
+ "secrets": {
61
+ "cosmotech": {
62
+ "twin_cache": {
63
+ "host": "TWIN_CACHE_HOST",
64
+ "port": "TWIN_CACHE_PORT",
65
+ "password": "TWIN_CACHE_PASSWORD",
66
+ "username": "TWIN_CACHE_USERNAME",
67
+ },
68
+ "idp": {
69
+ "base_url": "IDP_BASE_URL",
70
+ "tenant_id": "IDP_TENANT_ID",
71
+ "client_id": "IDP_CLIENT_ID",
72
+ "client_secret": "IDP_CLIENT_SECRET",
70
73
  },
74
+ "api": {"url": "CSM_API_URL", "scope": "CSM_API_SCOPE"},
75
+ "dataset_absolute_path": "CSM_DATASET_ABSOLUTE_PATH",
76
+ "parameters_absolute_path": "CSM_PARAMETERS_ABSOLUTE_PATH",
77
+ "organization_id": "CSM_ORGANIZATION_ID",
78
+ "workspace_id": "CSM_WORKSPACE_ID",
79
+ "runner_id": "CSM_RUNNER_ID",
80
+ "run_id": "CSM_RUN_ID",
81
+ "run_template_id": "CSM_RUN_TEMPLATE_ID",
71
82
  }
72
- ],
83
+ }
84
+ }
85
+ # HARD CODED ENVVAR CONVERSION
86
+ CONVERSION_DICT = {
73
87
  "secrets": {
74
88
  "log_level": "LOG_LEVEL",
75
89
  "s3": {
76
90
  "access_key_id": "AWS_ACCESS_KEY_ID",
77
91
  "endpoint_url": "AWS_ENDPOINT_URL",
78
92
  "secret_access_key": "AWS_SECRET_ACCESS_KEY",
93
+ "bucket_name": "CSM_DATA_BUCKET_NAME",
79
94
  "bucket_prefix": "CSM_DATA_BUCKET_PREFIX",
95
+ "ca_bundle": "CSM_S3_CA_BUNDLE",
80
96
  },
81
97
  "azure": {
82
98
  "account_name": "AZURE_ACCOUNT_NAME",
@@ -87,30 +103,16 @@ class Configuration(Dotdict):
87
103
  "data_explorer_resource_ingest_uri": "AZURE_DATA_EXPLORER_RESOURCE_INGEST_URI",
88
104
  "data_explorer_resource_uri": "AZURE_DATA_EXPLORER_RESOURCE_URI",
89
105
  "storage_blob_name": "AZURE_STORAGE_BLOB_NAME",
106
+ "data_blob_prefix": "CSM_DATA_BLOB_PREFIX",
107
+ "data_prefix": "CSM_DATA_PREFIX",
90
108
  "storage_sas_url": "AZURE_STORAGE_SAS_URL",
91
109
  "tenant_id": "AZURE_TENANT_ID",
92
110
  },
93
111
  "cosmotech": {
94
- "api_url": "CSM_API_URL",
95
- "container_mode": "CSM_CONTAINER_MODE",
96
112
  "data_adx_tag": "CSM_DATA_ADX_TAG",
97
113
  "data_adx_wait_ingestion": "CSM_DATA_ADX_WAIT_INGESTION",
98
- "data_blob_prefix": "CSM_DATA_BLOB_PREFIX",
99
- "data_bucket_name": "CSM_DATA_BUCKET_NAME",
100
- "data_prefix": "CSM_DATA_PREFIX",
101
- "dataset_absolute_path": "CSM_DATASET_ABSOLUTE_PATH",
102
- "organization_id": "CSM_ORGANIZATION_ID",
103
- "parameters_absolute_path": "CSM_PARAMETERS_ABSOLUTE_PATH",
104
- "run_id": "CSM_RUN_ID",
105
- "runner_id": "CSM_RUNNER_ID",
106
- "run_template_id": "CSM_RUN_TEMPLATE_ID",
107
- "s3_ca_bundle": "CSM_S3_CA_BUNDLE",
108
- "scenario_id": "CSM_SCENARIO_ID",
109
114
  "send_datawarehouse_datasets": "CSM_SEND_DATAWAREHOUSE_DATASETS",
110
115
  "send_datawarehouse_parameters": "CSM_SEND_DATAWAREHOUSE_PARAMETERS",
111
- "workspace_id": "CSM_WORKSPACE_ID",
112
- "fetch_dataset": "FETCH_DATASET",
113
- "fetch_datasets_in_parallel": "FETCH_DATASETS_IN_PARALLEL",
114
116
  },
115
117
  "postgres": {
116
118
  "db_name": "POSTGRES_DB_NAME",
@@ -132,38 +134,64 @@ class Configuration(Dotdict):
132
134
  },
133
135
  }
134
136
 
137
+ # HARD CODED configmap mount path set in K8s simulation pod by API run function
138
+ K8S_CONFIG = "/mnt/coal/coal-config.toml"
139
+
135
140
  def __init__(self, dct: dict = None):
136
- if dct:
141
+ if isinstance(dct, Dotdict):
142
+ super().__init__(dct, root=dct.root)
143
+ elif isinstance(dct, dict):
137
144
  super().__init__(dct)
138
145
  elif config_path := os.environ.get("CONFIG_FILE_PATH", default=None):
139
- with open(config_path, "rb") as f:
140
- super().__init__(tomllib.load(f))
146
+ with open(config_path, "rb") as config:
147
+ super().__init__(tomllib.load(config))
148
+ elif os.path.isfile(self.K8S_CONFIG):
149
+ with open(self.K8S_CONFIG, "rb") as config:
150
+ super().__init__(tomllib.load(config))
141
151
  else:
142
152
  LOGGER.info(T("coal.utils.configuration.no_config_file"))
143
153
  super().__init__(self.CONVERSION_DICT)
144
154
 
155
+ # add envvar set by the API
156
+ self.merge(Dotdict(self.API_ENV_DICT))
157
+
145
158
  if "secrets" in self:
146
159
  self.secrets = self._env_swap_recusion(self.secrets)
147
160
  # set secret section back to respective section
148
161
  self.merge(self.secrets)
149
162
  del self.secrets
150
163
 
164
+ # add coal.store default value if ont define
165
+ if self.safe_get("coal.store") is None:
166
+ self.merge({"coal": {"store": "$cosmotech.parameters_absolute_path"}})
167
+
151
168
  # convert value to env
152
169
  def _env_swap_recusion(self, dic):
153
170
  for k, v in dic.items():
154
171
  if isinstance(v, Dotdict):
155
172
  dic[k] = self._env_swap_recusion(v)
156
- # remove value not found
157
173
  dic[k] = {k: v for k, v in dic[k].items() if v is not None}
158
174
  elif isinstance(v, list):
159
175
  dic[k] = list(self._env_swap_recusion(_v) for _v in v)
160
176
  elif isinstance(v, str):
161
177
  dic[k] = os.environ.get(v)
178
+ # remove value not found
179
+ dic = {k: v for k, v in dic.items() if v}
162
180
  return dic
163
181
 
164
182
  def merge_in(self, dic):
165
183
  trans_dic = self._env_swap_recusion(dic)
166
- self._merge(trans_dic)
184
+ self.merge(trans_dic)
185
+
186
+ def safe_get(self, key, default=None):
187
+ try:
188
+ _r = self
189
+ for _k in key.split("."):
190
+ _r = _r.__getattr__(_k)
191
+ return _r
192
+ except (KeyError, AttributeError) as err:
193
+ LOGGER.debug(f"{err} not found; returning {default}")
194
+ return default
167
195
 
168
196
 
169
197
  ENVIRONMENT_CONFIGURATION = Configuration()
@@ -7,7 +7,7 @@
7
7
  from cosmotech.orchestrator.utils.translate import T
8
8
 
9
9
  from cosmotech.csm_data.utils.click import click
10
- from cosmotech.csm_data.utils.decorators import web_help, translate_help
10
+ from cosmotech.csm_data.utils.decorators import translate_help, web_help
11
11
 
12
12
 
13
13
  @click.command()
@@ -5,10 +5,11 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
- from cosmotech.csm_data.utils.click import click
9
- from cosmotech.csm_data.utils.decorators import web_help, translate_help
10
8
  from cosmotech.orchestrator.utils.translate import T
11
9
 
10
+ from cosmotech.csm_data.utils.click import click
11
+ from cosmotech.csm_data.utils.decorators import translate_help, web_help
12
+
12
13
 
13
14
  @click.command()
14
15
  @web_help("csm-data/adx-send-runner-data")
@@ -7,6 +7,7 @@
7
7
 
8
8
  from cosmotech.orchestrator.utils.translate import T
9
9
 
10
+ from cosmotech.coal.utils.configuration import Configuration
10
11
  from cosmotech.csm_data.utils.click import click
11
12
  from cosmotech.csm_data.utils.decorators import require_env, translate_help, web_help
12
13
 
@@ -66,15 +67,16 @@ def run_load_data(
66
67
  # Import the function at the start of the command
67
68
  from cosmotech.coal.cosmotech_api.apis.runner import RunnerApi
68
69
 
69
- _r = RunnerApi()
70
+ _configuration = Configuration()
71
+ _configuration.cosmotech.organization_id = organization_id
72
+ _configuration.cosmotech.workspace_id = workspace_id
73
+ _configuration.cosmotech.runner_id = runner_id
74
+ _configuration.cosmotech.parameters_absolute_path = parameters_absolute_path
75
+ _configuration.cosmotech.dataset_absolute_path = dataset_absolute_path
70
76
 
71
- return _r.download_runner_data(
72
- organization_id=organization_id,
73
- workspace_id=workspace_id,
74
- runner_id=runner_id,
75
- parameter_folder=parameters_absolute_path,
76
- dataset_folder=dataset_absolute_path,
77
- )
77
+ _r = RunnerApi(_configuration)
78
+
79
+ return _r.download_runner_data(download_datasets=True)
78
80
 
79
81
 
80
82
  if __name__ == "__main__":
@@ -5,10 +5,11 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
- from cosmotech.csm_data.utils.click import click
9
- from cosmotech.csm_data.utils.decorators import web_help, translate_help
10
8
  from cosmotech.orchestrator.utils.translate import T
11
9
 
10
+ from cosmotech.csm_data.utils.click import click
11
+ from cosmotech.csm_data.utils.decorators import translate_help, web_help
12
+
12
13
 
13
14
  @click.command()
14
15
  @click.option(
@@ -5,10 +5,11 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
- from cosmotech.csm_data.utils.click import click
9
- from cosmotech.csm_data.utils.decorators import web_help, translate_help
10
8
  from cosmotech.orchestrator.utils.translate import T
11
9
 
10
+ from cosmotech.csm_data.utils.click import click
11
+ from cosmotech.csm_data.utils.decorators import translate_help, web_help
12
+
12
13
  VALID_TYPES = (
13
14
  "sqlite",
14
15
  "csv",
@@ -5,10 +5,11 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
- from cosmotech.csm_data.utils.click import click
9
- from cosmotech.csm_data.utils.decorators import web_help, translate_help
10
8
  from cosmotech.orchestrator.utils.translate import T
11
9
 
10
+ from cosmotech.csm_data.utils.click import click
11
+ from cosmotech.csm_data.utils.decorators import translate_help, web_help
12
+
12
13
 
13
14
  @click.command()
14
15
  @web_help("csm-data/store/dump-to-postgres")
@@ -5,10 +5,11 @@
5
5
  # etc., to any person is prohibited unless it has been previously and
6
6
  # specifically authorized by written means by Cosmo Tech.
7
7
 
8
- from cosmotech.csm_data.utils.click import click
9
- from cosmotech.csm_data.utils.decorators import web_help, translate_help
10
8
  from cosmotech.orchestrator.utils.translate import T
11
9
 
10
+ from cosmotech.csm_data.utils.click import click
11
+ from cosmotech.csm_data.utils.decorators import translate_help, web_help
12
+
12
13
 
13
14
  @click.command()
14
15
  @web_help("csm-data/store/list-tables")