def update_engine(engine, old, new): """Modify a StenoEngine using a before and after config object. Using the before and after allows this function to not make unnecessary changes. """ machine_type = new.get_machine_type() machine_options = new.get_machine_specific_options(machine_type) if (old.get_machine_type() != machine_type or old.get_machine_specific_options(machine_type) != machine_options): try: machine_class = machine_registry.get(machine_type) except NoSuchMachineException as e: raise InvalidConfigurationError(unicode(e)) engine.set_machine(machine_class(machine_options)) dictionary_file_names = new.get_dictionary_file_names() if old.get_dictionary_file_names() != dictionary_file_names: try: dicts = dict_manager.load(dictionary_file_names) except DictionaryLoaderException as e: raise InvalidConfigurationError(unicode(e)) engine.get_dictionary().set_dicts(dicts) log_file_name = new.get_log_file_name() if old.get_log_file_name() != log_file_name: engine.set_log_file_name(log_file_name) enable_stroke_logging = new.get_enable_stroke_logging() if old.get_enable_stroke_logging() != enable_stroke_logging: engine.enable_stroke_logging(enable_stroke_logging) enable_translation_logging = new.get_enable_translation_logging() if old.get_enable_translation_logging() != enable_translation_logging: engine.enable_translation_logging(enable_translation_logging)
def check_steno_config(config_params): """This will do several check on the given configuration This method can be used in StenoEngine's __init__ method, but also when exiting the configuration dialog. @return: a tuple composed of: - a list of configuration errors - a tuple of the following values: * machine_type * user_dictionary """ errors = [] machine_type = config_params.get(conf.MACHINE_CONFIG_SECTION, conf.MACHINE_TYPE_OPTION) if machine_type not in SUPPORTED_MACHINES_DICT: # The machine isn't supported error = InvalidConfigurationError( 'Invalid configuration value for %s: %s' % (conf.MACHINE_TYPE_OPTION, machine_type)) errors.append(error) # Load the dictionary. The dictionary path can be either # absolute or relative to the configuration directory. dictionary_filename = config_params.get(conf.DICTIONARY_CONFIG_SECTION, conf.DICTIONARY_FILE_OPTION) dictionary_path = join(conf.CONFIG_DIR, dictionary_filename) if not isfile(dictionary_path): error = InvalidConfigurationError( 'Invalid configuration value for %s: %s' % (conf.DICTIONARY_FILE_OPTION, dictionary_path)) errors.append(error) dictionary_extension = splitext(dictionary_path)[1] if dictionary_extension != conf.JSON_EXTENSION: error = InvalidConfigurationError( 'The value of %s must end with %s.' % (conf.DICTIONARY_FILE_OPTION, conf.JSON_EXTENSION)) errors.append(error) # Load the dictionary. The dictionary path can be either # absolute or relative to the configuration directory. user_dictionary = None try: with open(dictionary_path, 'r') as f: user_dictionary = steno_dictionary.load_dictionary(f.read()) except ValueError: error = InvalidConfigurationError( 'The dictionary file contains incorrect json.') errors.append(error) return errors, (machine_type, user_dictionary)
def load(self, fp): self._config = configparser.RawConfigParser() reader = codecs.getreader('utf8')(fp) try: self._config.readfp(reader) except configparser.Error as e: raise InvalidConfigurationError(str(e))
def load(self): self.clear() with open(self.path, encoding='utf-8') as fp: try: self._config.read_file(fp) except configparser.Error as e: raise InvalidConfigurationError(str(e))
def get_dicts(config): """Initialize a StenoEngine from a config object.""" dictionary_file_names = config.get_dictionary_file_names() try: dicts = dict_manager.load(dictionary_file_names) except DictionaryLoaderException as e: raise InvalidConfigurationError(unicode(e)) return dicts
def reset_machine(engine, config): """Set the machine on the engine based on config.""" machine_type = config.get_machine_type() machine_options = config.get_machine_specific_options(machine_type) try: instance = machine_registry.get(machine_type)(machine_options) except NoSuchMachineException as e: raise InvalidConfigurationError(unicode(e)) engine.set_machine(instance)
def update_engine(engine, config, reset_machine=False): """Modify a StenoEngine using a before and after config object. Using the before and after allows this function to not make unnecessary changes. """ machine_type = config.get_machine_type() try: machine_class = machine_registry.get(machine_type) except NoSuchMachineException as e: raise InvalidConfigurationError(str(e)) machine_options = config.get_machine_specific_options(machine_type) machine_mappings = config.get_system_keymap(machine_type) engine.set_machine(machine_class, machine_options, machine_mappings, reset_machine=reset_machine) dictionary_file_names = config.get_dictionary_file_names() engine.set_dictionaries(dictionary_file_names) log_file_name = config.get_log_file_name() if log_file_name: # Older versions would use "plover.log" for logging strokes. if os.path.realpath(log_file_name) == os.path.realpath(log.LOG_FILENAME): log.warning('stroke logging must use a different file than %s, ' 'renaming to %s', log.LOG_FILENAME, conf.DEFAULT_LOG_FILE) log_file_name = conf.DEFAULT_LOG_FILE config.set_log_file_name(log_file_name) with open(config.target_file, 'wb') as f: config.save(f) engine.set_log_file_name(log_file_name) enable_stroke_logging = config.get_enable_stroke_logging() engine.enable_stroke_logging(enable_stroke_logging) enable_translation_logging = config.get_enable_translation_logging() engine.enable_translation_logging(enable_translation_logging) space_placement = config.get_space_placement() engine.set_space_placement(space_placement) undo_levels = config.get_undo_levels() engine.set_undo_levels(undo_levels) start_capitalized = config.get_start_capitalized() start_attached = config.get_start_attached() engine.set_starting_stroke_state(attach=start_attached, capitalize=start_capitalized)
def init_engine(engine, config): """Initialize a StenoEngine from a config object.""" reset_machine(engine, config) dictionary_file_names = config.get_dictionary_file_names() try: dicts = dict_manager.load(dictionary_file_names) except DictionaryLoaderException as e: raise InvalidConfigurationError(unicode(e)) engine.get_dictionary().set_dicts(dicts) engine.set_log_file_name(config) engine.enable_stroke_logging(config.get_enable_stroke_logging()) engine.enable_translation_logging(config.get_enable_translation_logging()) engine.set_space_placement(config.get_space_placement()) engine.set_is_running(config.get_auto_start())
def _update(self, config_update=None, full=False, reset_machine=False): original_config = self._config.as_dict() # Update configuration. if config_update is not None: self._config.update(**config_update) config = self._config.as_dict() else: config = original_config # Create configuration update. if full: config_update = config else: config_update = { option: value for option, value in config.items() if value != original_config[option] } if 'machine_type' in config_update: for opt in ( 'machine_specific_options', 'system_keymap', ): config_update[opt] = config[opt] # Update logging. log.set_stroke_filename(config['log_file_name']) log.enable_stroke_logging(config['enable_stroke_logging']) log.enable_translation_logging(config['enable_translation_logging']) # Update output. self._formatter.set_space_placement(config['space_placement']) self._formatter.start_attached = config['start_attached'] self._formatter.start_capitalized = config['start_capitalized'] self._translator.set_min_undo_length(config['undo_levels']) # Update machine. update_keymap = False start_machine = False machine_params = MachineParams(config['machine_type'], config['machine_specific_options'], config['system_keymap']) if reset_machine or machine_params != self._machine_params: if self._machine is not None: self._machine.stop_capture() self._machine = None machine_type = config['machine_type'] machine_options = config['machine_specific_options'] try: machine_class = machine_registry.get(machine_type) except NoSuchMachineException as e: raise InvalidConfigurationError(str(e)) self._machine = machine_class(machine_options) self._machine.set_suppression(self._is_running) self._machine.add_state_callback(self._machine_state_callback) self._machine.add_stroke_callback(self._machine_stroke_callback) self._machine_params = machine_params update_keymap = True start_machine = True elif self._machine is not None: update_keymap = 'system_keymap' in config_update if update_keymap: machine_keymap = config['system_keymap'] if machine_keymap is not None: self._machine.set_keymap(machine_keymap) if start_machine: self._machine.start_capture() # Update dictionaries. dictionaries_files = config['dictionary_file_names'] dictionaries = self._dictionaries_manager.load(dictionaries_files) self._dictionaries.set_dicts(dictionaries) # Trigger `config_changed` hook. if config_update: self._trigger_hook('config_changed', config_update)
def __init__(self, engine_command_callback): """Creates and configures a single steno pipeline.""" self.subscribers = [] self.is_running = False self.machine = None self.machine_init = {} self.translator = None self.formatter = None self.output = None # Check and use configuration self.config = conf.get_config() config_errors, config_values = check_steno_config(self.config) for error in config_errors: # This will raise one of the configuration errors. raise error machine_type, user_dictionary = config_values # Set the machine module and any initialization variables. self.machine_module = conf.import_named_module( machine_type, SUPPORTED_MACHINES_DICT) if self.machine_module is None: raise InvalidConfigurationError( 'Invalid configuration value for %s: %s' % (conf.MACHINE_TYPE_OPTION, machine_type)) if issubclass(self.machine_module.Stenotype, plover.machine.base.SerialStenotypeBase): serial_params = conf.get_serial_params(machine_type, self.config) self.machine_init.update(serial_params.__dict__) # Initialize the logger. log_file = join( conf.CONFIG_DIR, self.config.get(conf.LOGGING_CONFIG_SECTION, conf.LOG_FILE_OPTION)) self.logger = logging.getLogger(conf.LOGGER_NAME) self.logger.setLevel(logging.DEBUG) handler = RotatingFileHandler( log_file, maxBytes=conf.LOG_MAX_BYTES, backupCount=conf.LOG_COUNT, ) handler.setFormatter(logging.Formatter(conf.LOG_FORMAT)) self.logger.addHandler(handler) # Construct the stenography capture-translate-format-display pipeline. self.machine = self.machine_module.Stenotype(**self.machine_init) self.translator = translation.Translator() self.translator.set_dictionary(user_dictionary) self.formatter = formatting.Formatter() # Add hooks for logging. Do this first so logs appear in order. if self.config.getboolean(conf.LOGGING_CONFIG_SECTION, conf.ENABLE_STROKE_LOGGING_OPTION): self.machine.add_callback(self._log_stroke) if self.config.getboolean(conf.LOGGING_CONFIG_SECTION, conf.ENABLE_TRANSLATION_LOGGING_OPTION): self.translator.add_listener(self._log_translation) self.machine.add_callback( lambda x: self.translator.translate(steno.Stroke(x))) self.translator.add_listener(self.formatter.format) # This seems like a reasonable number. If this becomes a problem it can # be parameterized. self.translator.set_min_undo_length(10) keyboard_control = keyboardcontrol.KeyboardEmulation() bag = SimpleNamespace() bag.send_backspaces = keyboard_control.send_backspaces bag.send_string = keyboard_control.send_string bag.send_key_combination = keyboard_control.send_key_combination bag.send_engine_command = engine_command_callback self.full_output = bag bag = SimpleNamespace() bag.send_engine_command = engine_command_callback self.command_only_output = bag self.running_state = self.translator.get_state() auto_start = self.config.getboolean(conf.MACHINE_CONFIG_SECTION, conf.MACHINE_AUTO_START_OPTION) self.set_is_running(auto_start) # Start the machine monitoring for steno strokes. self.machine.start_capture()
def _update(self, config_update=None, full=False, reset_machine=False): original_config = self._config.as_dict() # Update configuration. if config_update is not None: self._config.update(**config_update) config = self._config.as_dict() else: config = original_config # Create configuration update. if full: config_update = config else: config_update = { option: value for option, value in config.items() if value != original_config[option] } if 'machine_type' in config_update: for opt in ( 'machine_specific_options', 'system_keymap', ): config_update[opt] = config[opt] # Update logging. log.set_stroke_filename(config['log_file_name']) log.enable_stroke_logging(config['enable_stroke_logging']) log.enable_translation_logging(config['enable_translation_logging']) # Update output. self._formatter.set_space_placement(config['space_placement']) self._formatter.start_attached = config['start_attached'] self._formatter.start_capitalized = config['start_capitalized'] self._translator.set_min_undo_length(config['undo_levels']) # Update system. system_name = config['system_name'] if system.NAME != system_name: log.info('loading system: %s', system_name) system.setup(system_name) # Update machine. update_keymap = False start_machine = False machine_params = MachineParams(config['machine_type'], config['machine_specific_options'], config['system_keymap']) # Do not reset if only the keymap changed. if self._machine_params is None or \ self._machine_params.type != machine_params.type or \ self._machine_params.options != machine_params.options: reset_machine = True if reset_machine: if self._machine is not None: self._machine.stop_capture() self._machine = None machine_type = config['machine_type'] machine_options = config['machine_specific_options'] try: machine_class = registry.get_plugin('machine', machine_type).obj except Exception as e: raise InvalidConfigurationError(str(e)) log.info('setting machine: %s', machine_type) self._machine = machine_class(machine_options) self._machine.set_suppression(self._is_running) self._machine.add_state_callback(self._machine_state_callback) self._machine.add_stroke_callback(self._machine_stroke_callback) self._machine_params = machine_params update_keymap = True start_machine = True elif self._machine is not None: update_keymap = 'system_keymap' in config_update if update_keymap: machine_keymap = config['system_keymap'] if machine_keymap is not None: self._machine.set_keymap(machine_keymap) if start_machine: self._machine.start_capture() # Update running extensions. enabled_extensions = config['enabled_extensions'] running_extensions = set(self._running_extensions) self._stop_extensions(running_extensions - enabled_extensions) self._start_extensions(enabled_extensions - running_extensions) # Trigger `config_changed` hook. if config_update: self._trigger_hook('config_changed', config_update) # Update dictionaries. config_dictionaries = OrderedDict( (d.path, d) for d in config['dictionaries']) copy_default_dictionaries(config_dictionaries.keys()) # Start by unloading outdated dictionaries. self._dictionaries_manager.unload_outdated() self._set_dictionaries([ d for d in self._dictionaries.dicts if d.path in config_dictionaries and \ d.path in self._dictionaries_manager ]) # And then (re)load all dictionaries. dictionaries = [] for result in self._dictionaries_manager.load( config_dictionaries.keys()): if isinstance(result, DictionaryLoaderException): d = ErroredDictionary(result.path, result.exception) # Only show an error if it's new. if d != self._dictionaries.get(result.path): log.error('loading dictionary `%s` failed: %s', shorten_path(result.path), str(result.exception)) else: d = result d.enabled = config_dictionaries[d.path].enabled dictionaries.append(d) self._set_dictionaries(dictionaries)
def load(self, fp): self._config = RawConfigParser() try: self._config.readfp(fp) except ConfigParser.Error as e: raise InvalidConfigurationError(str(e))