|  | @@ -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
 |