# -*- coding: utf-8 -*- # @Time : 2022/6/24 14:04 # @Author : MaochengHu # @Email : wojiaohumaocheng@gmail.com # @File : config_parser.py # @Project : person_monitor import os import ast import sys import yaml import prettytable as pt from importlib import import_module from dev.src.utils.path_checker import check_file_exist from dev.src.utils.log import logger, SplitLine class Config(object): """ This class is used for loading config from python script. """ def __init__(self, config_path): check_file_exist(config_path) file_ext_name = os.path.splitext(config_path)[1] if file_ext_name == ".py": self.config_from_python_config(config_path) else: error_msg = "yolo config_files path is not exist -> {}".format(config_path) logger.error(error_msg) assert IOError(error_msg) def copy(self, new_config_dict: dict): """ Copies this config_files into a new config_files object, making the changes given by new_config_dict. """ ret = Config(vars(self)) for key, val in new_config_dict.items(): ret.__setattr__(key, val) return ret def replace(self, new_config_dict: dict): """ Copies new_config_dict into this config_files object. Note: new_config_dict can also be a config_files object. """ if isinstance(new_config_dict, Config): new_config_dict = vars(new_config_dict) for key, val in new_config_dict.items(): self.__setattr__(key, val) def get(self, k, rv=None): """ Get config file with key-value format :param k: :param rv: :return: """ dict_v = self.__dict__.get(k, rv) return dict_v @staticmethod def _validate_py_syntax(filename): with open(filename, 'r', encoding='utf-8') as f: # Setting encoding explicitly to resolve coding issue on windows content = f.read() try: ast.parse(content) except SyntaxError as e: raise SyntaxError('There are syntax errors in config_files ' 'file {}: {}'.format(filename, e)) @staticmethod def _load_yaml(yaml_path: str): assert os.path.exists(yaml_path), "cannot find {}".format(yaml_path) with open(yaml_path, 'r', encoding='utf-8') as yaml_file: config = yaml.load(yaml_file, Loader=yaml.FullLoader) return config def config_from_yaml(self, yaml_path: str): """ Get config file from yaml file :param yaml_path: """ yaml_dict = self._load_yaml(yaml_path) self.config_from_dict(yaml_dict) def config_from_python_config(self, config_path): """ Get config file from python file :param config_path: :return: """ self._validate_py_syntax(config_path) python_name, extension = os.path.splitext(os.path.basename(config_path)) # son_package = os.path.basename(os.path.dirname(__file__)) sys.path.append(os.path.dirname(os.path.abspath(__file__))) mod = import_module("{}".format(python_name)) del_module = ["os"] mod_dict = mod.__dict__ for key in list(mod_dict.keys()): if "__" in key or key in del_module: del mod_dict[key] self.config_from_dict(mod_dict) def config_from_dict(self, insert_dict): """ Get config file from dict :param insert_dict: """ self.__dict__.update(insert_dict) def show_info(self, name=None): """ Show Config file by config file dict :param name: """ name = "Config" if name is None else name with SplitLine("{} Info".format(name), "-") as title_line: tb = pt.PrettyTable() tb.header_style = "title" tb.padding_width = 10 tb.field_names = ["Parameters", "Values"] for key, value in self.__dict__.items(): if key.startswith("__"): continue tb.add_row((str(key), str(value))) logger.info("\n{}\n".format(tb)) def __call__(self, *args, **kwargs): pass def main(): """ test code """ python_config_path = "../../develop/config_files/yolox_nano_bytetrack_tin.py" config = Config(python_config_path) config.show_info() if __name__ == "__main__": main()