def validation_error(cls, item, validation_failure_info, msg=""): """Raise a validation error with all relevant infos.""" raise ConfigFileError( "Config validation error: Entry {}:{}:{}:{} is not valid. {}". format(validation_failure_info[0][0], validation_failure_info[0][1], validation_failure_info[1], item, msg))
def get_hw_switch_states(self): """Return hw switch states.""" if not self.initial_states_sent: if 'virtual_platform_start_active_switches' in self.machine.config: initial_active_switches = [] for switch in Util.string_to_list( self.machine. config['virtual_platform_start_active_switches']): if switch not in self.machine.switches: raise ConfigFileError( "Switch {} used in virtual_platform_start_active_switches was not found " "in switches section.".format(switch), 1, self.log.name) initial_active_switches.append( self.machine.switches[switch].hw_switch.number) for k in self.hw_switches: if k in initial_active_switches: self.hw_switches[k] ^= 1 self.initial_states_sent = True else: switches = [x for x in self.machine.switches if x.platform == self] for switch in switches: self.hw_switches[ switch.hw_switch.number] = switch.state ^ switch.invert return self.hw_switches
def validate_config_entry(self, settings, name): """Validate one entry of this player.""" validated_config = dict() # settings here is the same as a show entry, so we process with # that if not isinstance(settings, dict): if isinstance(settings, (str, int, float)): settings = self.get_string_config(settings) else: raise AssertionError( "Invalid settings for player {}:{} {}".format( name, self.show_section, settings)) # settings here are dicts of devices/settings for device, device_settings in settings.items(): try: validated_config.update( self._validate_config_item(device, device_settings)) except ConfigFileError as e: raise ConfigFileError( "Failed to load config player {}:{} {}".format( name, self.show_section, settings), 1, self.log.name) from e return validated_config
def validate_item(self, item, validator, validation_failure_info): """Validate an item using a validator.""" try: if item.lower() == 'none': item = None except AttributeError: pass if '(' in validator and ')' in validator[-1:] == ')': validator_parts = validator.split('(') validator = validator_parts[0] param = validator_parts[1][:-1] return self.validator_list[validator]( item, validation_failure_info=validation_failure_info, param=param) elif validator in self.validator_list: return self.validator_list[validator]( item, validation_failure_info=validation_failure_info) else: raise ConfigFileError( "Invalid Validator '{}' in config spec {}:{}".format( validator, validation_failure_info[0][0], validation_failure_info[1]), 4, self.log.name)
def check_for_invalid_sections(self, spec, config, validation_failure_info): """Check if all attributes are defined in spec.""" try: for k in config: if not isinstance(k, dict): if k not in spec and k[0] != '_': path_list = validation_failure_info[0].split(':') if len(path_list) > 1 and path_list[ -1] == validation_failure_info[1]: path_list.append('[list_item]') elif path_list[0] == validation_failure_info[1]: path_list = list() path_list.append(validation_failure_info[1]) path_list.append(k) path_string = ':'.join(path_list) if self.machine.machine_config['mpf'][ 'allow_invalid_config_sections']: self.log.warning( 'Unrecognized config setting. "%s" is ' 'not a valid setting name.', path_string) else: self.log.error( 'Your config contains a value for the ' 'setting "%s", but this is not a valid ' 'setting name.', path_string) raise ConfigFileError( 'Your config contains a value for the ' 'setting "' + path_string + '", but this is not a valid ' 'setting name.', 2, self.log.name) except TypeError: raise ConfigFileError( 'Error in config. Your "{}:" section contains a value that is ' 'not a parent with sub-settings: {}'.format( validation_failure_info[0], config), 3, self.log.name)
def _load_config_file_and_return_loaded_files( self, filename, config_type: str, ignore_unknown_sections=False ) -> Tuple[dict, List[str]]: # pragma: no cover """Load a config file and return loaded files.""" # config_type is str 'machine' or 'mode', which specifies whether this # file being loaded is a machine config or a mode config file expected_version_str = ConfigProcessor.get_expected_version( config_type) config = FileManager.load(filename, expected_version_str, True) subfiles = [] if not ConfigValidator.config_spec: ConfigValidator.load_config_spec() if not config: return dict(), [] self.log.info('Loading config: %s', filename) if config_type in ("machine", "mode"): if not isinstance(config, dict): raise ConfigFileError( "Config should be a dict: {}".format(config), self.log.name, "ConfigProcessor") for k in config.keys(): try: if config_type not in ConfigValidator.config_spec[k][ '__valid_in__']: raise ValueError( 'Found a "{}:" section in config file {}, ' 'but that section is not valid in {} config ' 'files.'.format(k, filename, config_type)) except KeyError: if not ignore_unknown_sections: raise ValueError( 'Found a "{}:" section in config file {}, ' 'but that section is not valid in {} config ' 'files.'.format(k, filename, config_type)) try: if 'config' in config: path = os.path.split(filename)[0] for file in Util.string_to_list(config['config']): full_file = os.path.join(path, file) subfiles.append(full_file) subconfig, subsubfiles = self._load_config_file_and_return_loaded_files( full_file, config_type) subfiles.extend(subsubfiles) config = Util.dict_merge(config, subconfig) return config, subfiles except TypeError: return dict(), []
def device_added_system_wide(self): """Initialise internal state.""" super().device_added_system_wide() if self.config['persist_state']: raise ConfigFileError( "Cannot set persist_state for system-wide state_machine in {}". format(self.name)) self._start_state("start")
def __init__(self, number, config, machine): """Initialise stepper.""" self.config = config self.log = logging.getLogger('TIC Stepper') self.log.debug("Configuring Stepper Parameters.") self.serial_number = number self.tic = PololuTiccmdWrapper(self.serial_number, machine, False) self.machine = machine self._position = None self._watchdog_task = None if self.config['step_mode'] not in [1, 2, 4, 8, 16, 32]: raise ConfigFileError("step_mode must be one of (1, 2, 4, 8, 16, or 32)", 1, self.log.name) if self.config['max_speed'] <= 0: raise ConfigFileError("max_speed must be greater than 0", 2, self.log.name) if self.config['max_speed'] > 500000000: raise ConfigFileError("max_speed must be less than or equal to 500,000,000", 3, self.log.name)
def validation_error(self, item, validation_failure_info, msg="", code=None): """Raise a validation error with all relevant infos.""" raise ConfigFileError( "Config validation error: Entry {} = \"{}\" is not valid. {}". format(self._build_error_path(validation_failure_info), item, msg), 5 if code is None else code, self.log.name)
def validate_config_item(self, spec, validation_failure_info, item='item not in config!@#', ): """Validate a config item.""" try: item_type, validation, default = spec except (ValueError, AttributeError): raise ValueError('Error in validator spec: {}:{}'.format( validation_failure_info, spec)) if default.lower() == 'none': default = None elif not default: default = 'default required!@#' if item == 'item not in config!@#': if default == 'default required!@#': self.validation_error("None", validation_failure_info, 'Required setting {} missing from config file.'.format( validation_failure_info[1]), 9) else: item = default if item_type == 'single': return self.validate_item(item, validation, validation_failure_info) elif item_type == 'list': item_list = Util.string_to_list(item) new_list = list() for i in item_list: new_list.append(self.validate_item(i, validation, validation_failure_info)) return new_list elif item_type == 'set': item_set = set(Util.string_to_list(item)) new_set = set() for i in item_set: new_set.add(self.validate_item(i, validation, validation_failure_info)) return new_set elif item_type == "event_handler": if validation != "str:ms": raise AssertionError("event_handler should use str:ms in config_spec: {}".format(spec)) return self._validate_dict_or_omap(item_type, validation, validation_failure_info, item) elif item_type in ('dict', 'omap'): return self._validate_dict_or_omap(item_type, validation, validation_failure_info, item) else: raise ConfigFileError("Invalid Type '{}' in config spec {}:{}".format(item_type, validation_failure_info[0][0], validation_failure_info[1]), 1, self.log.name)
def configure_servo(self, number: str): """Configure servo.""" try: i2c_address, servo_number = number.rsplit("-", 1) except ValueError: servo_number = number i2c_address = 0x40 try: number_int = int(servo_number) except ValueError: raise ConfigFileError("Invalid servo number {} in {}.".format(servo_number, number), 2, self.log.name) i2c_device = yield from self._initialize_controller(i2c_address) # check bounds if number_int < 0 or number_int > 15: raise ConfigFileError("Invalid number {} in {}. The controller only supports servos 0 to 15.".format( number_int, number), 1, self.log.name) return I2cServo(number_int, self.config, i2c_device)
def device_added_system_wide(self): """Initialise internal state.""" self._state = LogicBlockState(self.get_start_value()) super().device_added_system_wide() if not self.config['enable_events']: self.enable() if self.config['persist_state']: raise ConfigFileError( "Cannot set persist_state for system-wide logic_blocks in {}". format(self.name)) self.post_update_event()
def register_player_events(self, config, mode: Mode = None, priority=0): """Register events for standalone player.""" # config is localized key_list = list() subscription_list = dict() # type: Dict[BoolTemplate, asyncio.Future] if config: for event, settings in config.items(): # prevent runtime crashes if (not mode or (mode and not mode.is_game_mode) ) and not self.is_entry_valid_outside_mode(settings): raise ConfigFileError( "Section not valid outside of game modes. {} {}:{} Mode: {}" .format(self, event, settings, mode), 1, self.config_file_section) if event.startswith("{") and event.endswith("}"): condition = event[1:-1] self._create_subscription(condition, subscription_list, settings, priority, mode) else: event, actual_priority = self._parse_event_priority( event, priority) if mode and event in mode.config['mode']['start_events']: self.machine.log.error( "{0} mode's {1}: section contains a \"{2}:\" event " "which is also in the start_events: for the {0} mode. " "Change the {1}: {2}: event name to " "\"mode_{0}_started:\"".format( mode.name, self.config_file_section, event)) raise ValueError( "{0} mode's {1}: section contains a \"{2}:\" event " "which is also in the start_events: for the {0} mode. " "Change the {1}: {2}: event name to " "\"mode_{0}_started:\"".format( mode.name, self.config_file_section, event)) key_list.append( self.machine.events.add_handler( event=event, handler=self.config_play_callback, calling_context=event, priority=actual_priority, mode=mode, settings=settings)) return key_list, subscription_list
def __init__(self, machine): """Initialise RGB DMD.""" super().__init__(machine) self.features['tickless'] = True self.log = logging.getLogger('SmartMatrix') self.log.debug("Configuring SmartMatrix RGB DMD hardware interface.") self.devices = dict() # type: Dict[str, SmartMatrixDevice] if not isinstance(self.machine.config['smartmatrix'], dict): raise ConfigFileError("Smartmatrix config needs to be a dict.") for name, config in self.machine.config['smartmatrix'].items(): config = self.machine.config_validator.validate_config( config_spec='smartmatrix', source=config) self.devices[name] = SmartMatrixDevice(config, machine)
def validate_item(self, item, validator, validation_failure_info): """Validate an item using a validator.""" try: if item.lower() == 'none': item = None except AttributeError: pass if ':' in validator: validator = validator.split(':') # item could be str, list, or list of dicts item = Util.event_config_to_dict(item) return_dict = dict() for k, v in item.items(): return_dict[self.validate_item( k, validator[0], validation_failure_info)] = (self.validate_item( v, validator[1], validation_failure_info)) return return_dict elif '(' in validator and ')' in validator[-1:] == ')': validator_parts = validator.split('(') validator = validator_parts[0] param = validator_parts[1][:-1] return self.validator_list[validator]( item, validation_failure_info=validation_failure_info, param=param) elif validator in self.validator_list: return self.validator_list[validator]( item, validation_failure_info=validation_failure_info) else: raise ConfigFileError( "Invalid Validator '{}' in config spec {}:{}".format( validator, validation_failure_info[0][0], validation_failure_info[1]), 4, self.log.name)
def validate_config_item(self, spec, validation_failure_info, item='item not in config!@#', ): """Validate a config item.""" try: item_type, validation, default = spec.split('|') except (ValueError, AttributeError): raise ValueError('Error in validator spec: {}:{}'.format( validation_failure_info, spec)) if default.lower() == 'none': default = None elif not default: default = 'default required!@#' if item == 'item not in config!@#': if default == 'default required!@#': raise ValueError('Required setting missing from config file. ' 'Run with verbose logging and look for the last ' 'ConfigProcessor entry above this line to see where the ' 'problem is. {} {}'.format(spec, validation_failure_info)) else: item = default if item_type == 'single': return self.validate_item(item, validation, validation_failure_info) elif item_type == 'list': item_list = Util.string_to_list(item) new_list = list() for i in item_list: new_list.append(self.validate_item(i, validation, validation_failure_info)) return new_list elif item_type == 'set': item_set = set(Util.string_to_list(item)) new_set = set() for i in item_set: new_set.add(self.validate_item(i, validation, validation_failure_info)) return new_set elif item_type == 'dict': item_dict = self.validate_item(item, validation, validation_failure_info) if not item_dict: return dict() else: return item_dict else: raise ConfigFileError("Invalid Type '{}' in config spec {}:{}".format(item_type, validation_failure_info[0][0], validation_failure_info[1]))
def raise_config_error(self, msg, error_no): """Raise a ConfigFileError exception.""" raise ConfigFileError(msg, error_no, self.log.name)
def raise_config_error(self, msg, error_no, *, context=None): """Raise a ConfigFileError exception.""" raise ConfigFileError(msg, error_no, self.log.name, context)