Пример #1
0
    def _check_sections(self, config, config_type, filename,
                        ignore_unknown_sections):
        config_spec = self.config_validator.get_config_spec()
        if not isinstance(config, dict):
            raise ConfigFileError("Config should be a dict: {}".format(config),
                                  1, self.log.name, filename)
        for k in config.keys():
            try:
                if config_type not in config_spec[k]['__valid_in__']:
                    raise ConfigFileError(
                        'Found a "{}:" section in config file {}, '
                        'but that section is not valid in {} config '
                        'files (only in {}).'.format(
                            k, filename, config_type,
                            config_spec[k]['__valid_in__']), 2, self.log.name,
                        filename)
            except KeyError:
                if not ignore_unknown_sections:
                    suggestion = self._find_similar_key(
                        k, config_spec, config_type)

                    raise ConfigFileError(
                        'Found a "{}:" section in config file {}, '
                        'but that section name is unknown. Did you mean "{}:" '
                        'instead?.'.format(k, filename, suggestion), 3,
                        self.log.name, filename)
Пример #2
0
 def _validate_config(self):
     if not self.ball_device.config['eject_coil']:
         raise ConfigFileError("Pulse Coil Ejector needs an eject_coil.", 1,
                               self.ball_device.log.name + "-pulse_ejector")
     #     if self.config['eject_coil_enable_time']:
     if self.ball_device.config['eject_coil_enable_time']:
         raise ConfigFileError(
             "Pulse Coil Ejector does not support eject_coil_enable_time.",
             2, self.ball_device.log.name + "-pulse_ejector")
Пример #3
0
    def check_for_invalid_sections(self, spec, config,
                                   validation_failure_info):
        """Check if all attributes are defined in spec."""
        # TODO: refactor this method
        try:
            for k in config:
                if not isinstance(k, dict):
                    if k not in spec and k[0] != '_':

                        path_list = validation_failure_info.parent.item.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 "mpf" in self.machine.config and self.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.parent.item, config), 3,
                self.log.name)
Пример #4
0
    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
Пример #5
0
    def run(self):
        """Run loop for the loader thread."""
        try:  # wrap the so we can send exceptions to the main thread
            while not self.thread_stopper.is_set():
                try:
                    asset = self.loader_queue.get(block=True, timeout=1)
                except Empty:
                    asset = None

                if asset:
                    with asset.lock:
                        if not asset.loaded:
                            try:
                                asset.do_load()
                            except Exception as e:
                                raise ConfigFileError(
                                    "Error while loading {} asset file '{}'".format(asset.attribute, asset.file),
                                    1, self.log.name, asset.name) from e
                            self.loaded_queue.put((asset, True))
                        else:
                            self.loaded_queue.put((asset, False))

            return

        # pylint: disable-msg=broad-except
        except Exception:  # pragma: no cover
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            msg = ''.join(line for line in lines)
            self.exception_queue.put(msg)
            raise
Пример #6
0
    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
Пример #7
0
 def raise_config_error(self,
                        msg,
                        error_no,
                        *,
                        source_exception=None,
                        context=None) -> NoReturn:
     """Raise a ConfigFileError exception."""
     raise ConfigFileError(msg, error_no, self.log.name if self.log else "", context, self._url_base) \
         from source_exception
Пример #8
0
    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)
Пример #9
0
 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)
Пример #10
0
    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)

        if 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

        if 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
        if 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)
        if item_type in ('dict', 'omap'):
            return self._validate_dict_or_omap(item_type, validation, validation_failure_info, item)

        raise ConfigFileError("Invalid Type '{}' in config spec {}:{}".format(item_type,
                              validation_failure_info[0][0],
                              validation_failure_info[1]), 1, self.log.name)
Пример #11
0
    def validate_and_parse_config(self, config: dict, is_mode_config: bool, debug_prefix: str = None):
        """Validate and parse spinner config."""
        config = super().validate_and_parse_config(config, is_mode_config, debug_prefix)
        for switch in config['switch']:
            if switch not in config['switches']:
                config['switches'].append(switch)

        if config['labels'] and len(config['labels']) != len(config['switches']):
            raise ConfigFileError("Spinner labels must be the same number as switches", 1, self.name)

        return config
Пример #12
0
    async 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 = await 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)
Пример #13
0
    def __init__(self, number, config, platform):
        """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, platform.machine, False)
        self.machine = platform.machine          # type: MachineController
        self.platform = platform
        self._position = None
        self._watchdog_task = None
        self._poll_task = None
        self._move_complete = asyncio.Event()
        self._switch_state = {}

        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)
Пример #14
0
    def __init__(self, config, ball_device, machine):
        """Initialise pulse coil ejector."""
        for option in ["eject_coil", "eject_coil_jam_pulse", "eject_coil_retry_pulse", "eject_coil_reorder_pulse",
                       "eject_coil_max_wait_ms", "retries_before_increasing_pulse"]:
            if option not in config and option in ball_device.config:
                config[option] = ball_device.config[option]

        super().__init__(config, ball_device, machine)

        self.config = self.machine.config_validator.validate_config("ball_device_ejector_pulse", self.config)

        # prevent conflicting options
        if "eject_coil_enable_time" in self.ball_device.config and self.ball_device.config['eject_coil_enable_time']:
            raise ConfigFileError("Pulse Coil Ejector does not support eject_coil_enable_time.", 2,
                                  self.ball_device.log.name + "-pulse_ejector")
Пример #15
0
    def _check_duplicate_light_numbers(machine: MachineController, **kwargs):
        del kwargs
        check_set = set()
        for light in machine.lights.values():
            for drivers in light.hw_drivers.values():
                for driver in drivers:
                    key = (light.config['platform'], driver.number,
                           type(driver))
                    if key in check_set:
                        raise ConfigFileError(
                            "Duplicate light number {} {} for light {}".format(
                                type(driver), driver.number, light), 10,
                            "light", key, "light")

                    check_set.add(key)
Пример #16
0
    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
Пример #17
0
    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.", 1, self.log.name)

        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)
Пример #18
0
    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 validator[-1:] == ')':
            validator_parts = validator.split('(', maxsplit=1)
            validator = validator_parts[0]
            param = validator_parts[1][:-1]
            return self.validator_list[validator](item, validation_failure_info=validation_failure_info, param=param)
        if validator in self.validator_list:
            return self.validator_list[validator](item, validation_failure_info=validation_failure_info)

        raise ConfigFileError("Invalid Validator '{}' in config spec {}:{}".format(
                              validator,
                              validation_failure_info[0][0],
                              validation_failure_info[1]), 4, self.log.name)
Пример #19
0
 def _show_validation_error(self, msg, error_code) -> "NoReturn":  # pragma: no cover
     raise ConfigFileError('"{}" >> {}'.format(self.name, msg), error_code, "show", self.name)
Пример #20
0
 def raise_config_error(self, msg, error_no, *, context=None):
     """Raise a ConfigFileError exception."""
     raise ConfigFileError(msg, error_no, self.log.name, context,
                           self._url_base)
Пример #21
0
    async def _initialize(self):
        await super()._initialize()
        self.platform = self.machine.get_platform_sections(
            'switches', self.config['platform'])

        if self.config['type'].upper() == 'NC':
            self.invert = 1

        self.recycle_secs = self.config['ignore_window_ms'] / 1000.0

        config = SwitchConfig(name=self.name,
                              invert=self.invert,
                              debounce=self.config['debounce'])
        if not self.platform.features[
                'allow_empty_numbers'] and self.config['number'] is None:
            self.raise_config_error("Switch must have a number.", 1)

        try:
            self.hw_switch = self.platform.configure_switch(
                self.config['number'], config,
                self.config['platform_settings'])
        except AssertionError as e:
            raise ConfigFileError(
                "Failed to configure switch {} in platform. See error above".
                format(self.name), 2, self.class_label) from e

        if self.recycle_secs:
            self.add_handler(state=1,
                             callback=self._post_events_with_recycle,
                             callback_kwargs={"state": 1})
            self.add_handler(state=0,
                             callback=self._post_events_with_recycle,
                             callback_kwargs={"state": 0})
        else:
            self.add_handler(state=1,
                             callback=self._post_events,
                             callback_kwargs={"state": 1})
            self.add_handler(state=0,
                             callback=self._post_events,
                             callback_kwargs={"state": 0})

        if self.machine.config['mpf']['auto_create_switch_events']:
            self._create_activation_event(
                self.machine.config['mpf']['switch_event_active'].replace(
                    '%', self.name), 1)
            '''event: (name)_active
            desc: Posted when this switch becomes active.
            Note that this will only be posted if there is an event handler for it or if debug is set to True on this
            switch for performance reasons.
            '''
            self._create_activation_event(
                self.machine.config['mpf']['switch_event_inactive'].replace(
                    '%', self.name), 0)
            '''event: (name)_inactive
            desc: Posted when this switch becomes inactive.
            Note that this will only be posted if there is an event handler for it or if debug is set to True on this
            switch for performance reasons.
            '''

        for tag in self.tags:
            self._create_activation_event(
                self.machine.config['mpf']['switch_tag_event'].replace(
                    '%', tag), 1)
            '''event: sw_(tag)
            desc: Posted when a switch with this tag becomes active.
            Note that this will only be posted if there is an event handler for it or if debug is set to True on this
            switch for performance reasons.
            '''
            self._create_activation_event(
                self.machine.config['mpf']['switch_tag_event'].replace(
                    '%', tag) + "_active", 1)
            '''event: sw_(tag)_active
            desc: Posted when a switch with this tag becomes active.
            Note that this will only be posted if there is an event handler for it or if debug is set to True on this
            switch for performance reasons.
            '''
            self._create_activation_event(
                self.machine.config['mpf']['switch_tag_event'].replace(
                    '%', tag) + "_inactive", 0)
            '''event: sw_(tag)_inactive
            desc: Posted when a switch with this tag becomes inactive.
            Note that this will only be posted if there is an event handler for it or if debug is set to True on this
            switch for performance reasons.
            '''

        for event in Util.string_to_event_list(
                self.config['events_when_activated']):
            self._create_activation_event(event, 1)

        for event in Util.string_to_event_list(
                self.config['events_when_deactivated']):
            self._create_activation_event(event, 0)
Пример #22
0
    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!@#':
                section = self._build_error_path(
                    validation_failure_info.parent)
                self.validation_error(
                    "None", validation_failure_info,
                    'Required setting "{}:" is missing from section "{}:" in your config.'
                    .format(validation_failure_info.item, section), 9)
            else:
                item = default

        if item_type == 'single':
            return self.validate_item(item, validation,
                                      validation_failure_info)

        if item_type == 'list':
            if validation in ("event_posted", "event_handler"):
                item_list = Util.string_to_list(item)
            else:
                item_list = Util.string_to_event_list(item)

            new_list = list()

            for i in item_list:
                if i in ("", " "):
                    self.validation_error(item, validation_failure_info,
                                          "List contains an empty element.",
                                          15)
                new_list.append(
                    self.validate_item(i, validation, validation_failure_info))

            return new_list

        if 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
        if item_type == "event_handler":
            if validation != "event_handler:ms":
                raise AssertionError(
                    "event_handler should use event_handler:ms in config_spec: {}"
                    .format(spec))
            return self._validate_dict_or_omap(item_type, validation,
                                               validation_failure_info, item)
        if item_type in ('dict', 'omap'):
            return self._validate_dict_or_omap(item_type, validation,
                                               validation_failure_info, item)

        raise ConfigFileError(
            "Invalid Type '{}' in config spec {}".format(
                item_type, self._build_error_path(validation_failure_info)), 1,
            self.log.name)