def test_yaml_patches(self): # tests our patches to the yaml processor config = """ str_1: +1 str_2: 032 str_3: on str_4: off str_5: 123e45 bool_1: yes bool_2: no bool_3: true bool_4: false str_6: hi int_1: 123 float_1: 1.0 """ parsed_config = YamlInterface.process(config, True) for k, v in parsed_config.items(): if not type(v) is eval(k.split('_')[0]): raise AssertionError('YAML value "{}" is {}, not {}'.format( v, type(v), eval(k.split('_')[0])))
def load_mode_config_spec(cls, mode_string, config_spec): """Load config specs for a mode.""" if '_mode_settings' not in cls.config_spec: cls.config_spec['_mode_settings'] = {} if mode_string not in cls.config_spec['_mode_settings']: cls.config_spec['_mode_settings'][ mode_string] = YamlInterface.process(config_spec)
def load_config_spec(self): """Load config spec.""" if ConfigValidator.class_cache: self.config_spec = ConfigValidator.class_cache return cache_file = os.path.join(self.get_cache_dir(), "config_spec.mpf_cache") config_spec_file = os.path.abspath( os.path.join(mpf.core.__path__[0], os.pardir, "config_spec.yaml")) if os.path.isfile(cache_file) and os.path.getmtime( cache_file) >= os.path.getmtime(config_spec_file): try: with open(cache_file, 'rb') as f: self.config_spec = pickle.load(f) # nosec ConfigValidator.class_cache = deepcopy(self.config_spec) return except Exception: # noqa pass with open(config_spec_file, 'rb') as f: config_str = f.read() config = YamlInterface.process(config_str) config = self._process_config_spec(config, "root") self.config_spec = config self.machine.load_external_platform_config_specs() with open(cache_file, 'wb') as f: pickle.dump(config, f, protocol=4) self.log.info('Config spec file cache created: %s', cache_file) ConfigValidator.class_cache = deepcopy(self.config_spec)
def load_mode_config_spec(self, mode_string, config_spec): """Load config specs for a mode.""" if '_mode_settings' not in self.config_spec: self.config_spec['_mode_settings'] = {} if mode_string not in self.config_spec['_mode_settings']: config = YamlInterface.process(config_spec) self.config_spec['_mode_settings'][mode_string] = self._process_config_spec(config, mode_string)
def send_slide_to_mc(self, value): del value try: settings = YamlInterface.process(self.slide_player_code.text) except Exception as e: msg = str(e).replace('"', '\n') Popup(title='Error in your config', content=Label(text=msg, size=(750, 350)), size_hint=(None, None), size=(Window.width, 400)).open() return try: settings = (self.slide_player.validate_config_entry( settings, 'slides')) except Exception as e: msg = str(e).replace('"', '\n') Popup(title='Error in your config', content=Label(text=msg, size=(750, 350)), size_hint=(None, None), size=(Window.width, 400)).open() return if self._initialized: self.slide_player.clear_context('imc') else: self._initialized = True self.slide_player.play(settings, 'imc', 100) self.clock.loop.run_until_complete( asyncio.sleep(.1, loop=self.clock.loop))
def load_external_platform_config_specs(self, config): """Load config spec for external platforms.""" for platform_entry in iter_entry_points(group='mpf.platforms'): config_spec = platform_entry.load().get_config_spec() if config_spec: # add specific config spec if platform has any config[config_spec[1]] = self._process_config_spec( YamlInterface.process(config_spec[0]), config_spec[1]) return config
def load_device_config_specs(config_spec, machine_config): """Load device config specs.""" for device_type in machine_config['mpf']['device_modules'].values(): device_cls = Util.string_to_class(device_type) # type: Device if device_cls.get_config_spec(): # add specific config spec if device has any config_spec[device_cls.config_section] = ConfigSpecLoader.process_config_spec( YamlInterface.process(device_cls.get_config_spec()), device_cls.config_section) return config_spec
def load_device_config_specs(self, config_spec, machine_config): """Load device config specs.""" for device_type in machine_config['mpf']['device_modules']: device_cls = Util.string_to_class(device_type) if device_cls.get_config_spec(): # add specific config spec if device has any config_spec[device_cls.config_section] = self._process_config_spec( YamlInterface.process(device_cls.get_config_spec()), device_cls.config_section) return config_spec
def load_mode_config_spec(self, mode_string, config_spec): """Load config specs for a mode.""" if '_mode_settings' not in self.config_spec: self.config_spec['_mode_settings'] = {} if mode_string not in self.config_spec['_mode_settings']: if isinstance(config_spec, dict): self.config_spec['_mode_settings'][mode_string] = \ ConfigSpecLoader.process_config_spec(config_spec, mode_string) else: config = YamlInterface.process(config_spec) self.config_spec['_mode_settings'][mode_string] = \ ConfigSpecLoader.process_config_spec(config, mode_string)
def send_slide_to_mc(self, value): del value settings = YamlInterface.process(self.slide_player_code.text) try: settings = (self.slide_player.validate_config_entry( settings, 'slides')) except AssertionError as e: msg = str(e).replace('"', '\n') Popup(title='Error in your config', content=Label(text=msg, size=(750, 350)), size_hint=(None, None), size=(Window.width, 400)).open() return if self._initialized: self.slide_player.clear_context('imc') else: self._initialized = True self.slide_player.play(settings, 'imc', None, force=True)
def load_config_spec(cls, config_spec=None): """Load config specs.""" if not config_spec: config_spec = mpf_config_spec cls.config_spec = YamlInterface.process(config_spec)
def load_device_config_spec(cls, config_section, config_spec): """Load config specs for a device.""" cls.config_spec[config_section] = YamlInterface.process(config_spec)
def test_round_trip(self): orig_config = """\ hardware: platform: smart_virtual driverboards: virtual dmd: smartmatrix config: - portconfig.yaml - switches.yaml - coils.yaml - devices.yaml - keyboard.yaml - virtual.yaml - images.yaml dmd: physical: false width: 128 height: 32 type: color window: elements: - type: virtualdmd width: 512 height: 128 h_pos: center v_pos: center pixel_color: ff6600 dark_color: 220000 pixel_spacing: 1 - type: shape shape: box width: 516 height: 132 color: aaaaaa thickness: 2 modes: - base - airlock_multiball sound_system: buffer: 512 frequency: 44100 channels: 1 initial_volume: 1 volume_steps: 20 tracks: voice: volume: 1 priority: 2 simultaneous_sounds: 1 preload: false sfx: volume: 1 priority: 1 preload: false simultaneous_sounds: 3 stream: name: music priority: 0 """ parsed_config = YamlInterface.process(orig_config, True) saved_config = YamlInterface.save_to_str(parsed_config) # print(saved_config) self.assertEqual(orig_config, saved_config)
def load_device_config_spec(self, config_section, config_spec): """Load config specs for a device.""" self.config_spec[config_section] = self._process_config_spec( YamlInterface.process(config_spec), config_section)
class Document(object): def __init__(self, uri, source=None, version=None, local=True, extra_sys_path=None): self.uri = uri self.version = version self.path = uris.to_fs_path(uri) self.filename = os.path.basename(self.path) self._local = local self._source = source self._extra_sys_path = extra_sys_path or [] self._config_simple = {} self._config_roundtrip = {} self._last_config_simple = {} self._last_config_roundtrip = {} self._loader_roundtrip = YamlRoundtrip() self._loader_simple = YamlInterface() def invalidate_config(self): self._last_config_simple = {} self._config_roundtrip = {} @property def config_roundtrip(self): if not self._config_roundtrip: self._load_config_roundtrip() if not self._config_roundtrip: return self._last_config_roundtrip else: return self._config_roundtrip def _load_config_roundtrip(self): try: self._config_roundtrip = self._loader_roundtrip.process( self.source) except: self._parsing_failed = True else: self._parsing_failed = False self._last_config_roundtrip = self._config_roundtrip @property def config_simple(self): if not self._config_simple: self._load_config_simple() if not self._config_simple: return self._last_config_simple else: return self._config_simple def _load_config_simple(self): try: self._config_simple = self._loader_simple.process(self.source) except: self._parsing_failed = True else: self._parsing_failed = False self._last_config_simple = self._config_simple def __str__(self): return str(self.uri) @property def lines(self): return self.source.splitlines(True) @property def source(self): if self._source is None: with io.open(self.path, 'r', encoding='utf-8') as f: return f.read() return self._source def apply_change(self, change): """Apply a change to the document.""" text = change['text'] change_range = change.get('range') if not change_range: # The whole file has changed self._source = text self.invalidate_config() return start_line = change_range['start']['line'] start_col = change_range['start']['character'] end_line = change_range['end']['line'] end_col = change_range['end']['character'] # Check for an edit occuring at the very end of the file if start_line == len(self.lines): self._source = self.source + text self.invalidate_config() return new = io.StringIO() # Iterate over the existing document until we hit the edit range, # at which point we write the new text, then loop until we hit # the end of the range and continue writing. for i, line in enumerate(self.lines): if i < start_line: new.write(line) continue if i > end_line: new.write(line) continue if i == start_line: new.write(line[:start_col]) new.write(text) if i == end_line: new.write(line[end_col:]) self._source = new.getvalue() self.invalidate_config() def offset_at_position(self, position): """Return the byte-offset pointed at by the given position.""" return position['character'] + len(''.join( self.lines[:position['line']])) def word_at_position(self, position): """Get the word under the cursor returning the start and end positions.""" if position['line'] >= len(self.lines): return '' line = self.lines[position['line']] i = position['character'] # Split word in two start = line[:i] end = line[i:] # Take end of start and start of end to find word # These are guaranteed to match, even if they match the empty string m_start = RE_START_WORD.findall(start) m_end = RE_END_WORD.findall(end) return m_start[0] + m_end[-1] def sys_path(self): # Copy our extra sys path path = list(self._extra_sys_path) return path