modular-service-cli/modular_service_cli/service/config.py (164 lines of code) (raw):
from abc import ABC, abstractmethod
from concurrent.futures import ThreadPoolExecutor, as_completed
from itertools import chain
from pathlib import Path
from typing import Generator, TYPE_CHECKING
from botocore.credentials import JSONFileCache
from modular_service_cli.service.logger import get_logger
if TYPE_CHECKING:
from modular_cli_sdk.services.credentials_manager import (
AbstractCredentialsManager)
SYSTEM_LOG = get_logger(__name__)
Json = dict | list | float | int | str | bool
class AbstractConfig(ABC):
@property
@abstractmethod
def api_link(self) -> str | None:
...
@api_link.setter
@abstractmethod
def api_link(self, value):
...
@property
@abstractmethod
def access_token(self) -> str | None:
...
@access_token.setter
@abstractmethod
def access_token(self, value):
...
@property
@abstractmethod
def refresh_token(self) -> str | None:
...
@refresh_token.setter
@abstractmethod
def refresh_token(self, value):
...
@abstractmethod
def items(self) -> Generator[tuple[str, Json], None, None]:
...
@abstractmethod
def clear(self):
...
@abstractmethod
def set(self, key: str, value: Json):
...
@abstractmethod
def update(self, dct: dict):
...
class OnDiskModularServiceConfig(JSONFileCache, AbstractConfig):
CACHE_DIR = Path.home() / '.modular_service_admin_cli'
def __init__(self, prefix: str = 'root', working_dir: Path = CACHE_DIR):
super().__init__(working_dir=str(working_dir / prefix))
def get(self, cache_key: str) -> Json | None:
if cache_key in self:
return self[cache_key]
def set(self, key: str, value: Json):
self[key] = value
def update(self, dct: dict):
for key, value in dct.items():
self.set(key, value)
@property
def api_link(self) -> str | None:
return self.get('api_link')
@api_link.setter
def api_link(self, value: str):
self['api_link'] = value
@api_link.deleter
def api_link(self):
if 'api_link' in self:
del self['api_link']
@property
def access_token(self) -> str | None:
return self.get('access_token')
@access_token.setter
def access_token(self, value: str):
self['access_token'] = value
@access_token.deleter
def access_token(self):
if 'access_token' in self:
del self['access_token']
@property
def refresh_token(self) -> str | None:
return self.get('refresh_token')
@refresh_token.setter
def refresh_token(self, value: str):
self['refresh_token'] = value
@refresh_token.deleter
def refresh_token(self):
if 'refresh_token' in self:
del self['refresh_token']
@classmethod
def public_config_params(cls) -> list[property]:
return [
cls.api_link,
]
@classmethod
def private_config_params(cls) -> list[property]:
return [
cls.access_token,
cls.refresh_token
]
def items(self, private: bool = False) -> Generator[tuple[str, Json], None, None]:
lst = self.public_config_params()
if private:
lst += self.private_config_params()
with ThreadPoolExecutor() as executor: # it reads a lot of files
futures = {
executor.submit(prop.fget, self): prop.fget.__name__
for prop in lst
}
for future in as_completed(futures):
yield futures[future], future.result()
def clear(self):
it = chain(self.public_config_params(), self.private_config_params())
with ThreadPoolExecutor() as executor:
for prop in it:
executor.submit(prop.fdel, self)
class ModularCliSdkConfig(AbstractConfig):
"""
For integration with modular cli sdk
"""
__slots__ = '_credentials_manager', '_config_dict'
def __init__(self, credentials_manager: 'AbstractCredentialsManager'):
self._credentials_manager = credentials_manager
self._config_dict = {}
@property
def config_dict(self) -> dict:
from modular_cli_sdk.commons.exception import \
ModularCliSdkBaseException
# in order to be able to use other classes from this module
# without cli_sdk installed
if not self._config_dict:
try:
SYSTEM_LOG.info('Getting creds from credentials manager')
self._config_dict = self._credentials_manager.extract()
except ModularCliSdkBaseException:
pass
return self._config_dict
def set(self, key: str, value: Json) -> None:
config_dict = self.config_dict
config_dict[key] = value
self._credentials_manager.store(config_dict)
def update(self, dct: dict) -> None:
config_dict = self.config_dict
config_dict.update(dct)
self._credentials_manager.store(config_dict)
@property
def api_link(self) -> str | None:
return self.config_dict.get('api_link')
@api_link.setter
def api_link(self, value: str):
self.set('api_link', value)
@property
def access_token(self) -> str | None:
return self.config_dict.get('access_token')
@access_token.setter
def access_token(self, value: str):
self.set('access_token', value)
@property
def refresh_token(self) -> str | None:
return self.config_dict.get('refresh_token')
@refresh_token.setter
def refresh_token(self, value: str):
self.set('refresh_token', value)
def items(self) -> Generator[tuple[str, Json], None, None]:
yield 'api_link', self.api_link
def clear(self):
self._credentials_manager.clean_up()