Source code for denspp.offline.json_handler
import json
from typing import Any
from logging import getLogger, Logger
from os import makedirs
from os.path import join, exists, isabs
from denspp.offline import get_path_to_project
[docs]
class JsonHandler:
_path2folder: str
_file_name: str
_ending_chck: list = ['.json']
_logger: Logger
_template: Any
def __init__(self, template: Any | dict, path: str='config', file_name: str='Params'):
"""Creating a class for handling JSON files
:param template: Dummy dataclass with entries or dictionary (is only generated if JSON not exist)
:param path: String with path to the folder which has the JSON file [Default: '']
:param file_name: String with name of the JSON file [Default: 'Config_Train']
"""
self._logger = getLogger(__name__)
self._path2folder = join(get_path_to_project(), path) if not isabs(path) else path
self._file_name = self.__remove_ending_from_filename(file_name)
self._template = template
makedirs(self._path2folder, exist_ok=True)
if not exists(self.__path2chck):
data2json = template if isinstance(template, dict) else self.__translate_dataclass_to_dict(template)
self.write_dict_to_json(data2json)
self._logger.info(f"Create new yaml file in folder: {self._path2folder}")
@staticmethod
def __translate_dataclass_to_dict(class_content: type) -> dict:
"""Translating all class variables with default values into dict"""
return {key: value for key, value in class_content.__dict__.items()
if not key.startswith('__') and not callable(key)}
@property
def __path2chck(self) -> str:
"""Getting the path to the desired CSV file"""
return join(self._path2folder, f"{self._file_name}{self._ending_chck[0]}")
def __remove_ending_from_filename(self, file_name: str) -> str:
"""Function for removing data type ending
:param file_name: String with file name
:return:
String with file name without data type ending
"""
used_file_name = [file_name.split(file_end)[0] for file_end in self._ending_chck if file_end in file_name]
return used_file_name[0] if len(used_file_name) > 0 else file_name
def __check_scheme_validation(self, template: type | dict, real_file: type | dict) -> bool:
"""Function for validating the key entries from template json and real json file
:param template: Dictionary or class from the template for generating json file
:param real_file: Dictionary from real_file
:return:
Boolean decision if both key are equal
"""
keys_tmplt = self.__translate_dataclass_to_dict(template).keys() if not isinstance(template, dict) else template.keys()
keys_real = self.__translate_dataclass_to_dict(real_file).keys() if not isinstance(real_file, dict) else real_file.keys()
equal_chck = keys_tmplt == keys_real
if not equal_chck:
list_not0 = [key for key in keys_real if key not in keys_tmplt]
list_not1 = [key for key in keys_tmplt if key not in [keys_real, list_not0]]
list_not0.extend(list_not1)
raise RuntimeError(f"Config file not valid (wrong keys: {list_not0})! - Please check and correct/remove actual config file!")
else:
return equal_chck
[docs]
def write_dict_to_json(self, config_data: dict) -> None:
"""Writing list with configuration sets to JSON file
Args:
config_data: Dict. with configuration
Returns:
None
"""
makedirs(self._path2folder, exist_ok=True)
with open(self.__path2chck, 'w') as f:
json.dump(config_data, f, sort_keys=False)
[docs]
def get_dict(self) -> dict:
"""Getting the dictionary with configuration sets from JSON file
:return: Dict. with configuration
"""
if not exists(self.__path2chck):
raise FileNotFoundError("YAML does not exists - Please create one!")
else:
# --- Reading YAML file
with open(self.__path2chck, 'r') as f:
data = json.load(f)
self._logger.debug(f"... read JSON file: {self.__path2chck}")
self.__check_scheme_validation(self._template, data)
return data
[docs]
def get_class(self, class_constructor: type):
"""Getting all key inputs from json dictionary to a class"""
data = self.get_dict()
return class_constructor(**data)