18 from typing
import Dict, Any, Optional, Type, TypeVar, List, Tuple
19 from typing_extensions
import Self
20 from abc
import abstractmethod
21 from pathlib
import Path
27 T = TypeVar(
"T", int, float, str, bool)
29 CONFIG_DIR = Path.home().joinpath(
".config",
"coretex")
30 DEFAULT_VENV_PATH = CONFIG_DIR /
"venv"
33 class InvalidConfiguration(Exception):
35 def __init__(self, message: str, errors: List[str]) ->
None:
36 super().__init__(message)
41 class ConfigurationNotFound(Exception):
45 class BaseConfiguration:
47 def __init__(self, raw: Dict[str, Any]) ->
None:
52 def getConfigPath(cls) -> Path:
56 def _isConfigValid(self) -> Tuple[bool, List[str]]:
60 def load(cls) -> Self:
61 configPath = cls.getConfigPath()
62 if not configPath.exists():
63 raise ConfigurationNotFound(f
"Configuration not found at path: {configPath}")
65 with configPath.open(
"r")
as file:
70 isValid, errors = config._isConfigValid()
72 raise InvalidConfiguration(
"Invalid configuration found.", errors)
76 def _value(self, configKey: str, valueType: Type[T], envKey: Optional[str] =
None) -> Optional[T]:
77 if envKey
is not None and envKey
in os.environ:
78 return valueType(os.environ[envKey])
80 return self._raw.get(configKey)
82 def getValue(self, configKey: str, valueType: Type[T], envKey: Optional[str] =
None, default: Optional[T] =
None) -> T:
83 value = self._value(configKey, valueType, envKey)
88 if not isinstance(value, valueType):
89 raise TypeError(f
"Invalid {configKey} type \"{type(value)}\", expected: \"{valueType.__name__}\".")
93 def getOptValue(self, configKey: str, valueType: Type[T], envKey: Optional[str] =
None) -> Optional[T]:
94 value = self._value(configKey, valueType, envKey)
96 if not isinstance(value, valueType):
101 def save(self) -> None:
102 configPath = self.getConfigPath()
104 if not configPath.parent.exists():
105 configPath.parent.mkdir(parents =
True, exist_ok =
True)
107 with configPath.open(
"w")
as configFile:
108 json.dump(self._raw, configFile, indent = 4)
110 def update(self, config: Self) ->
None:
111 self._raw = config._raw