def test_output_optimization(undo, do, expected_instructions): output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.format([], undo, None) formatter.format(undo, do, None) assert output.instructions == expected_instructions
def test_output_optimisation(self): for undo, do, expected_instructions in ( # No change. ([ translation(english='noop'), ], [ translation(english='noop'), ], [('s', ' noop')]), # Append only. ([ translation(english='test'), ], [ translation(english='testing'), ], [('s', ' test'), ('s', 'ing')]), # Chained meta-commands. ([ translation(english='{#a}'), ], [ translation(english='{#a}{#b}'), ], [('c', 'a'), ('c', 'b')]), ): output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.format([], undo, None) formatter.format(undo, do, None) self.assertEqual(output.instructions, expected_instructions)
def test_replace(self): for translations, expected_instructions in ( # Check that 'replace' does not unconditionally erase # the previous character if it does not match. ([ translation(english='{MODE:SET_SPACE:}'), translation(english='foobar'), translation(english='{^}{#Return}{^}{-|}'), ], [('s', 'foobar'), ('c', 'Return')]), # Check 'replace' correctly takes into account # the previous translation. ([ translation(english='test '), translation(english='{^,}'), ], [('s', 'test '), ('b', 1), ('s', ', ')]), # While the previous translation must be taken into account, # any meta-command must not be fired again. ([ translation(english='{#Return}'), translation(english='test'), ], [('c', 'Return'), ('s', 'test ')]), ): output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.set_space_placement('After Output') prev = None for t in translations: formatter.format([], [t], prev) prev = t self.assertEqual(output.instructions, expected_instructions)
def test_starting_stroke(self): # Args: (Capitalized, Attached, Undo, Current, Prev Formatter) cases = ( ((True, True, [], [translation(rtfcre=('S'), english='hello')], None), ([action(text='Hello', word='Hello')], ), [('s', 'Hello')]), ((False, False, [], [translation(rtfcre=('S'), english='hello')], None), ([action(text=' hello', word='hello')], ), [('s', ' hello')]), ((True, False, [], [translation(rtfcre=('S'), english='hello')], None), ([action(text=' Hello', word='Hello')], ), [('s', ' Hello')]), ((False, True, [], [translation(rtfcre=('S'), english='hello')], None), ([action(text='hello', word='hello')], ), [('s', 'hello')]), ) for args, formats, outputs in cases: output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.set_space_placement('Before Output') capitalized, attached, undo, do, prev = args formatter.start_capitalized = capitalized formatter.start_attached = attached formatter.format(undo, do, prev) for i, t in enumerate(do): self.assertEqual(t.formatting, formats[i]) self.assertEqual(output.instructions, outputs)
def test_replace(translations, expected_instructions): output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.set_space_placement('After Output') prev = [] for t in translations: formatter.format([], [t], prev) prev.append(t) assert output.instructions == expected_instructions
def test_get_last_action(self): formatter = formatting.Formatter() self.assertEqual(formatter._get_last_action(None), action()) self.assertEqual(formatter._get_last_action([]), action()) actions = [action(text='hello'), action(text='world')] self.assertEqual(formatter._get_last_action(actions), actions[-1]) formatter.start_attached = True formatter.start_capitalized = True self.assertEqual(formatter._get_last_action(None), action(capitalize=True, attach=True))
def test_get_last_action(): formatter = formatting.Formatter() assert formatter._get_last_action(None) == action() assert formatter._get_last_action([]) == action() actions = [action(text='hello'), action(text='world')] assert formatter._get_last_action(actions) == actions[-1] formatter.start_attached = True formatter.start_capitalized = True assert formatter._get_last_action(None) == action(capitalize=True, attach=True)
def test_starting_stroke(capitalized, attached, undo, do, prev, expected_formats, expected_outputs): output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.start_capitalized = capitalized formatter.start_attached = attached formatter.format(undo, do, prev) for i, t in enumerate(do): assert t.formatting == expected_formats[i] assert output.instructions == expected_outputs
def test_formatter(undo, do, prev, expected_formats, expected_outputs): output = CaptureOutput() # Add some initial blank text so # undoing with no previous state # does not assert. output.text = ' ' * 128 formatter = formatting.Formatter() formatter.set_output(output) formatter.format(undo, do, prev) for i, t in enumerate(do): assert t.formatting == expected_formats[i] assert output.instructions == expected_outputs
def test_undo_replace(self): # Undoing a replace.... output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.set_space_placement('After Output') prev = translation(english='test') formatter.format([], [prev], None) undo = translation(english='{^,}') formatter.format([], [undo], prev) # Undo. formatter.format([undo], [], prev) self.assertEqual(output.instructions, [ ('s', 'test '), ('b', 1), ('s', ', '), ('b', 2), ('s', ' '), ])
def __init__(self, thread_hook=same_thread_hook): """Creates and configures a single steno pipeline.""" self.subscribers = [] self.stroke_listeners = [] self.is_running = False self.machine = None self.thread_hook = thread_hook self.translator = translation.Translator() self.formatter = formatting.Formatter() self.translator.add_listener(log.translation) 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) self.full_output = SimpleNamespace() self.command_only_output = SimpleNamespace() self.running_state = self.translator.get_state() self.set_is_running(False)
def __init__(self, thread_hook=same_thread_hook): """Creates and configures a single steno pipeline.""" self.subscribers = [] self.stroke_listeners = [] self.is_running = False self.machine = None self.machine_class = None self.machine_options = None self.machine_mappings = None self.thread_hook = thread_hook self.translator = translation.Translator() self.formatter = formatting.Formatter() self.translator.add_listener(log.translation) self.translator.add_listener(self.formatter.format) self.full_output = SimpleNamespace() self.command_only_output = SimpleNamespace() self.running_state = self.translator.get_state() self.set_is_running(False)
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 test_formatter(self): cases = ( ( ([translation(formatting=[action(text='hello')])], [], None), (), [('b', 5)] ), ( ([], [translation(rtfcre=('S'), english='hello')], translation(rtfcre=('T'), english='a', formatting=[action(text='f')]) ), ([action(text=' hello', word='hello')],), [('s', ' hello')] ), ( ([], [translation(rtfcre=('S'), english='hello')], None), ([action(text=' hello', word='hello')],), [('s', ' hello')] ), ( ([], [translation(rtfcre=('ST-T',))], None), ([action(text=' ST-T', word='ST-T')],), [('s', ' ST-T')] ), ( ([], [translation(rtfcre=('ST-T',))], translation(formatting=[action(text='hi')])), ([action(text=' ST-T', word='ST-T')],), [('s', ' ST-T')] ), ( ([translation(formatting=[action(text=' test')])], [translation(english='rest')], translation(formatting=[action(capitalize=True)])), ([action(text=' Rest', word='Rest')],), [('b', 4), ('s', 'Rest')] ), ( ([translation(formatting=[action(text='dare'), action(text='ing', replace='e')])], [translation(english='rest')], translation(formatting=[action(capitalize=True)])), ([action(text=' Rest', word='Rest')],), [('b', 6), ('s', ' Rest')] ), ( ([translation(formatting=[action(text=' drive')])], [translation(english='driving')], None), ([action(text=' driving', word='driving')],), [('b', 1), ('s', 'ing')] ), ( ([translation(formatting=[action(text=' drive')])], [translation(english='{#c}driving')], None), ([action(combo='c'), action(text=' driving', word='driving')],), [('b', 6), ('c', 'c'), ('s', ' driving')] ), ( ([translation(formatting=[action(text=' drive')])], [translation(english='{PLOVER:c}driving')], None), ([action(command='c'), action(text=' driving', word='driving')],), [('b', 6), ('e', 'c'), ('s', ' driving')] ), ( ([], [translation(rtfcre=('1',))], None), ([action(text=' 1', word='1', glue=True)],), [('s', ' 1')] ), ( ([], [translation(rtfcre=('1',))], translation(formatting=[action(text='hi', word='hi')])), ([action(text=' 1', word='1', glue=True)],), [('s', ' 1')] ), ( ([], [translation(rtfcre=('1',))], translation(formatting=[action(text='hi', word='hi', glue=True)])), ([action(text='1', word='hi1', glue=True)],), [('s', '1')] ), ( ([], [translation(rtfcre=('1-9',))], translation(formatting=[action(text='hi', word='hi', glue=True)])), ([action(text='19', word='hi19', glue=True)],), [('s', '19')] ), ( ([], [translation(rtfcre=('ST-PL',))], translation(formatting=[action(text='hi', word='hi')])), ([action(text=' ST-PL', word='ST-PL')],), [('s', ' ST-PL')] ), ( ([], [translation(rtfcre=('ST-PL',))], None), ([action(text=' ST-PL', word='ST-PL')],), [('s', ' ST-PL')] ), ) for args, formats, outputs in cases: output = CaptureOutput() formatter = formatting.Formatter() formatter.set_output(output) formatter.set_space_placement('Before Output') undo, do, prev = args formatter.format(undo, do, prev) for i in xrange(len(do)): self.assertEqual(do[i].formatting, formats[i]) self.assertEqual(output.instructions, outputs)
def setup_method(self): self.formatter = formatting.Formatter() self.translations = [] self.retro_formatter = formatting.RetroFormatter(self.translations)
def __init__(self): """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 self.config = conf.get_config() # Set the machine module and any initialization variables. machine_type = self.config.get(conf.MACHINE_CONFIG_SECTION, conf.MACHINE_TYPE_OPTION) self.machine_module = conf.import_named_module(machine_type, machine.supported) if self.machine_module is None: raise ValueError('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__) # Set the steno dictionary format module. dictionary_format = self.config.get(conf.DICTIONARY_CONFIG_SECTION, conf.DICTIONARY_FORMAT_OPTION) self.dictionary_module = conf.import_named_module( dictionary_format, dictionary.supported) if self.dictionary_module is None: raise ValueError( 'Invalid configuration value for %s: %s' % (conf.DICTIONARY_FORMAT_OPTION, dictionary_format)) # Load the dictionary. The dictionary path can be either # absolute or relative to the configuration directory. dictionary_filename = self.config.get(conf.DICTIONARY_CONFIG_SECTION, conf.DICTIONARY_FILE_OPTION) dictionary_path = os.path.join(conf.CONFIG_DIR, dictionary_filename) if not os.path.isfile(dictionary_path): raise ValueError('Invalid configuration value for %s: %s' % (conf.DICTIONARY_FILE_OPTION, dictionary_path)) dictionary_extension = os.path.splitext(dictionary_path)[1] if dictionary_extension == conf.JSON_EXTENSION: try: with open(dictionary_path, 'r') as f: self.dictionary = json.load(f) except UnicodeDecodeError: with open(dictionary_path, 'r') as f: self.dictionary = json.load(f, conf.ALTERNATIVE_ENCODING) else: raise ValueError( 'The value of %s must end with %s.' % (conf.DICTIONARY_FILE_OPTION, conf.JSON_EXTENSION)) # Initialize the logger. log_file = os.path.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 = logging.handlers.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.output = keyboardcontrol.KeyboardEmulation() self.translator = steno.Translator(self.machine, self.dictionary, self.dictionary_module) self.formatter = formatting.Formatter(self.translator) auto_start = self.config.getboolean(conf.MACHINE_CONFIG_SECTION, conf.MACHINE_AUTO_START_OPTION) self.set_is_running(auto_start) # Add hooks for logging. 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_callback(self._log_translation) # Start the machine monitoring for steno strokes. self.machine.start_capture()