|
|
@@ -0,0 +1,121 @@
|
|
|
+import pathlib
|
|
|
+import json
|
|
|
+import json.decoder
|
|
|
+
|
|
|
+from .exception import config_exception
|
|
|
+from .app_resources import app_resources
|
|
|
+
|
|
|
+class config:
|
|
|
+ def __init__(self, defaults: dict) -> None:
|
|
|
+ self.__defaults = defaults.copy()
|
|
|
+ self.__config = defaults.copy()
|
|
|
+
|
|
|
+ def _get(self, name: str) -> str | int | float | dict | list:
|
|
|
+ if not name in self.__config:
|
|
|
+ raise TypeError("Can not found " + name + " in config.")
|
|
|
+
|
|
|
+ return self.__config[name]
|
|
|
+
|
|
|
+ def __get_default(self, name: str) -> str | int | float | dict | list:
|
|
|
+ return self.__defaults[name]
|
|
|
+
|
|
|
+ @property
|
|
|
+ def defaults(self) -> dict:
|
|
|
+ return self.__defaults.copy()
|
|
|
+
|
|
|
+ def exists(self, name: str) -> bool:
|
|
|
+ return name in self.__defaults
|
|
|
+
|
|
|
+ def load(self, config: dict) -> object:
|
|
|
+ for key in config:
|
|
|
+ if not self.exists(key):
|
|
|
+ content = "When parsing config file found key " + key + " "
|
|
|
+ content = content + "which is not recognized. Correct it."
|
|
|
+
|
|
|
+ raise config_exception(content)
|
|
|
+
|
|
|
+ if type(config[key]) is not type(self.__get_default(key)):
|
|
|
+ required_type = type(self.__get_default).__name__
|
|
|
+ detected_type = type(config[key]).__name__
|
|
|
+
|
|
|
+ content = "When processing \"" + key + "\" key in config "
|
|
|
+ content = content + "detected types mismatch. It would be an "
|
|
|
+ content = content + required_type + ", but it is an "
|
|
|
+ content = content + detected_type + "."
|
|
|
+
|
|
|
+ raise config_exception(content)
|
|
|
+
|
|
|
+ self.__config[key] = config[key]
|
|
|
+
|
|
|
+ return self
|
|
|
+
|
|
|
+ def __str__(self) -> str:
|
|
|
+ dump = "Config dump: \n"
|
|
|
+
|
|
|
+ for count in self.defaults.keys():
|
|
|
+ key = "Key \"" + count + "\": "
|
|
|
+ key = key + "\"" + self._get(count) + "\", "
|
|
|
+ key = key + "default = \"" + self.__get_default(count) + "\""
|
|
|
+ dump = dump + key + "\n"
|
|
|
+
|
|
|
+ return dump
|
|
|
+
|
|
|
+class config_generator:
|
|
|
+ def __init__(self, target: type) -> None:
|
|
|
+ if target is config:
|
|
|
+ raise TypeError("Config is skeleton class for configs.")
|
|
|
+
|
|
|
+ self.__config = target().defaults
|
|
|
+ self.__json_config = json.dumps(self.__config)
|
|
|
+
|
|
|
+ def save(self, where: pathlib.Path) -> None:
|
|
|
+ if where.exists():
|
|
|
+ content = "Can not create config file \"" + str(where) + "\" "
|
|
|
+ content = content + "because it already exists in filesystem."
|
|
|
+
|
|
|
+ raise config_exception(content)
|
|
|
+
|
|
|
+ with where.open("w") as handler:
|
|
|
+ handler.write(self.__json_config)
|
|
|
+
|
|
|
+class config_loader:
|
|
|
+ def __init__(self, target: type) -> None:
|
|
|
+ if target is config:
|
|
|
+ raise TypeError("Config is skeleton class for configs.")
|
|
|
+
|
|
|
+ self.__type = target
|
|
|
+ self.__target = None
|
|
|
+
|
|
|
+ @property
|
|
|
+ def result(self) -> config:
|
|
|
+ if self.__target is None:
|
|
|
+ raise RuntimeError("Config is not loaded yet.")
|
|
|
+
|
|
|
+ return self.__target
|
|
|
+
|
|
|
+ @property
|
|
|
+ def resources(self) -> app_resources:
|
|
|
+ return app_resources(self.result)
|
|
|
+
|
|
|
+ def load(self, where: pathlib.Path) -> object:
|
|
|
+ if not where.is_file():
|
|
|
+ content = "Can not found required config file \""
|
|
|
+ content = content + where.absolute() + "\"."
|
|
|
+
|
|
|
+ raise config_exception(content)
|
|
|
+
|
|
|
+ preparing = self.__type()
|
|
|
+
|
|
|
+ with where.open() as config:
|
|
|
+ try:
|
|
|
+ config_object = json.loads(config.read())
|
|
|
+ preparing.load(config_object)
|
|
|
+ self.__target = preparing
|
|
|
+
|
|
|
+ except json.decoder.JSONDecodeError as code_error:
|
|
|
+ content = "Can not load config file, syntax error: "
|
|
|
+ content = content + str(code_error) + "."
|
|
|
+
|
|
|
+ raise config_error(content)
|
|
|
+
|
|
|
+ return self
|