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 = YamlRoundtrip.process(config) 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 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 str_6: hi str_7: 2:10 str_8: 2:10.1 bool_1: yes bool_2: no bool_3: true bool_4: false bool_5: True bool_6: False int_1: 123 yaml.scalarfloat.ScalarFloat_1: 1.0 """ values = { "str_1": "+1", "str_2": "032", "str_3": "on", "str_4": "off", "str_5": "123e45", "str_6": "hi", "str_7": "2:10", "str_8": "2:10.1", "bool_1": True, "bool_2": False, "bool_3": True, "bool_4": False, "bool_5": True, "bool_6": False, "int_1": 123, "yaml.scalarfloat.ScalarFloat_1": 1.0, } parsed_config = YamlRoundtrip.process(config) 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]))) self.assertEqual(values[k], v)
def test_round_trip(self): self.maxDiff = None 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 = YamlRoundtrip.process(orig_config) saved_config = YamlRoundtrip.save_to_str(parsed_config) # print(saved_config) self.assertEqual(orig_config, saved_config)
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