Skip to content

Commit 29623f0

Browse files
SK-2954: Split ISkyflow into BaseSkyflow/BaseSkyflowImpl, make connection/detect structurally absent when unsupported
Renames ISkyflow -> BaseSkyflow (pure interface) and the old BaseSkyflow -> BaseSkyflowImpl (concrete). Moves connection/detect support into ConnectionCapable/DetectCapable interfaces + ConnectionMixin/DetectMixin in a new common/client/utils/_utils.py, conditionally composed into a variant's Skyflow class by make_skyflow_class() so unsupported variants (e.g. flowvault) genuinely lack .connection()/.detect() (AttributeError) instead of raising NotImplementedError from a present-but-guarded method. Also fixes two review-flagged bugs: adding a vault/connection config with a duplicate id to an already-built client now raises SkyflowError instead of silently overwriting the existing entry, and update_connection_config no longer risks a bare KeyError on a missing connection_id. Extracts the Builder's raw NotImplementedError string literals into named constants. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent feb79cc commit 29623f0

8 files changed

Lines changed: 231 additions & 152 deletions

File tree

common/client/base_skyflow.py

Lines changed: 44 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
from abc import ABC, abstractmethod
22
from collections import OrderedDict
3-
from functools import partial
4-
53
from common.errors import SkyflowError
64
from common.utils import SkyflowMessages
7-
from common.utils.enums import LogLevel as _CommonLogLevel
8-
from common.utils.logger import Logger as _CommonLogger, log_info, log_warn
5+
from common.utils.logger import log_info, log_warn
96
from common.utils.constants import OptionField
10-
from common.utils.validations import (
11-
validate_vault_config as _common_validate_vault_config,
12-
validate_update_vault_config as _common_validate_update_vault_config,
13-
validate_log_level as _common_validate_log_level,
14-
validate_credentials as _common_validate_credentials,
7+
8+
_BUILDER_TEMPLATE_ERROR = (
9+
"BaseSkyflowImpl.Builder is an interface template -- build a concrete Skyflow "
10+
"class via make_skyflow_class() instead of using it directly. Missing: {missing}"
1511
)
12+
_CONNECTIONS_NOT_SUPPORTED_ERROR = "Connections are not supported by this Skyflow SDK variant"
13+
_DETECT_NOT_SUPPORTED_ERROR = "Detect is not supported by this Skyflow SDK variant"
1614

1715

18-
class ISkyflow(ABC):
16+
class BaseSkyflow(ABC):
1917
@classmethod
2018
@abstractmethod
2119
def builder(cls):
@@ -37,22 +35,6 @@ def update_vault_config(self, config):
3735
def get_vault_config(self, vault_id):
3836
raise NotImplementedError
3937

40-
@abstractmethod
41-
def add_connection_config(self, config):
42-
raise NotImplementedError
43-
44-
@abstractmethod
45-
def remove_connection_config(self, connection_id):
46-
raise NotImplementedError
47-
48-
@abstractmethod
49-
def update_connection_config(self, config):
50-
raise NotImplementedError
51-
52-
@abstractmethod
53-
def get_connection_config(self, connection_id):
54-
raise NotImplementedError
55-
5638
@abstractmethod
5739
def add_skyflow_credentials(self, credentials):
5840
raise NotImplementedError
@@ -77,19 +59,11 @@ def get_log_level(self):
7759
def vault(self, vault_id=None):
7860
raise NotImplementedError
7961

80-
@abstractmethod
81-
def connection(self, connection_id=None):
82-
raise NotImplementedError
8362

84-
@abstractmethod
85-
def detect(self, vault_id=None):
86-
raise NotImplementedError
87-
88-
89-
class BaseSkyflow(ISkyflow):
63+
class BaseSkyflowImpl(BaseSkyflow):
9064

9165
def __init__(self, builder):
92-
if type(self) is BaseSkyflow:
66+
if type(self) is BaseSkyflowImpl:
9367
raise SkyflowError(
9468
SkyflowMessages.Error.BASE_SKYFLOW_INSTANTIATION_NOT_ALLOWED.value,
9569
SkyflowMessages.ErrorCodes.INVALID_INPUT.value,
@@ -102,7 +76,7 @@ def builder(cls):
10276
return cls.Builder()
10377

10478
def add_vault_config(self, config):
105-
self.__builder._Builder__add_vault_config(config)
79+
self.__builder._add_vault_config(config)
10680
return self
10781

10882
def remove_vault_config(self, vault_id):
@@ -114,34 +88,15 @@ def update_vault_config(self, config):
11488
def get_vault_config(self, vault_id):
11589
return self.__builder.get_vault_config(vault_id).get(OptionField.VAULT_CLIENT).get_config()
11690

117-
def add_connection_config(self, config):
118-
self.__builder._require_connections()
119-
self.__builder._Builder__add_connection_config(config)
120-
return self
121-
122-
def remove_connection_config(self, connection_id):
123-
self.__builder._require_connections()
124-
self.__builder.remove_connection_config(connection_id)
125-
return self
126-
127-
def update_connection_config(self, config):
128-
self.__builder._require_connections()
129-
self.__builder.update_connection_config(config)
130-
return self
131-
132-
def get_connection_config(self, connection_id):
133-
self.__builder._require_connections()
134-
return self.__builder.get_connection_config(connection_id).get(OptionField.VAULT_CLIENT).get_config()
135-
13691
def add_skyflow_credentials(self, credentials):
137-
self.__builder._Builder__add_skyflow_credentials(credentials)
92+
self.__builder._add_skyflow_credentials(credentials)
13893
return self
13994

14095
def update_skyflow_credentials(self, credentials):
141-
self.__builder._Builder__add_skyflow_credentials(credentials)
96+
self.__builder._add_skyflow_credentials(credentials)
14297

14398
def set_log_level(self, log_level):
144-
self.__builder._Builder__set_log_level(log_level)
99+
self.__builder._set_log_level(log_level)
145100
return self
146101

147102
def update_log_level(self, log_level):
@@ -150,21 +105,14 @@ def update_log_level(self, log_level):
150105
return self.set_log_level(log_level)
151106

152107
def get_log_level(self):
153-
return self.__builder._Builder__log_level
108+
return self.__builder.get_log_level()
154109

155110
def vault(self, vault_id=None):
156111
vault_config = self.__builder.get_vault_config(vault_id)
157112
return vault_config.get(OptionField.VAULT_CONTROLLER)
158113

159-
def connection(self, connection_id=None):
160-
self.__builder._require_connections()
161-
connection_config = self.__builder.get_connection_config(connection_id)
162-
return connection_config.get(OptionField.CONTROLLER)
163-
164-
def detect(self, vault_id=None):
165-
self.__builder._require_detect()
166-
vault_config = self.__builder.get_vault_config(vault_id)
167-
return vault_config.get(OptionField.DETECT_CONTROLLER)
114+
def _get_builder(self):
115+
return self.__builder
168116

169117
class Builder(ABC):
170118
_vault_client_cls = None
@@ -192,10 +140,7 @@ class Builder(ABC):
192140
def __init__(self):
193141
missing = [hook for hook in self._REQUIRED_HOOKS if getattr(self, hook) is None]
194142
if missing:
195-
raise NotImplementedError(
196-
"BaseSkyflow.Builder is an interface template -- build a concrete Skyflow "
197-
f"class via make_skyflow_class() instead of using it directly. Missing: {', '.join(missing)}"
198-
)
143+
raise NotImplementedError(_BUILDER_TEMPLATE_ERROR.format(missing=', '.join(missing)))
199144
self.__vault_configs = OrderedDict()
200145
self.__vault_list = list()
201146
self.__connection_configs = OrderedDict()
@@ -206,11 +151,11 @@ def __init__(self):
206151

207152
def _require_connections(self):
208153
if self._connection_cls is None:
209-
raise NotImplementedError("Connections are not supported by this Skyflow SDK variant")
154+
raise NotImplementedError(_CONNECTIONS_NOT_SUPPORTED_ERROR)
210155

211156
def _require_detect(self):
212157
if self._detect_cls is None:
213-
raise NotImplementedError("Detect is not supported by this Skyflow SDK variant")
158+
raise NotImplementedError(_DETECT_NOT_SUPPORTED_ERROR)
214159

215160
def add_vault_config(self, config):
216161
vault_id = config.get(OptionField.VAULT_ID)
@@ -282,7 +227,7 @@ def remove_connection_config(self, connection_id):
282227
def update_connection_config(self, config):
283228
self._require_connections()
284229
self._validate_update_connection_config(self.__logger, config)
285-
connection_id = config[OptionField.CONNECTION_ID]
230+
connection_id = config.get(OptionField.CONNECTION_ID)
286231
if connection_id not in self.__connection_configs:
287232
raise SkyflowError(self._skyflow_messages.Error.CONNECTION_ID_NOT_IN_CONFIG_LIST.value.format(connection_id), self._skyflow_messages.ErrorCodes.INVALID_INPUT.value)
288233
connection_config = self.__connection_configs[connection_id]
@@ -312,9 +257,17 @@ def set_log_level(self, log_level):
312257
def get_logger(self):
313258
return self.__logger
314259

315-
def __add_vault_config(self, config):
260+
def get_log_level(self):
261+
return self.__log_level
262+
263+
def _add_vault_config(self, config):
316264
self._validate_vault_config(self.__logger, config)
317265
vault_id = config.get(OptionField.VAULT_ID)
266+
if vault_id in self.__vault_configs:
267+
raise SkyflowError(
268+
self._skyflow_messages.Error.VAULT_ID_ALREADY_EXISTS.value.format(vault_id),
269+
self._skyflow_messages.ErrorCodes.INVALID_INPUT.value
270+
)
318271
vault_client = self._vault_client_cls(config)
319272
vault_config = {
320273
OptionField.VAULT_CLIENT: vault_client,
@@ -327,34 +280,39 @@ def __add_vault_config(self, config):
327280
if self._detect_cls is not None:
328281
log_info(self._skyflow_messages.Info.DETECT_CONTROLLER_INITIALIZED.value.format(vault_id), self.__logger)
329282

330-
def __add_connection_config(self, config):
283+
def _add_connection_config(self, config):
331284
self._validate_connection_config(self.__logger, config)
332285
connection_id = config.get(OptionField.CONNECTION_ID)
286+
if connection_id in self.__connection_configs:
287+
raise SkyflowError(
288+
self._skyflow_messages.Error.CONNECTION_ID_ALREADY_EXISTS.value.format(connection_id),
289+
self._skyflow_messages.ErrorCodes.INVALID_INPUT.value
290+
)
333291
vault_client = self._vault_client_cls(config)
334292
self.__connection_configs[connection_id] = {
335293
OptionField.VAULT_CLIENT: vault_client,
336294
OptionField.CONTROLLER: self._connection_cls(vault_client)
337295
}
338296
log_info(self._skyflow_messages.Info.CONNECTION_CONTROLLER_INITIALIZED.value.format(connection_id), self.__logger)
339297

340-
def __update_vault_client_logger(self, log_level, logger):
298+
def _update_vault_client_logger(self, log_level, logger):
341299
for vault_id, vault_config in self.__vault_configs.items():
342300
vault_config.get(OptionField.VAULT_CLIENT).set_logger(log_level, logger)
343301

344302
for connection_id, connection_config in self.__connection_configs.items():
345303
connection_config.get(OptionField.VAULT_CLIENT).set_logger(log_level, logger)
346304

347-
def __set_log_level(self, log_level):
305+
def _set_log_level(self, log_level):
348306
self._validate_log_level(self.__logger, log_level)
349307
self.__log_level = log_level
350308
self.__logger.set_log_level(log_level)
351309
if self._set_active_log_level is not None:
352310
self._set_active_log_level(log_level)
353-
self.__update_vault_client_logger(log_level, self.__logger)
311+
self._update_vault_client_logger(log_level, self.__logger)
354312
log_info(self._skyflow_messages.Info.LOGGER_SETUP_DONE.value, self.__logger)
355313
log_info(self._skyflow_messages.Info.CURRENT_LOG_LEVEL.value.format(self.__log_level), self.__logger)
356314

357-
def __add_skyflow_credentials(self, credentials):
315+
def _add_skyflow_credentials(self, credentials):
358316
if credentials is not None:
359317
self.__skyflow_credentials = credentials
360318
self._validate_credentials(self.__logger, credentials)
@@ -371,51 +329,13 @@ def build(self):
371329
self._set_active_log_level(self.__log_level)
372330

373331
for config in self.__vault_list:
374-
self.__add_vault_config(config)
332+
self._add_vault_config(config)
375333

376334
for config in self.__connection_list:
377-
self.__add_connection_config(config)
335+
self._add_connection_config(config)
378336

379-
self.__update_vault_client_logger(self.__log_level, self.__logger)
337+
self._update_vault_client_logger(self.__log_level, self.__logger)
380338

381-
self.__add_skyflow_credentials(self.__skyflow_credentials)
339+
self._add_skyflow_credentials(self.__skyflow_credentials)
382340

383341
return self._skyflow_cls(self)
384-
385-
386-
def make_skyflow_class(*, vault_client_cls, vault_controller_cls, skyflow_messages,
387-
validate_vault_config=None, validate_update_vault_config=None,
388-
validate_log_level=None, validate_credentials=None,
389-
logger_cls=_CommonLogger, default_log_level=_CommonLogLevel.ERROR,
390-
connection_cls=None, detect_cls=None,
391-
validate_connection_config=None, validate_update_connection_config=None,
392-
set_active_log_level=None):
393-
394-
if connection_cls is not None and (validate_connection_config is None or validate_update_connection_config is None):
395-
raise ValueError("connection_cls requires validate_connection_config and validate_update_connection_config")
396-
397-
validate_vault_config = validate_vault_config or partial(_common_validate_vault_config, messages=skyflow_messages)
398-
validate_update_vault_config = validate_update_vault_config or partial(_common_validate_update_vault_config, messages=skyflow_messages)
399-
validate_log_level = validate_log_level or partial(_common_validate_log_level, messages=skyflow_messages)
400-
validate_credentials = validate_credentials or partial(_common_validate_credentials, messages=skyflow_messages)
401-
402-
builder_attrs = {
403-
'_vault_client_cls': vault_client_cls,
404-
'_vault_controller_cls': vault_controller_cls,
405-
'_connection_cls': connection_cls,
406-
'_detect_cls': detect_cls,
407-
'_logger_cls': logger_cls,
408-
'_default_log_level': default_log_level,
409-
'_skyflow_messages': skyflow_messages,
410-
'_validate_vault_config': staticmethod(validate_vault_config),
411-
'_validate_update_vault_config': staticmethod(validate_update_vault_config),
412-
'_validate_connection_config': staticmethod(validate_connection_config) if validate_connection_config else None,
413-
'_validate_update_connection_config': staticmethod(validate_update_connection_config) if validate_update_connection_config else None,
414-
'_validate_log_level': staticmethod(validate_log_level),
415-
'_validate_credentials': staticmethod(validate_credentials),
416-
'_set_active_log_level': staticmethod(set_active_log_level) if set_active_log_level else None,
417-
}
418-
variant_builder = type('Builder', (BaseSkyflow.Builder,), builder_attrs)
419-
variant_skyflow = type('Skyflow', (BaseSkyflow,), {'Builder': variant_builder})
420-
variant_builder._skyflow_cls = variant_skyflow
421-
return variant_skyflow

common/client/utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from common.client.utils._utils import ConnectionCapable, DetectCapable, ConnectionMixin, DetectMixin, make_skyflow_class

0 commit comments

Comments
 (0)