def _get_dictionary_save_name(self, title, default_name=None, default_extensions=(), initial_filename=None): if default_name is not None: # Default to a writable dictionary format. writable_extensions = set( _dictionary_formats(include_readonly=False)) default_name += '.' + next( (e for e in default_extensions if e in writable_extensions), 'json') default_name = os.path.join(self._file_dialogs_directory, default_name) else: default_name = self._file_dialogs_directory new_filename = QFileDialog.getSaveFileName( parent=self, caption=title, directory=default_name, filter=_dictionary_filters(include_readonly=False), )[0] if not new_filename: return None new_filename = normalize_path(new_filename) self._file_dialogs_directory = os.path.dirname(new_filename) if new_filename == initial_filename: return None return new_filename
def test_dictionaries_option(self): section = config.SYSTEM_CONFIG_SECTION % config.DEFAULT_SYSTEM_NAME option = config.SYSTEM_DICTIONARIES_OPTION legacy_section = config.LEGACY_DICTIONARY_CONFIG_SECTION legacy_option = config.LEGACY_DICTIONARY_FILE_OPTION c = config.Config() config_dir = os.path.normcase(os.path.realpath(config.CONFIG_DIR)) # Check the default value. self.assertEqual(c.get_dictionaries(), [DictionaryConfig(path) for path in system.DEFAULT_DICTIONARIES]) # Load from a file encoded the ancient way... filename = normalize_path('/some_file') f = make_config('[%s]\n%s: %s' % (legacy_section, legacy_option, filename)) c.load(f) # ..and make sure the right value is set. self.assertEqual(c.get_dictionaries(), [DictionaryConfig(filename)]) # Load from a file encoded the old way... filenames = [os.path.join(ABS_PATH, f) for f in ('b', 'a', 'd', 'c')] dictionaries = [DictionaryConfig(path) for path in filenames] value = '\n'.join('%s%d: %s' % (legacy_option, d, v) for d, v in enumerate(reversed(filenames), start=1)) f = make_config('[%s]\n%s' % (legacy_section, value)) c.load(f) # ...and make sure the right value is set. self.assertEqual(c.get_dictionaries(), dictionaries) # Check the config is saved back converted to the new way. f = make_config() c.save(f) new_config_contents = '[%s]\n%s = %s\n\n' % ( section, option, json.dumps([ {'path': path, 'enabled': True} for path in filenames ], sort_keys=True)) self.assertEqual(f.getvalue().decode('utf-8'), new_config_contents) # Load from a file encoded the new way... f = make_config(new_config_contents) c.load(f) # ...and make sure the right value is set. self.assertEqual(c.get_dictionaries(), dictionaries) # Set a value... dictionaries.reverse() filenames.reverse() c.set_dictionaries(dictionaries) f = make_config() # ...save it... c.save(f) # ...and make sure it's right. new_config_contents = '[%s]\n%s = %s\n\n' % ( section, option, json.dumps([ {'path': path, 'enabled': True} for path in filenames ], sort_keys=True)) self.assertEqual(f.getvalue().decode('utf-8'), new_config_contents) # The new way must take precedence over the old way. legacy_value = '\n'.join('%s%d = %s' % (legacy_option, d, v) for d, v in enumerate(['/foo', '/bar'], start=1)) f = make_config(new_config_contents + '\n[%s]\n%s\n' % ( legacy_section, legacy_value)) c.load(f) self.assertEqual(c.get_dictionaries(), dictionaries)
def _create_new_dictionary(self): new_filename = QFileDialog.getSaveFileName( self, _('New dictionary'), None, _dictionary_filters(include_readonly=False), )[0] if not new_filename: return new_filename = normalize_path(new_filename) try: d = create_dictionary(new_filename, threaded_save=False) d.save() except: log.error('creating dictionary %s failed', new_filename, exc_info=True) return dictionaries = self._config_dictionaries[:] for d in dictionaries: if d.path == new_filename: break else: dictionaries.insert(0, DictionaryConfig(new_filename)) # Note: pass in `loaded_dictionaries` to force update (use case: # the user decided to overwrite an already loaded dictionary). self._update_dictionaries( dictionaries, keep_selection=False, loaded_dictionaries=self._loaded_dictionaries)
def handle(self, words=None): if not words: self.output("Filename must be provided") return True else: filename = normalize_path(' '.join(words)) with open(filename, 'a') as f: f.write(self.tape_buffer.text) self.output(f"Saved tape to {filename}") return True
def test_simple_fields(self): Case = namedtuple('Case', ['field', 'section', 'option', 'default', 'value1', 'value2', 'value3']) cases = ( ('machine_type', config.MACHINE_CONFIG_SECTION, config.MACHINE_TYPE_OPTION, config.DEFAULT_MACHINE_TYPE, 'Gemini PR', 'TX Bolt', 'Passport'), ('log_file_name', config.LOGGING_CONFIG_SECTION, config.LOG_FILE_OPTION, normalize_path(os.path.join(CONFIG_DIR, config.DEFAULT_LOG_FILE)), os.path.join(ABS_PATH, 'l1'), os.path.join(ABS_PATH, 'log'), os.path.join(ABS_PATH, 'sawzall')), ('enable_stroke_logging', config.LOGGING_CONFIG_SECTION, config.ENABLE_STROKE_LOGGING_OPTION, config.DEFAULT_ENABLE_STROKE_LOGGING, False, True, False), ('enable_translation_logging', config.LOGGING_CONFIG_SECTION, config.ENABLE_TRANSLATION_LOGGING_OPTION, config.DEFAULT_ENABLE_TRANSLATION_LOGGING, False, True, False), ('auto_start', config.MACHINE_CONFIG_SECTION, config.MACHINE_AUTO_START_OPTION, config.DEFAULT_MACHINE_AUTO_START, True, False, True), ('show_stroke_display', config.STROKE_DISPLAY_SECTION, config.STROKE_DISPLAY_SHOW_OPTION, config.DEFAULT_STROKE_DISPLAY_SHOW, True, False, True), ('space_placement', config.OUTPUT_CONFIG_SECTION, config.OUTPUT_CONFIG_SPACE_PLACEMENT_OPTION, config.DEFAULT_OUTPUT_CONFIG_SPACE_PLACEMENT, 'Before Output', 'After Output', 'None'), ) for case in cases: case = Case(*case) c = config.Config() getter = getattr(c, 'get_' + case.field) setter = getattr(c, 'set_' + case.field) # Check the default value. self.assertEqual(getter(), case.default) # Set a value... setter(case.value1) # ...and make sure it is really set. self.assertEqual(getter(), case.value1) # Load from a file... f = make_config('[%s]\n%s: %s' % (case.section, case.option, case.value2)) c.load(f) # ..and make sure the right value is set. self.assertEqual(getter(), case.value2) # Set a value... setter(case.value3) f = make_config() # ...save it... c.save(f) # ...and make sure it's right. self.assertEqual(f.getvalue().decode('utf-8'), '[%s]\n%s = %s\n\n' % (case.section, case.option, case.value3))
def handle(self, words=[]): path = normalize_path(" ".join(words)) if not isfile(path): self.output(f"{path} is not a file") return True with self.engine: self.output(f"Adding {path} as a dictionary") dicts = self.engine.config["dictionaries"].copy() dicts.insert(0, DictionaryConfig(path)) self.engine.config = {"dictionaries": dicts} return True
def make_dict(contents, extension=None, name=None): kwargs = {'delete': False} if name is not None: kwargs['prefix'] = name + '_' if extension is not None: kwargs['suffix'] = '.' + extension tf = tempfile.NamedTemporaryFile(**kwargs) try: tf.write(contents) tf.close() yield normalize_path(tf.name) finally: os.unlink(tf.name)
def _add_existing_dictionaries(self): new_filenames = QFileDialog.getOpenFileNames( self, _('Add dictionaries'), None, _dictionary_filters(), )[0] dictionaries = self._config_dictionaries[:] for filename in new_filenames: filename = normalize_path(filename) for d in dictionaries: if d.path == filename: break else: dictionaries.insert(0, DictionaryConfig(filename)) self._update_dictionaries(dictionaries, keep_selection=False)
def make_dict(contents, extension=None, name=None): kwargs = { 'delete': False } if name is not None: kwargs['prefix'] = name + '_' if extension is not None: kwargs['suffix'] = '.' + extension tf = tempfile.NamedTemporaryFile(**kwargs) try: tf.write(contents) tf.close() yield normalize_path(tf.name) finally: os.unlink(tf.name)
def _add_existing_dictionaries(self): new_filenames = QFileDialog.getOpenFileNames( # i18n: Widget: “DictionariesWidget”, “add” file picker. parent=self, caption=_('Add dictionaries'), directory=self._file_dialogs_directory, filter=_dictionary_filters(), )[0] dictionaries = self._config_dictionaries[:] for filename in new_filenames: filename = normalize_path(filename) self._file_dialogs_directory = os.path.dirname(filename) for d in dictionaries: if d.path == filename: break else: dictionaries.insert(0, DictionaryConfig(filename)) self._update_dictionaries(dictionaries, keep_selection=False)
def _create_new_dictionary(self): new_filename = QFileDialog.getSaveFileName( self, _('New dictionary'), None, _dictionary_filters(include_readonly=False), )[0] if not new_filename: return new_filename = normalize_path(new_filename) try: d = create_dictionary(new_filename, threaded_save=False) d.save() except: log.error('creating dictionary %s failed', new_filename, exc_info=True) return dictionaries = self._config_dictionaries[:] for d in dictionaries: if d.path == new_filename: break else: dictionaries.insert(0, DictionaryConfig(new_filename)) # Note: pass in `loaded_dictionaries` to force update (use case: # the user decided to overwrite an already loaded dictionary). self._update_dictionaries(dictionaries, keep_selection=False, loaded_dictionaries=self._loaded_dictionaries)
def test_loading_dictionaries(tmp_path, engine): def check_loaded_events(actual_events, expected_events): assert len(actual_events) == len(expected_events) for n, event in enumerate(actual_events): event_type, event_args, event_kwargs = event msg = 'event %u: %r' % (n, event) assert event_type == 'dictionaries_loaded', msg assert event_kwargs == {}, msg assert len(event_args) == 1, msg assert isinstance(event_args[0], StenoDictionaryCollection), msg assert [(d.path, d.enabled, isinstance(d, ErroredDictionary)) for d in event_args[0].dicts] == expected_events[n], msg with \ make_dict(tmp_path, b'{}', 'json', 'valid1') as valid_dict_1, \ make_dict(tmp_path, b'{}', 'json', 'valid2') as valid_dict_2, \ make_dict(tmp_path, b'', 'json', 'invalid1') as invalid_dict_1, \ make_dict(tmp_path, b'', 'json', 'invalid2') as invalid_dict_2: valid_dict_1 = normalize_path(str(valid_dict_1)) valid_dict_2 = normalize_path(str(valid_dict_2)) invalid_dict_1 = normalize_path(str(invalid_dict_1)) invalid_dict_2 = normalize_path(str(invalid_dict_2)) engine.start() for new_dictionaries, *expected_events in ( # Load one valid dictionary. [ [ # path, enabled (valid_dict_1, True), ], [ # path, enabled, errored (valid_dict_1, True, False), ] ], # Load another invalid dictionary. [[ (valid_dict_1, True), (invalid_dict_1, True), ], [ (valid_dict_1, True, False), (invalid_dict_1, True, True), ]], # Disable first dictionary. [[ (valid_dict_1, False), (invalid_dict_1, True), ], [ (valid_dict_1, False, False), (invalid_dict_1, True, True), ]], # Replace invalid dictonary with another invalid one. [[ (valid_dict_1, False), (invalid_dict_2, True), ], [ (valid_dict_1, False, False), ], [ (valid_dict_1, False, False), (invalid_dict_2, True, True), ]]): engine.events.clear() config_update = { 'dictionaries': [DictionaryConfig(*d) for d in new_dictionaries] } engine.config = dict(config_update) assert engine.events[0] == ('config_changed', (config_update, ), {}) check_loaded_events(engine.events[1:], expected_events) # Simulate an outdated dictionary. engine.events.clear() engine.dictionaries[valid_dict_1].timestamp -= 1 engine.config = {} check_loaded_events(engine.events, [[ (invalid_dict_2, True, True), ], [ (valid_dict_1, False, False), (invalid_dict_2, True, True), ]])