Skip to content

Commit 8d8d061

Browse files
committed
feat: import from external store
1 parent a76c147 commit 8d8d061

File tree

19 files changed

+197
-91
lines changed

19 files changed

+197
-91
lines changed

src/kiara/context/config.py

+22-9
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
from kiara.registries.ids import ID_REGISTRY
3535
from kiara.utils import log_message
3636
from kiara.utils.files import get_data_from_file
37+
from kiara.utils.stores import create_store
3738

3839
if TYPE_CHECKING:
3940
from kiara.context import Kiara
4041
from kiara.models.context import ContextInfo
42+
from kiara.registries import KiaraArchive
4143

4244
logger = structlog.getLogger()
4345

@@ -96,13 +98,22 @@ def add_pipelines(self, *pipelines: str):
9698
"ignore.pipeline", reason="path does not exist", path=pipeline
9799
)
98100

99-
# @property
100-
# def db_url(self):
101-
# return get_kiara_db_url(self.context_folder)
102-
#
103-
# @property
104-
# def data_directory(self) -> str:
105-
# return os.path.join(self.context_folder, "data")
101+
def create_archive(
102+
self, archive_alias: str, allow_write_access: bool = False
103+
) -> "KiaraArchive":
104+
"""Create the kiara archive with the specified alias.
105+
106+
Make sure you know what you are doing when setting 'allow_write_access' to True.
107+
"""
108+
109+
store_config = self.archives[archive_alias]
110+
store = create_store(
111+
archive_id=store_config.archive_uuid,
112+
store_type=store_config.archive_type,
113+
store_config=store_config.config,
114+
allow_write_access=allow_write_access,
115+
)
116+
return store
106117

107118

108119
class KiaraSettings(BaseSettings):
@@ -120,7 +131,7 @@ class KiaraSettings(BaseSettings):
120131

121132

122133
def create_default_store(
123-
store_id: str, store_type: str, stores_base_path: str
134+
store_id: uuid.UUID, store_type: str, stores_base_path: str
124135
) -> KiaraArchiveConfig:
125136

126137
env_registry = EnvironmentRegistry.instance()
@@ -167,10 +178,12 @@ def create_in_folder(cls, path: Union[Path, str]) -> "KiaraConfig":
167178
return config
168179

169180
@classmethod
170-
def load_from_file(cls, path: Union[Path, None] = None) -> "KiaraConfig":
181+
def load_from_file(cls, path: Union[Path, str, None] = None) -> "KiaraConfig":
171182

172183
if path is None:
173184
path = Path(KIARA_MAIN_CONFIG_FILE)
185+
elif isinstance(path, str):
186+
path = Path(path)
174187

175188
if not path.exists():
176189
raise Exception(

src/kiara/defaults.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"kiara",
8181
"callbacks",
8282
]
83+
INVALID_ALIAS_NAMES = ["kiara", "__default__", "alias", "value", "value_id"]
8384
"""List of reserved names, inputs/outputs can't use those."""
8485

8586
DEFAULT_DATA_STORE_MARKER = "default_data_store"
@@ -94,7 +95,7 @@
9495
DEFAULT_WORKFLOW_STORE_MARKER = "default_workflow_store"
9596
"""Name for the default context workflow store."""
9697

97-
METADATA_DESTINY_STORE_MARKER = "default_destiny_store"
98+
METADATA_DESTINY_STORE_MARKER = "metadata"
9899
"""Name for the default context destiny store."""
99100

100101
PIPELINE_PARENT_MARKER = "__pipeline__"

src/kiara/interfaces/cli/data/commands.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,8 @@ def explain_value(
251251
252252
All of the 'show-additional-information' flags are only applied when the 'terminal' output format is selected. This might change in the future.
253253
"""
254-
from kiara.interfaces.python_api import ValueInfo
255254

256-
kiara_obj: Kiara = ctx.obj.kiara
255+
kiara_api: KiaraAPI = ctx.obj.kiara_api
257256

258257
render_config = {
259258
"show_pedigree": pedigree,
@@ -270,26 +269,26 @@ def explain_value(
270269
all_values = []
271270
for v_id in value_id:
272271
try:
273-
value = kiara_obj.data_registry.get_value(v_id)
272+
value_info = kiara_api.retrieve_value_info(v_id)
274273
except Exception as e:
275274
terminal_print()
276275
terminal_print(f"[red]Error[/red]: {e}")
277276
sys.exit(1)
278-
if not value:
277+
if not value_info:
279278
terminal_print(f"[red]Error[/red]: No value found for: {v_id}")
280279
sys.exit(1)
281-
all_values.append(value)
280+
all_values.append(value_info)
282281

283282
if len(all_values) == 1:
284283
title = f"Value details for: [b i]{value_id[0]}[/b i]"
285284
else:
286285
title = "Value details"
287286

288-
v_infos = (
289-
ValueInfo.create_from_instance(kiara=kiara_obj, instance=v) for v in all_values
290-
)
287+
# v_infos = (
288+
# ValueInfo.create_from_instance(kiara=kiara_obj, instance=v) for v in all_values
289+
# )
291290

292-
terminal_print_model(*v_infos, format=format, in_panel=title, **render_config)
291+
terminal_print_model(*all_values, format=format, in_panel=title, **render_config)
293292

294293

295294
@data.command(name="load")

src/kiara/interfaces/python_api/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ def instance(cls, context_name: Union[str, None] = None) -> "KiaraAPI":
144144
def __init__(self, kiara_config: Union["KiaraConfig", None] = None):
145145

146146
if kiara_config is None:
147+
from kiara.context import Kiara, KiaraConfig
148+
147149
kiara_config = KiaraConfig()
148150

149151
self._kiara_config: KiaraConfig = kiara_config

src/kiara/registries/__init__.py

+44-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import abc
99
import os
1010
import uuid
11-
from typing import TYPE_CHECKING, Generic, Iterable, Type, TypeVar, Union
11+
from typing import TYPE_CHECKING, Any, Generic, Iterable, Mapping, Type, TypeVar, Union
1212

1313
import structlog
1414
from pydantic import BaseModel, ConfigDict, Field
@@ -22,12 +22,15 @@
2222

2323
if TYPE_CHECKING:
2424
from kiara.context import Kiara
25+
from kiara.context.config import KiaraArchiveConfig
2526

2627

2728
class ArchiveConfig(BaseModel, abc.ABC):
2829
@classmethod
2930
@abc.abstractmethod
30-
def create_new_store_config(cls, store_id: str, stores_base_path: str) -> Self:
31+
def create_new_store_config(
32+
cls, store_id: uuid.UUID, stores_base_path: str
33+
) -> Self:
3134
raise NotImplementedError(
3235
f"Store config type '{cls}' does not implement 'create_new_config'."
3336
)
@@ -55,16 +58,42 @@ class KiaraArchive(abc.ABC):
5558

5659
_config_cls = ArchiveConfig # type: ignore
5760

61+
@classmethod
62+
def create_config(
63+
cls, config: Union["KiaraArchiveConfig", BaseModel, Mapping[str, Any]]
64+
) -> "BaseArchive":
65+
66+
from kiara.context.config import KiaraArchiveConfig
67+
68+
if isinstance(config, cls._config_cls):
69+
config = config
70+
elif isinstance(config, KiaraArchiveConfig):
71+
config = cls._config_cls(**config.config)
72+
elif isinstance(config, BaseModel):
73+
config = cls._config_cls(**config.model_dump())
74+
elif isinstance(config, Mapping):
75+
config = cls._config_cls(**config)
76+
77+
return config
78+
79+
def __init__(self, force_read_only: bool = False, **kwargs):
80+
self._force_read_only: bool = force_read_only
81+
5882
@classmethod
5983
@abc.abstractmethod
6084
def supported_item_types(cls) -> Iterable[str]:
6185
pass
6286

6387
@classmethod
6488
@abc.abstractmethod
65-
def is_writeable(cls) -> bool:
89+
def _is_writeable(cls) -> bool:
6690
pass
6791

92+
def is_writeable(self) -> bool:
93+
if self._force_read_only:
94+
return False
95+
return self.__class__._is_writeable()
96+
6897
@abc.abstractmethod
6998
def register_archive(self, kiara: "Kiara"):
7099
pass
@@ -125,7 +154,7 @@ class BaseArchive(KiaraArchive, Generic[ARCHIVE_CONFIG_CLS]):
125154

126155
@classmethod
127156
def create_new_config(
128-
cls, store_id: str, stores_base_path: str
157+
cls, store_id: uuid.UUID, stores_base_path: str
129158
) -> ARCHIVE_CONFIG_CLS:
130159

131160
log_message(
@@ -139,12 +168,22 @@ def create_new_config(
139168
store_id=store_id, stores_base_path=stores_base_path
140169
)
141170

142-
def __init__(self, archive_id: uuid.UUID, config: ARCHIVE_CONFIG_CLS):
171+
def __init__(
172+
self,
173+
archive_id: uuid.UUID,
174+
config: ARCHIVE_CONFIG_CLS,
175+
force_read_only: bool = False,
176+
):
143177

178+
super().__init__(force_read_only=force_read_only)
144179
self._archive_id: uuid.UUID = archive_id
145180
self._config: ARCHIVE_CONFIG_CLS = config
146181
self._kiara: Union["Kiara", None] = None
147182

183+
@classmethod
184+
def _is_writeable(cls) -> bool:
185+
return False
186+
148187
def _get_config(self) -> ARCHIVE_CONFIG_CLS:
149188
return self._config
150189

src/kiara/registries/aliases/__init__.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import structlog
2121

22+
from kiara.defaults import INVALID_ALIAS_NAMES
23+
from kiara.exceptions import KiaraException
2224
from kiara.models.events.alias_registry import AliasArchiveAddedEvent
2325
from kiara.registries import BaseArchive
2426
from kiara.registries.data import ValueLink
@@ -55,18 +57,14 @@ def find_value_id_for_alias(self, alias: str) -> Union[uuid.UUID, None]:
5557
def find_aliases_for_value_id(self, value_id: uuid.UUID) -> Union[Set[str], None]:
5658
pass
5759

58-
@classmethod
59-
def is_writeable(cls) -> bool:
60-
return False
61-
6260

6361
class AliasStore(AliasArchive):
6462
@abc.abstractmethod
6563
def register_aliases(self, value_id: uuid.UUID, *aliases: str):
6664
pass
6765

6866
@classmethod
69-
def is_writeable(cls) -> bool:
67+
def _is_writeable(cls) -> bool:
7068
return True
7169

7270

@@ -278,6 +276,13 @@ def register_aliases(
278276
allow_overwrite: bool = False,
279277
):
280278

279+
for alias in aliases:
280+
if alias in INVALID_ALIAS_NAMES:
281+
raise KiaraException(
282+
msg=f"Invalid alias name: {alias}.",
283+
details=f"The following names can't be used as alias: {', '.join(INVALID_ALIAS_NAMES)}.",
284+
)
285+
281286
value_id = self._get_value_id(value_id=value_id)
282287
store_name = self.default_alias_store
283288
store: AliasStore = self.get_archive(archive_id=store_name) # type: ignore

src/kiara/registries/aliases/archives.py

-4
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,6 @@ class FileSystemAliasStore(FileSystemAliasArchive, AliasStore):
132132

133133
_archive_type_name = "filesystem_alias_store"
134134

135-
@classmethod
136-
def is_writeable(cls) -> bool:
137-
return True
138-
139135
def register_aliases(self, value_id: uuid.UUID, *aliases: str):
140136

141137
value_path = self._translate_value_id(value_id=value_id)

src/kiara/registries/data/__init__.py

+32-17
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ def __init__(self, kiara: "Kiara"):
110110

111111
def resolve_alias(self, alias: str) -> uuid.UUID:
112112

113+
dbg(f"RESOLVE: {alias}")
114+
113115
if ":" in alias:
114116
ref_type, rest = alias.split(":", maxsplit=1)
115117

@@ -230,7 +232,9 @@ def NONE_VALUE(self) -> Value:
230232
def retrieve_all_available_value_ids(self) -> Set[uuid.UUID]:
231233

232234
result: Set[uuid.UUID] = set()
233-
for store in self._data_archives.values():
235+
for alias, store in self._data_archives.items():
236+
print(alias)
237+
dbg(store.config.model_dump())
234238
ids = store.value_ids
235239
if ids:
236240
result.update(ids)
@@ -378,24 +382,35 @@ def get_value(self, value: Union[uuid.UUID, ValueLink, str]) -> Value:
378382
_value = self._registered_values[_value_id]
379383
return _value
380384

381-
matches = []
382-
for store_id, store in self.data_archives.items():
383-
match = store.has_value(value_id=_value_id)
384-
if match:
385-
matches.append(store_id)
385+
default_store: DataArchive = self.get_archive(
386+
archive_id=self.default_data_store
387+
)
388+
if not default_store.has_value(value_id=_value_id):
386389

387-
if len(matches) == 0:
388-
raise NoSuchValueIdException(
389-
value_id=_value_id, msg=f"No value registered with id: {value}"
390-
)
391-
elif len(matches) > 1:
392-
raise NoSuchValueIdException(
393-
value_id=_value_id,
394-
msg=f"Found value with id '{value}' in multiple archives, this is not supported (yet): {matches}",
395-
)
390+
matches = []
391+
for store_id, store in self.data_archives.items():
392+
match = store.has_value(value_id=_value_id)
393+
if match:
394+
matches.append(store_id)
395+
396+
if len(matches) == 0:
397+
raise NoSuchValueIdException(
398+
value_id=_value_id, msg=f"No value registered with id: {value}"
399+
)
400+
elif len(matches) > 1:
401+
raise NoSuchValueIdException(
402+
value_id=_value_id,
403+
msg=f"Found value with id '{value}' in multiple archives, this is not supported (yet): {matches}",
404+
)
405+
store_that_has_it = matches[0]
406+
else:
407+
store_that_has_it = self.default_data_store
396408

397-
self._value_archive_lookup_map[_value_id] = matches[0]
398-
stored_value = self.get_archive(matches[0]).retrieve_value(value_id=_value_id)
409+
self._value_archive_lookup_map[_value_id] = store_that_has_it
410+
411+
stored_value = self.get_archive(store_that_has_it).retrieve_value(
412+
value_id=_value_id
413+
)
399414
stored_value._set_registry(self)
400415
stored_value._is_stored = True
401416

0 commit comments

Comments
 (0)