From d0ab3257445f2370cefb374442cff867dba850d0 Mon Sep 17 00:00:00 2001 From: alfrix Date: Sun, 9 Jul 2023 14:02:47 -0300 Subject: [PATCH] config: changes in how the config is validated now it validates in steps 1 defaults 2 user settings 3 user includes 4 auto-generated section unknown keys will be removed from the auto-generated section if no other errors are found detect and warn about missing newlines in headers --- ks_includes/config.py | 59 ++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/ks_includes/config.py b/ks_includes/config.py index e7def458..b3dd72e2 100644 --- a/ks_includes/config.py +++ b/ks_includes/config.py @@ -47,6 +47,8 @@ class KlipperScreenConfig: try: self.config.read(self.default_config_path) + # In case a user altered defaults.conf + self.validate_config(self.config) if self.config_path != self.default_config_path: user_def, saved_def = self.separate_saved_config(self.config_path) self.defined_config = configparser.ConfigParser() @@ -59,19 +61,16 @@ class KlipperScreenConfig: self.exclude_from_config(self.defined_config) self.log_config(self.defined_config) - self.config.read_string(user_def) + if self.validate_config(self.defined_config, string=user_def): + self.config.read_string(user_def) if saved_def is not None: - self.config.read_string(saved_def) - logging.info(f"====== Saved Def ======\n{saved_def}\n=======================") + auto_gen = configparser.ConfigParser() + auto_gen.read_string(saved_def) + if self.validate_config(auto_gen, string=saved_def, remove=True): + self.config.read_string(saved_def) + logging.info(f"====== Saved Def ======\n{saved_def}\n=======================") # This is the final config # self.log_config(self.config) - if self.validate_config(): - logging.info('Configuration validated succesfuly') - else: - logging.error('Invalid configuration detected !!!') - logging.info('Loading default config') - self.config = configparser.ConfigParser() - self.config.read(self.default_config_path) except KeyError as Kerror: msg = f"Error reading config: {self.config_path}\n{Kerror}" logging.exception(msg) @@ -139,9 +138,16 @@ class KlipperScreenConfig: self.lang = self.langs[lang] self.lang.install(names=['gettext', 'ngettext']) - def validate_config(self): + def validate_config(self, config, string="", remove=False): valid = True - for section in self.config: + if string: + msg = "Section headers have extra information after brackets possible newline issue:" + for line in string.split('\n'): + if re.match(r".+\].", line): + logging.error(line) + self.errors.append(f'{msg}\n\n{line}') + return False + for section in config: if section == 'DEFAULT' or section.startswith('include '): # Do not validate 'DEFAULT' or 'include*' sections continue @@ -175,7 +181,7 @@ class KlipperScreenConfig: ) elif section.startswith('preheat '): strs = ('gcode', '') - numbers = [f'{option}' for option in self.config[section] if option != 'gcode'] + numbers = [f'{option}' for option in config[section] if option != 'gcode'] elif section.startswith('menu '): strs = ('name', 'icon', 'panel', 'method', 'params', 'enable', 'confirm', 'style') elif section == 'bed_screws': @@ -183,25 +189,29 @@ class KlipperScreenConfig: numbers = ('rotation', '') strs = ('screw_positions', '') elif section.startswith('graph') or section.startswith('displayed_macros'): - bools = [f'{option}' for option in self.config[section]] + bools = [f'{option}' for option in config[section]] elif section.startswith('z_calibrate_position'): # This section may be deprecated in favor of moving this options under the printer section numbers = ('calibrate_x_position', 'calibrate_y_position') else: self.errors.append(f'Section [{section}] not recognized') - for key in self.config[section]: + for key in config[section]: if key not in bools and key not in strs and key not in numbers: msg = f'Option "{key}" not recognized for section "[{section}]"' - self.errors.append(msg) - # This most probably is not a big issue, continue to load the config - elif key in numbers and not self.is_float(self.config[section][key]) \ - or key in bools and self.config[section][key] not in ["False", "false", "True", "true"]: + if remove: + # This should only be called for the auto-generated section + self.config.remove_option(section, key) + else: + self.errors.append(msg) + elif key in numbers and not self.is_float(config[section][key]) \ + or key in bools and not self.is_bool(config[section][key]): msg = ( f'Unable to parse "{key}" from [{section}]\n' - f'Expected a {"number" if key in numbers else "boolean"} but got: {self.config[section][key]}' + f'Expected a {"number" if key in numbers else "boolean"} but got: {config[section][key]}' ) self.errors.append(msg) + logging.error('Invalid configuration detected !!!') valid = False return valid @@ -213,6 +223,10 @@ class KlipperScreenConfig: except ValueError: return False + @staticmethod + def is_bool(element): + return element in ["False", "false", "True", "true"] + def get_errors(self): return "".join(f'{error}\n\n' for error in self.errors) @@ -347,7 +361,10 @@ class KlipperScreenConfig: self._include_config("/".join(full_path.split("/")[:-1]), include) self.exclude_from_config(config) self.log_config(config) - self.config.read(file) + with open(file, 'r') as f: + string = f.read() + if self.validate_config(config, string=string): + self.config.read(file) def separate_saved_config(self, config_path): user_def = []