digitalhub 0.10.0b2__py3-none-any.whl → 0.10.0b4__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.

Potentially problematic release.


This version of digitalhub might be problematic. Click here for more details.

Files changed (50) hide show
  1. digitalhub/entities/_base/entity/builder.py +5 -5
  2. digitalhub/entities/_base/material/entity.py +4 -17
  3. digitalhub/entities/_base/material/status.py +1 -1
  4. digitalhub/entities/_commons/models.py +7 -3
  5. digitalhub/entities/_commons/utils.py +5 -4
  6. digitalhub/entities/_operations/processor.py +5 -4
  7. digitalhub/entities/artifact/artifact/spec.py +3 -1
  8. digitalhub/entities/artifact/crud.py +3 -2
  9. digitalhub/entities/builders.py +6 -18
  10. digitalhub/entities/dataitem/crud.py +17 -5
  11. digitalhub/entities/dataitem/table/models.py +4 -3
  12. digitalhub/entities/dataitem/table/utils.py +7 -7
  13. digitalhub/entities/dataitem/utils.py +50 -6
  14. digitalhub/entities/model/_base/spec.py +6 -7
  15. digitalhub/entities/model/crud.py +3 -2
  16. digitalhub/entities/model/huggingface/spec.py +4 -2
  17. digitalhub/entities/model/mlflow/spec.py +6 -4
  18. digitalhub/entities/project/_base/spec.py +8 -6
  19. digitalhub/entities/project/crud.py +2 -2
  20. digitalhub/entities/run/_base/spec.py +4 -2
  21. digitalhub/entities/secret/_base/spec.py +4 -2
  22. digitalhub/entities/secret/crud.py +2 -0
  23. digitalhub/entities/task/_base/models.py +41 -40
  24. digitalhub/entities/task/_base/utils.py +2 -2
  25. digitalhub/stores/_base/store.py +5 -4
  26. digitalhub/stores/local/store.py +4 -3
  27. digitalhub/stores/remote/store.py +4 -3
  28. digitalhub/stores/s3/store.py +5 -4
  29. digitalhub/stores/sql/configurator.py +4 -4
  30. digitalhub/stores/sql/enums.py +1 -1
  31. digitalhub/stores/sql/store.py +7 -3
  32. digitalhub/utils/file_utils.py +8 -7
  33. digitalhub/utils/generic_utils.py +20 -8
  34. digitalhub/utils/types.py +6 -0
  35. digitalhub/utils/uri_utils.py +1 -1
  36. {digitalhub-0.10.0b2.dist-info → digitalhub-0.10.0b4.dist-info}/METADATA +27 -33
  37. {digitalhub-0.10.0b2.dist-info → digitalhub-0.10.0b4.dist-info}/RECORD +39 -49
  38. {digitalhub-0.10.0b2.dist-info → digitalhub-0.10.0b4.dist-info}/WHEEL +1 -2
  39. digitalhub-0.10.0b2.dist-info/top_level.txt +0 -2
  40. test/local/CRUD/test_artifacts.py +0 -96
  41. test/local/CRUD/test_dataitems.py +0 -96
  42. test/local/CRUD/test_models.py +0 -95
  43. test/local/imports/test_imports.py +0 -65
  44. test/local/instances/test_validate.py +0 -55
  45. test/test_crud_functions.py +0 -109
  46. test/test_crud_runs.py +0 -86
  47. test/test_crud_tasks.py +0 -81
  48. test/testkfp.py +0 -37
  49. test/testkfp_pipeline.py +0 -22
  50. {digitalhub-0.10.0b2.dist-info → digitalhub-0.10.0b4.dist-info/licenses}/LICENSE.txt +0 -0
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing import Optional
4
+
3
5
  from digitalhub.entities._base.entity.spec import Spec, SpecValidator
4
6
 
5
7
 
@@ -31,20 +33,20 @@ class ProjectValidator(SpecValidator):
31
33
  ProjectValidator validator.
32
34
  """
33
35
 
34
- context: str = None
36
+ context: Optional[str] = None
35
37
  """The project's context."""
36
38
 
37
- functions: list = None
39
+ functions: Optional[list] = None
38
40
  """List of project's functions."""
39
41
 
40
- artifacts: list = None
42
+ artifacts: Optional[list] = None
41
43
  """List of project's artifacts."""
42
44
 
43
- workflows: list = None
45
+ workflows: Optional[list] = None
44
46
  """List of project's workflows."""
45
47
 
46
- dataitems: list = None
48
+ dataitems: Optional[list] = None
47
49
  """List of project's dataitems."""
48
50
 
49
- models: list = None
51
+ models: Optional[list] = None
50
52
  """List of project's models."""
@@ -272,7 +272,7 @@ def update_project(entity: Project, **kwargs) -> Project:
272
272
  entity_type=entity.ENTITY_TYPE,
273
273
  entity_name=entity.name,
274
274
  entity_dict=entity.to_dict(),
275
- local=entity.local,
275
+ local=entity._client.is_local(),
276
276
  **kwargs,
277
277
  )
278
278
 
@@ -283,7 +283,7 @@ def delete_project(
283
283
  clean_context: bool = True,
284
284
  local: bool = False,
285
285
  **kwargs,
286
- ) -> list[dict]:
286
+ ) -> dict:
287
287
  """
288
288
  Delete a project.
289
289
 
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing import Optional
4
+
3
5
  from digitalhub.entities._base.entity.spec import Spec, SpecValidator
4
6
  from digitalhub.entities.task._base.models import K8s
5
7
 
@@ -47,8 +49,8 @@ class RunValidator(SpecValidator, K8s):
47
49
  """
48
50
 
49
51
  # Task parameters
50
- function: str = None
51
- workflow: str = None
52
+ function: Optional[str] = None
53
+ workflow: Optional[str] = None
52
54
 
53
55
  # Run parameters
54
56
  task: str
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing import Optional
4
+
3
5
  from digitalhub.entities._base.entity.spec import Spec, SpecValidator
4
6
 
5
7
 
@@ -28,8 +30,8 @@ class SecretValidator(SpecValidator):
28
30
  SecretValidator validator.
29
31
  """
30
32
 
31
- path: str = None
33
+ path: Optional[str] = None
32
34
  """Path to the secret."""
33
35
 
34
- provider: str = None
36
+ provider: Optional[str] = None
35
37
  """Provider of the secret."""
@@ -108,6 +108,8 @@ def get_secret(
108
108
  >>> entity_id="my-secret-id")
109
109
  """
110
110
  if not identifier.startswith("store://"):
111
+ if project is None:
112
+ raise ValueError("Project must be provided.")
111
113
  secrets = list_secrets(project=project, **kwargs)
112
114
  for secret in secrets:
113
115
  if secret.name == identifier:
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from enum import Enum
4
+ from typing import Optional
4
5
 
5
6
  from pydantic import BaseModel, ConfigDict, Field
6
7
 
@@ -30,7 +31,7 @@ class Volume(BaseModel):
30
31
  mount_path: str
31
32
  """Volume mount path inside the container."""
32
33
 
33
- spec: dict[str, str] = None
34
+ spec: Optional[dict[str, str]] = None
34
35
  """Volume spec."""
35
36
 
36
37
 
@@ -63,13 +64,13 @@ class Resource(BaseModel):
63
64
  Resource model.
64
65
  """
65
66
 
66
- cpu: ResourceItem = None
67
+ cpu: Optional[ResourceItem] = None
67
68
  """CPU resource model."""
68
69
 
69
- mem: ResourceItem = None
70
+ mem: Optional[ResourceItem] = None
70
71
  """Memory resource model."""
71
72
 
72
- gpu: ResourceItem = None
73
+ gpu: Optional[ResourceItem] = None
73
74
  """GPU resource model."""
74
75
 
75
76
 
@@ -90,31 +91,31 @@ class Toleration(BaseModel):
90
91
  Toleration model.
91
92
  """
92
93
 
93
- key: str = None
94
+ key: Optional[str] = None
94
95
  """Toleration key."""
95
96
 
96
- operator: str = None
97
+ operator: Optional[str] = None
97
98
  """Toleration operator."""
98
99
 
99
- value: str = None
100
+ value: Optional[str] = None
100
101
  """Toleration value."""
101
102
 
102
- effect: str = None
103
+ effect: Optional[str] = None
103
104
  """Toleration effect."""
104
105
 
105
- toleration_seconds: int = None
106
+ toleration_seconds: Optional[int] = None
106
107
  """Toleration seconds."""
107
108
 
108
109
 
109
110
  class V1NodeSelectorRequirement(BaseModel):
110
111
  key: str
111
112
  operator: str
112
- values: list[str] = None
113
+ values: Optional[list[str]] = None
113
114
 
114
115
 
115
116
  class V1NodeSelectorTerm(BaseModel):
116
- match_expressions: list[V1NodeSelectorRequirement] = None
117
- match_fields: list[V1NodeSelectorRequirement] = None
117
+ match_expressions: Optional[list[V1NodeSelectorRequirement]] = None
118
+ match_fields: Optional[list[V1NodeSelectorRequirement]] = None
118
119
 
119
120
 
120
121
  class V1NodeSelector(BaseModel):
@@ -129,21 +130,21 @@ class V1PreferredSchedulingTerm(BaseModel):
129
130
  class V1LabelSelectorRequirement(BaseModel):
130
131
  key: str
131
132
  operator: str
132
- values: list[str] = None
133
+ values: Optional[list[str]] = None
133
134
 
134
135
 
135
136
  class V1LabelSelector(BaseModel):
136
- match_expressions: list[V1LabelSelectorRequirement] = None
137
- match_labels: dict[str, str] = None
137
+ match_expressions: Optional[list[V1LabelSelectorRequirement]] = None
138
+ match_labels: Optional[dict[str, str]] = None
138
139
 
139
140
 
140
141
  class V1PodAffinityTerm(BaseModel):
141
- label_selector: V1LabelSelector = None
142
- match_label_keys: list[str] = None
143
- mismatch_label_keys: list[str] = None
144
- namespace_selector: V1LabelSelector = None
145
- namespaces: list[str] = None
146
- topology_key: str
142
+ label_selector: Optional[V1LabelSelector] = None
143
+ match_label_keys: Optional[list[str]] = None
144
+ mismatch_label_keys: Optional[list[str]] = None
145
+ namespace_selector: Optional[V1LabelSelector] = None
146
+ namespaces: Optional[list[str]] = None
147
+ topology_key: Optional[str] = None
147
148
 
148
149
 
149
150
  class V1WeightedPodAffinityTerm(BaseModel):
@@ -152,18 +153,18 @@ class V1WeightedPodAffinityTerm(BaseModel):
152
153
 
153
154
 
154
155
  class V1NodeAffinity(BaseModel):
155
- preferred_during_scheduling_ignored_during_execution: list[V1PreferredSchedulingTerm] = None
156
- required_during_scheduling_ignored_during_execution: V1NodeSelector = None
156
+ preferred_during_scheduling_ignored_during_execution: Optional[list[V1PreferredSchedulingTerm]] = None
157
+ required_during_scheduling_ignored_during_execution: Optional[V1NodeSelector] = None
157
158
 
158
159
 
159
160
  class V1PodAffinity(BaseModel):
160
- preferred_during_scheduling_ignored_during_execution: list[V1WeightedPodAffinityTerm] = None
161
- required_during_scheduling_ignored_during_execution: list[V1PodAffinityTerm] = None
161
+ preferred_during_scheduling_ignored_during_execution: Optional[list[V1WeightedPodAffinityTerm]] = None
162
+ required_during_scheduling_ignored_during_execution: Optional[list[V1PodAffinityTerm]] = None
162
163
 
163
164
 
164
165
  class V1PodAntiAffinity(BaseModel):
165
- preferred_during_scheduling_ignored_during_execution: list[V1WeightedPodAffinityTerm] = None
166
- required_during_scheduling_ignored_during_execution: list[V1PodAffinityTerm] = None
166
+ preferred_during_scheduling_ignored_during_execution: Optional[list[V1WeightedPodAffinityTerm]] = None
167
+ required_during_scheduling_ignored_during_execution: Optional[list[V1PodAffinityTerm]] = None
167
168
 
168
169
 
169
170
  class Affinity(BaseModel):
@@ -171,13 +172,13 @@ class Affinity(BaseModel):
171
172
  Affinity model.
172
173
  """
173
174
 
174
- node_affinity: V1NodeAffinity = None
175
+ node_affinity: Optional[V1NodeAffinity] = None
175
176
  """Node affinity."""
176
177
 
177
- pod_affinity: V1PodAffinity = None
178
+ pod_affinity: Optional[V1PodAffinity] = None
178
179
  """Pod affinity."""
179
180
 
180
- pod_anti_affinity: V1PodAntiAffinity = None
181
+ pod_anti_affinity: Optional[V1PodAntiAffinity] = None
181
182
  """Pod anti affinity."""
182
183
 
183
184
 
@@ -186,34 +187,34 @@ class K8s(BaseModel):
186
187
  Kubernetes resource model.
187
188
  """
188
189
 
189
- node_selector: list[NodeSelector] = None
190
+ node_selector: Optional[list[NodeSelector]] = None
190
191
  """Node selector."""
191
192
 
192
- volumes: list[Volume] = None
193
+ volumes: Optional[list[Volume]] = None
193
194
  """List of volumes."""
194
195
 
195
- resources: Resource = None
196
+ resources: Optional[Resource] = None
196
197
  """Resources restrictions."""
197
198
 
198
- affinity: Affinity = None
199
+ affinity: Optional[Affinity] = None
199
200
  """Affinity."""
200
201
 
201
- tolerations: list[Toleration] = None
202
+ tolerations: Optional[list[Toleration]] = None
202
203
  """Tolerations."""
203
204
 
204
- envs: list[Env] = None
205
+ envs: Optional[list[Env]] = None
205
206
  """Env variables."""
206
207
 
207
- secrets: list[str] = None
208
+ secrets: Optional[list[str]] = None
208
209
  """List of secret names."""
209
210
 
210
- profile: str = None
211
+ profile: Optional[str] = None
211
212
  """Profile template."""
212
213
 
213
- runtime_class: str = None
214
+ runtime_class: Optional[str] = None
214
215
  """Runtime class name."""
215
216
 
216
- priority_class: str = None
217
+ priority_class: Optional[str] = None
217
218
  """Priority class."""
218
219
 
219
220
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
 
4
- def build_task_actions(kind_action_list: list[tuple[str, str]]) -> dict[str, str]:
4
+ def build_task_actions(kind_action_list: list[tuple[str, str]]) -> list[dict[str, str]]:
5
5
  """
6
6
  Build task actions.
7
7
 
@@ -12,7 +12,7 @@ def build_task_actions(kind_action_list: list[tuple[str, str]]) -> dict[str, str
12
12
 
13
13
  Returns
14
14
  -------
15
- dict[str, str]
15
+ list[dict[str, str]]
16
16
  Returns the task actions.
17
17
  """
18
18
  return [{"kind": kind, "action": action} for (kind, action) in kind_action_list]
@@ -8,6 +8,7 @@ from typing import Any
8
8
 
9
9
  from digitalhub.readers.data.api import get_reader_by_engine
10
10
  from digitalhub.utils.exceptions import StoreError
11
+ from digitalhub.utils.types import SourcesOrListOfSources
11
12
  from digitalhub.utils.uri_utils import has_local_scheme
12
13
 
13
14
  if typing.TYPE_CHECKING:
@@ -36,7 +37,7 @@ class Store:
36
37
  """
37
38
 
38
39
  @abstractmethod
39
- def upload(self, src: str | list[str], dst: str) -> list[tuple[str, str]]:
40
+ def upload(self, src: SourcesOrListOfSources, dst: str) -> list[tuple[str, str]]:
40
41
  """
41
42
  Method to upload artifact to storage.
42
43
  """
@@ -58,8 +59,8 @@ class Store:
58
59
  @abstractmethod
59
60
  def read_df(
60
61
  self,
61
- path: str | list[str],
62
- extension: str,
62
+ path: SourcesOrListOfSources,
63
+ file_format: str | None = None,
63
64
  engine: str | None = None,
64
65
  **kwargs,
65
66
  ) -> Any:
@@ -159,7 +160,7 @@ class Store:
159
160
 
160
161
  Parameters
161
162
  ----------
162
- path : str
163
+ path : str | Path
163
164
  The path to build.
164
165
 
165
166
  Returns
@@ -8,6 +8,7 @@ from digitalhub.readers.data.api import get_reader_by_object
8
8
  from digitalhub.stores._base.store import Store
9
9
  from digitalhub.utils.exceptions import StoreError
10
10
  from digitalhub.utils.file_utils import get_file_info_from_local
11
+ from digitalhub.utils.types import SourcesOrListOfSources
11
12
 
12
13
 
13
14
  class LocalStore(Store):
@@ -51,7 +52,7 @@ class LocalStore(Store):
51
52
  """
52
53
  raise StoreError("Local store does not support download.")
53
54
 
54
- def upload(self, src: str | list[str], dst: str) -> list[tuple[str, str]]:
55
+ def upload(self, src: SourcesOrListOfSources, dst: str) -> list[tuple[str, str]]:
55
56
  """
56
57
  Upload an artifact to storage.
57
58
 
@@ -88,7 +89,7 @@ class LocalStore(Store):
88
89
 
89
90
  def read_df(
90
91
  self,
91
- path: str | list[str],
92
+ path: SourcesOrListOfSources,
92
93
  file_format: str | None = None,
93
94
  engine: str | None = None,
94
95
  **kwargs,
@@ -98,7 +99,7 @@ class LocalStore(Store):
98
99
 
99
100
  Parameters
100
101
  ----------
101
- path : str | list[str]
102
+ path : SourcesOrListOfSources
102
103
  Path(s) to read DataFrame from.
103
104
  file_format : str
104
105
  Extension of the file.
@@ -7,6 +7,7 @@ import requests
7
7
 
8
8
  from digitalhub.stores._base.store import Store
9
9
  from digitalhub.utils.exceptions import StoreError
10
+ from digitalhub.utils.types import SourcesOrListOfSources
10
11
 
11
12
 
12
13
  class RemoteStore(Store):
@@ -62,7 +63,7 @@ class RemoteStore(Store):
62
63
 
63
64
  return self._download_file(root, dst, overwrite)
64
65
 
65
- def upload(self, src: str | list[str], dst: str) -> list[tuple[str, str]]:
66
+ def upload(self, src: SourcesOrListOfSources, dst: str) -> list[tuple[str, str]]:
66
67
  """
67
68
  Upload an artifact to storage.
68
69
 
@@ -99,7 +100,7 @@ class RemoteStore(Store):
99
100
 
100
101
  def read_df(
101
102
  self,
102
- path: str | list[str],
103
+ path: SourcesOrListOfSources,
103
104
  file_format: str | None = None,
104
105
  engine: str | None = None,
105
106
  **kwargs,
@@ -109,7 +110,7 @@ class RemoteStore(Store):
109
110
 
110
111
  Parameters
111
112
  ----------
112
- path : str | list[str]
113
+ path : SourcesOrListOfSources
113
114
  Path(s) to read DataFrame from.
114
115
  file_format : str
115
116
  Extension of the file.
@@ -16,6 +16,7 @@ from digitalhub.stores.s3.configurator import S3StoreConfigurator
16
16
  from digitalhub.stores.s3.utils import get_bucket_name
17
17
  from digitalhub.utils.exceptions import StoreError
18
18
  from digitalhub.utils.file_utils import get_file_info_from_s3, get_file_mime_type
19
+ from digitalhub.utils.types import SourcesOrListOfSources
19
20
 
20
21
  if typing.TYPE_CHECKING:
21
22
  pass
@@ -117,7 +118,7 @@ class S3Store(Store):
117
118
 
118
119
  def upload(
119
120
  self,
120
- src: str | list[str],
121
+ src: SourcesOrListOfSources,
121
122
  dst: str,
122
123
  ) -> list[tuple[str, str]]:
123
124
  """
@@ -125,7 +126,7 @@ class S3Store(Store):
125
126
 
126
127
  Parameters
127
128
  ----------
128
- src : str | list[str]
129
+ src : SourcesOrListOfSources
129
130
  Source(s).
130
131
  dst : str
131
132
  The destination of the artifact on storage.
@@ -238,7 +239,7 @@ class S3Store(Store):
238
239
 
239
240
  def read_df(
240
241
  self,
241
- path: str | list[str],
242
+ path: SourcesOrListOfSources,
242
243
  file_format: str | None = None,
243
244
  engine: str | None = None,
244
245
  **kwargs,
@@ -248,7 +249,7 @@ class S3Store(Store):
248
249
 
249
250
  Parameters
250
251
  ----------
251
- path : str | list[str]
252
+ path : SourcesOrListOfSources
252
253
  Path(s) to read DataFrame from.
253
254
  file_format : str
254
255
  Extension of the file.
@@ -38,7 +38,7 @@ class SqlStoreConfigurator:
38
38
  else:
39
39
  config: SqlStoreConfig = SqlStoreConfig(**config)
40
40
  for pair in [
41
- (SqlStoreEnv.USER.value, config.user),
41
+ (SqlStoreEnv.USERNAME.value, config.user),
42
42
  (SqlStoreEnv.PASSWORD.value, config.password),
43
43
  (SqlStoreEnv.HOST.value, config.host),
44
44
  (SqlStoreEnv.PORT.value, config.port),
@@ -57,7 +57,7 @@ class SqlStoreConfigurator:
57
57
  """
58
58
  creds = configurator.get_all_cred()
59
59
  try:
60
- user = creds[SqlStoreEnv.USER.value]
60
+ user = creds[SqlStoreEnv.USERNAME.value]
61
61
  password = creds[SqlStoreEnv.PASSWORD.value]
62
62
  host = creds[SqlStoreEnv.HOST.value]
63
63
  port = creds[SqlStoreEnv.PORT.value]
@@ -74,14 +74,14 @@ class SqlStoreConfigurator:
74
74
  -------
75
75
  None
76
76
  """
77
- user = configurator.load_var(SqlStoreEnv.USER.value)
77
+ user = configurator.load_var(SqlStoreEnv.USERNAME.value)
78
78
  password = configurator.load_var(SqlStoreEnv.PASSWORD.value)
79
79
  host = configurator.load_var(SqlStoreEnv.HOST.value)
80
80
  port = configurator.load_var(SqlStoreEnv.PORT.value)
81
81
  database = configurator.load_var(SqlStoreEnv.DATABASE.value)
82
82
  if user is None or password is None or host is None or port is None or database is None:
83
83
  raise StoreError("Missing credentials for SQL store.")
84
- configurator.set_credential(SqlStoreEnv.USER.value, user)
84
+ configurator.set_credential(SqlStoreEnv.USERNAME.value, user)
85
85
  configurator.set_credential(SqlStoreEnv.PASSWORD.value, password)
86
86
  configurator.set_credential(SqlStoreEnv.HOST.value, host)
87
87
  configurator.set_credential(SqlStoreEnv.PORT.value, port)
@@ -10,7 +10,7 @@ class SqlStoreEnv(Enum):
10
10
 
11
11
  HOST = "DB_HOST"
12
12
  PORT = "DB_PORT"
13
- USER = "DB_USER"
13
+ USERNAME = "DB_USERNAME"
14
14
  PASSWORD = "DB_PASSWORD"
15
15
  DATABASE = "DB_DATABASE"
16
16
  PG_SCHEMA = "DB_SCHEMA"
@@ -14,6 +14,7 @@ from digitalhub.readers.data.api import get_reader_by_object
14
14
  from digitalhub.stores._base.store import Store
15
15
  from digitalhub.stores.sql.configurator import SqlStoreConfigurator
16
16
  from digitalhub.utils.exceptions import StoreError
17
+ from digitalhub.utils.types import SourcesOrListOfSources
17
18
 
18
19
  if typing.TYPE_CHECKING:
19
20
  from sqlalchemy.engine.row import Row
@@ -85,7 +86,7 @@ class SqlStore(Store):
85
86
 
86
87
  def upload(
87
88
  self,
88
- src: str | list[str],
89
+ src: SourcesOrListOfSources,
89
90
  dst: str,
90
91
  ) -> list[tuple[str, str]]:
91
92
  """
@@ -124,7 +125,7 @@ class SqlStore(Store):
124
125
 
125
126
  def read_df(
126
127
  self,
127
- path: str | list[str],
128
+ path: SourcesOrListOfSources,
128
129
  file_format: str | None = None,
129
130
  engine: str | None = None,
130
131
  **kwargs,
@@ -134,7 +135,7 @@ class SqlStore(Store):
134
135
 
135
136
  Parameters
136
137
  ----------
137
- path : str | list[str]
138
+ path : SourcesOrListOfSources
138
139
  Path(s) to read DataFrame from.
139
140
  file_format : str
140
141
  Extension of the file.
@@ -148,6 +149,9 @@ class SqlStore(Store):
148
149
  Any
149
150
  DataFrame.
150
151
  """
152
+ if isinstance(path, list):
153
+ raise StoreError("SQL store can only read a single DataFrame at a time.")
154
+
151
155
  reader = self._get_reader(engine)
152
156
  schema = self._get_schema(path)
153
157
  table = self._get_table_name(path)
@@ -4,6 +4,7 @@ from datetime import datetime
4
4
  from hashlib import sha256
5
5
  from mimetypes import guess_type
6
6
  from pathlib import Path
7
+ from typing import Optional
7
8
 
8
9
  from pydantic import BaseModel
9
10
 
@@ -13,12 +14,12 @@ class FileInfo(BaseModel):
13
14
  File info class.
14
15
  """
15
16
 
16
- path: str = None
17
- name: str = None
18
- content_type: str = None
19
- size: int = None
20
- hash: str = None
21
- last_modified: str = None
17
+ path: Optional[str] = None
18
+ name: Optional[str] = None
19
+ content_type: Optional[str] = None
20
+ size: Optional[int] = None
21
+ hash: Optional[str] = None
22
+ last_modified: Optional[str] = None
22
23
 
23
24
  def to_dict(self):
24
25
  return self.model_dump()
@@ -60,7 +61,7 @@ def get_file_size(data_path: str) -> int:
60
61
  return Path(data_path).stat().st_size
61
62
 
62
63
 
63
- def get_file_mime_type(data_path: str) -> str:
64
+ def get_file_mime_type(data_path: str) -> str | None:
64
65
  """
65
66
  Get the mime type of a file.
66
67
 
@@ -4,8 +4,9 @@ import base64
4
4
  import importlib.util as imputil
5
5
  import json
6
6
  from datetime import date, datetime, time
7
- from enum import Enum
7
+ from enum import Enum, EnumMeta
8
8
  from pathlib import Path
9
+ from types import MappingProxyType
9
10
  from typing import Any, Callable
10
11
  from zipfile import ZipFile
11
12
 
@@ -166,7 +167,7 @@ def dump_json(struct: Any) -> str:
166
167
  str
167
168
  The json string.
168
169
  """
169
- return json.dumps(struct, cls=CustomJsonEncoder).encode("utf-8")
170
+ return json.dumps(struct, cls=CustomJsonEncoder)
170
171
 
171
172
 
172
173
  def slugify_string(filename: str) -> str:
@@ -203,23 +204,34 @@ def import_function(path: Path, handler: str) -> Callable:
203
204
  Function.
204
205
  """
205
206
  spec = imputil.spec_from_file_location(path.stem, path)
207
+ if spec is None:
208
+ raise RuntimeError(f"Error loading function source from {str(path)}.")
209
+
206
210
  mod = imputil.module_from_spec(spec)
211
+ if spec.loader is None:
212
+ raise RuntimeError(f"Error getting module loader from {str(path)}.")
213
+
207
214
  spec.loader.exec_module(mod)
208
- return getattr(mod, handler)
215
+ func = getattr(mod, handler)
216
+ if not callable(func):
217
+ raise RuntimeError(f"Handler '{handler}' is not a callable.")
218
+
219
+ return func
209
220
 
210
221
 
211
- def list_enum(enum: Enum) -> list:
222
+ def list_enum(enum: EnumMeta) -> list[Any]:
212
223
  """
213
224
  Get all values of an enum.
214
225
 
215
226
  Parameters
216
227
  ----------
217
- enum : Enum
218
- Enum to get values from.
228
+ enum : EnumMeta
229
+ Enum class to get values from.
219
230
 
220
231
  Returns
221
232
  -------
222
- list
233
+ list[Any]
223
234
  List of enum values.
224
235
  """
225
- return [e.value for e in enum]
236
+ vals: MappingProxyType[str, Enum] = enum.__members__
237
+ return [member.value for member in vals.values()]
@@ -0,0 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Union
4
+
5
+ MetricType = Union[float, int, list[Union[float, int]]]
6
+ SourcesOrListOfSources = Union[str, list[str]]
@@ -93,7 +93,7 @@ def map_uri_scheme(uri: str) -> str:
93
93
  Raises
94
94
  ------
95
95
  ValueError
96
- If the scheme is unknown.
96
+ If the scheme is unknown or invalid.
97
97
  """
98
98
  scheme = urlparse(uri).scheme
99
99
  if scheme in list_enum(LocalSchemes):