def main(): """Launch plover.""" description = "Run the plover stenotype engine. This is a graphical application." parser = argparse.ArgumentParser(description=description) parser.add_argument('--version', action='version', version='%s %s' % (__software_name__.capitalize(), __version__)) parser.add_argument('-l', '--log-level', choices=['debug', 'info', 'warning', 'error'], default=None, help='set log level') args = parser.parse_args(args=sys.argv[1:]) if args.log_level is not None: log.set_level(args.log_level.upper()) try: # Ensure only one instance of Plover is running at a time. with plover.oslayer.processlock.PloverLock(): if sys.platform.startswith('darwin'): appnope.nope() init_config_dir() # This must be done after calling init_config_dir, so # Plover's configuration directory actually exists. log.setup_logfile() log.info('Plover %s', __version__) config = Config() config.target_file = CONFIG_FILE gui = plover.gui.main.PloverGUI(config) gui.MainLoop() with open(config.target_file, 'wb') as f: config.save(f) except plover.oslayer.processlock.LockNotAcquiredException: show_error('Error', 'Another instance of Plover is already running.') except: show_error('Unexpected error', traceback.format_exc()) os._exit(1)
def main(config): use_qt_notifications = True handler_class = None try: if sys.platform.startswith('linux'): from plover.oslayer.log_dbus import DbusNotificationHandler handler_class = DbusNotificationHandler elif sys.platform.startswith('darwin'): from plover.oslayer.log_osx import OSXNotificationHandler handler_class = OSXNotificationHandler except Exception: log.info('could not import platform gui log', exc_info=True) if handler_class is not None: try: handler = handler_class() except Exception: log.info('could not initialize platform gui log', exc_info=True) else: log.add_handler(handler) use_qt_notifications = False # Setup internationalization support. install_gettext() app = Application(config, use_qt_notifications) app.run() del app return 0
def main(config): handler_class = None try: if sys.platform.startswith('linux'): from plover.oslayer.log_dbus import DbusNotificationHandler handler_class = DbusNotificationHandler elif sys.platform.startswith('darwin'): from plover.oslayer.log_osx import OSXNotificationHandler handler_class = OSXNotificationHandler except Exception: log.info('could not import platform gui log', exc_info=True) if handler_class is not None: try: handler = handler_class() except Exception: log.info('could not initialize platform gui log', exc_info=True) else: log.add_handler(handler) engine = Engine(config, KeyboardEmulation()) if not engine.load_config(): return 3 quitting = Event() engine.hook_connect('quit', quitting.set) engine.start() try: quitting.wait() except KeyboardInterrupt: pass engine.quit() engine.join() return 0
def load_plugins(self, plugins_dir=PLUGINS_DIR): log.info('loading plugins from %s', plugins_dir) working_set = pkg_resources.working_set environment = pkg_resources.Environment([plugins_dir]) distributions, errors = working_set.find_plugins(environment) if errors: log.error("error(s) while loading plugins: %s", errors) list(map(working_set.add, distributions))
def start_loading(self, filename): op = self.dictionaries.get(filename) if op is not None and not op.needs_reloading(): return op log.info('%s dictionary: %s', 'loading' if op is None else 'reloading', filename) op = DictionaryLoadingOperation(filename) self.dictionaries[filename] = op return op
def run(self): """Overrides base class run method. Do not call directly.""" try: _loop(self.serial_port, self.finished, self._on_stroke, self._ready) except _StopException: pass except Exception: log.info("Failure starting Stentura", exc_info=True) self._error()
def run(self): """Overrides base class run method. Do not call directly.""" try: _loop(self.serial_port, self.finished, self._notify, self._ready) except _StopException: pass except Exception as e: log.info("Failure starting Stentura: %s", str(e)) self._error()
def register_plugin_from_entrypoint(self, plugin_type, entrypoint): log.info('%s: %s (from %s)', plugin_type, entrypoint.name, entrypoint.module_name) try: obj = entrypoint.resolve() except: log.error('error loading %s plugin: %s (from %s)', plugin_type, entrypoint.name, entrypoint.module_name, exc_info=True) else: self.register_plugin(plugin_type, entrypoint.name, obj)
def load(self, filenames): start_time = time.time() self.dictionaries = {f: self.start_loading(f) for f in filenames} results = [ self.dictionaries[f].get() for f in filenames ] log.info('loaded %u dictionaries in %.3fs', len(results), time.time() - start_time) return results
def install_gettext(): lang = get_language() log.info('setting language to: %s', lang) os.environ['LANGUAGE'] = lang locale_dir = pkg_resources.resource_filename('plover', 'gui_qt/messages') if PY2: kwargs = { 'unicode': 1 } else: kwargs = {} gettext.install('plover', locale_dir, *kwargs)
def _start_extensions(self, extension_list): for extension_name in extension_list: log.info('starting `%s` extension', extension_name) try: extension = registry.get_plugin('extension', extension_name).obj(self) extension.start() except Exception: log.error('initializing extension `%s` failed', extension_name, exc_info=True) else: self._running_extensions[extension_name] = extension
def start_capture(self): """Begin listening for output from the stenotype machine.""" try: self._machine = hid.device(VENDOR_ID, 1) self._machine.set_nonblocking(1) except IOError as e: log.info('Treal device not found: %s', str(e)) log.warning('Treal is not connected') self._error() return return ThreadedStenotypeBase.start_capture(self)
def start_capture(self): """Begin listening for output from the stenotype machine.""" try: if hasattr(hid.device, 'open'): self._machine = hid.device() self._machine.open(VENDOR_ID, 1) else: self._machine = hid.device(VENDOR_ID, 1) self._machine.set_nonblocking(0) except IOError as e: log.info('Treal device not found: %s', str(e)) log.warning('Treal is not connected') self._error() return super(Stenotype, self).start_capture()
def copy_default_dictionaries(config): '''Copy default dictionaries to the configuration directory. Each default dictionary is copied to the configuration directory if it's in use by the current config and missing. ''' config_dictionaries = set(os.path.basename(dictionary) for dictionary in config.get_dictionary_file_names()) for dictionary in config_dictionaries & set(DEFAULT_DICTIONARIES): dst = os.path.join(CONFIG_DIR, dictionary) if os.path.exists(dst): continue src = os.path.join(ASSETS_DIR, dictionary) log.info('copying %s to %s', src, dst) shutil.copy(src, dst)
def register_plugin_from_entrypoint(self, plugin_type, entrypoint): log.info('%s: %s (from %s)', plugin_type, entrypoint.name, entrypoint.dist) try: obj = entrypoint.resolve() except: log.error('error loading %s plugin: %s (from %s)', plugin_type, entrypoint.name, entrypoint.module_name, exc_info=True) else: plugin = self.register_plugin(plugin_type, entrypoint.name, obj) # Keep track of distributions providing plugins. dist_id = str(entrypoint.dist) dist = self._distributions.get(dist_id) if dist is None: dist = PluginDistribution(entrypoint.dist, set()) self._distributions[dist_id] = dist dist.plugins.add(plugin)
def start_capture(self): """Begin listening for output from the stenotype machine.""" devices = hid.HidDeviceFilter(vendor_id=VENDOR_ID).get_devices() if len(devices) == 0: log.info('Treal: no devices with vendor id %s', str(VENDOR_ID)) log.warning('Treal not connected') self._error() return self._machine = devices[0] self._machine.open() handler = DataHandler(self._notify) def callback(p): if len(p) != 6: return handler.update(p[1:]) self._machine.set_raw_data_handler(callback) self._ready()
def _load(self, filename): ext = os.path.splitext(filename)[1] reader = PREFERRED_READER[ext] log.info('reading %r using %s reader', filename, repr(reader) if reader else 'default') book = pyexcel.get_book_dict(file_name=filename, library=reader) def load(): for sheet, entries in book.items(): self._sheets.append(sheet) for row in entries: if not row or not row[0]: continue translation = row[1] if len(row) > 1 else '' steno = normalize_steno(row[0]) yield steno, translation self._extras[steno] = (sheet, row[2:]) self.update(load())
def register_plugin_from_entrypoint(self, plugin_type, entrypoint): log.info('%s: %s (from %s)', plugin_type, entrypoint.name, entrypoint.dist) try: obj = entrypoint.resolve() except: log.error('error loading %s plugin: %s (from %s)', plugin_type, entrypoint.name, entrypoint.module_name, exc_info=True) if not self._suppress_errors: reraise(*sys.exc_info()) else: plugin = self.register_plugin(plugin_type, entrypoint.name, obj) # Keep track of distributions providing plugins. dist_id = str(entrypoint.dist) dist = self._distributions.get(dist_id) if dist is None: dist = PluginDistribution(entrypoint.dist, set()) self._distributions[dist_id] = dist dist.plugins.add(plugin)
def __init__(self, config, controller, use_qt_notifications): # This is done dynamically so localization # support can be configure beforehand. from plover.gui_qt.main_window import MainWindow self._app = None self._win = None self._engine = None self._translator = None QCoreApplication.setApplicationName(__software_name__.capitalize()) QCoreApplication.setApplicationVersion(__version__) QCoreApplication.setOrganizationName('Open Steno Project') QCoreApplication.setOrganizationDomain('openstenoproject.org') self._app = QApplication([]) self._app.setAttribute(Qt.AA_UseHighDpiPixmaps) # Enable localization of standard Qt controls. log.info('setting language to: %s', _.lang) self._translator = QTranslator() translations_dir = QLibraryInfo.location(QLibraryInfo.TranslationsPath) self._translator.load('qtbase_' + _.lang, translations_dir) self._app.installTranslator(self._translator) QApplication.setQuitOnLastWindowClosed(False) self._app.engine = self._engine = Engine(config, controller, KeyboardEmulation()) # On macOS, quitting through the dock will result # in a direct call to `QCoreApplication.quit`. self._app.aboutToQuit.connect(self._app.engine.quit) signal.signal(signal.SIGINT, lambda signum, stack: self._engine.quit()) # Make sure the Python interpreter runs at least every second, # so signals have a chance to be processed. self._timer = QTimer() self._timer.timeout.connect(lambda: None) self._timer.start(1000) self._win = MainWindow(self._engine, use_qt_notifications)
def copy_default_dictionaries(dictionaries_files): '''Recreate default dictionaries. Each default dictionary is recreated if it's in use by the current config and missing. ''' for dictionary in dictionaries_files: # Ignore assets. if dictionary.startswith(ASSET_SCHEME): continue # Nothing to do if dictionary file already exists. if os.path.exists(dictionary): continue # Check it's actually a default dictionary. basename = os.path.basename(dictionary) if basename not in system.DEFAULT_DICTIONARIES: continue default_dictionary = os.path.join(system.DICTIONARIES_ROOT, basename) log.info('recreating %s from %s', dictionary, default_dictionary) shutil.copyfile(resource_filename(default_dictionary), dictionary)
def start_capture(self): if self.serial_port: self.serial_port.close() try: self.serial_port = serial.Serial(**self.serial_params) except (serial.SerialException, OSError) as e: log.warning('Machine not connected') log.info('Can\'t open Serial port: %s', str(e)) self._error() return if self.serial_port is None: log.warning('Serial port not found: %s', str(e)) self._error() return if not self.serial_port.isOpen(): log.warning('Serial port is not open: %s', str(e)) self._error() return return ThreadedStenotypeBase.start_capture(self)
def start_capture(self): if self.serial_port: self.serial_port.close() try: self.serial_port = serial.Serial(**self.serial_params) except (serial.SerialException, OSError) as e: log.warning('Stentura not connected') log.info('Can\'t open Serial port: %s', str(e)) self._error() return if self.serial_port is None: log.warning('Serial port not found: %s', str(e)) self._error() return if not self.serial_port.isOpen(): log.warning('Serial port is not open: %s', str(e)) self._error() return return ThreadedStenotypeBase.start_capture(self)
def run(self): while not self._stop.isSet(): if self._engine.machine_state != STATE_ERROR: log.info('plover-auto-reconnect-machine: machine is connected') # wait until notified self._wait() if self._engine.machine_state == STATE_ERROR: if isinstance(self._engine._machine, SerialStenotypeBase) and not self._port_exists( self._engine._machine.serial_params['port']): log.info( 'plover-auto-reconnect-machine: machine can not be reconnected, retrying later' ) else: log.info( 'plover-auto-reconnect-machine: machine is disconnected, trying to reconnect' ) self._engine.reset_machine() # prevent busy endless loop, just check again in one second sleep(1)
def register_plugin(self, plugin_type, entrypoint): log.info('%s: %s (from %s)', plugin_type, entrypoint.name, entrypoint.module_name) self._plugins[plugin_type][entrypoint.name.lower()] = entrypoint
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"] ) 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 = registry.get_plugin("machine", machine_type).resolve() 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 dictionaries. dictionaries_files = config["dictionary_file_names"] copy_default_dictionaries(dictionaries_files) 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)
# See LICENSE.txt for details. "Manager for stenotype machines types." from plover.machine.geminipr import Stenotype as geminipr from plover.machine.txbolt import Stenotype as txbolt from plover.machine.sidewinder import Stenotype as sidewinder from plover.machine.stentura import Stenotype as stentura from plover.machine.stenturait import StenotypeIT as stenturait from plover.machine.passport import Stenotype as passport from plover import log try: from plover.machine.treal import Stenotype as treal except Exception as e: log.info('Unable to use Treal on this machine: %s', str(e)) treal = None class NoSuchMachineException(Exception): def __init__(self, id): self._id = id def __str__(self): return 'Unrecognized machine type: {}'.format(self._id) class Registry(object): def __init__(self): self._machines = {} self._aliases = {} def register(self, name, machine):
def _stop_extensions(self, extension_list): for extension_name in list(extension_list): log.info('stopping `%s` extension', extension_name) extension = self._running_extensions.pop(extension_name) extension.stop() del extension
def install_gettext(): lang = get_language() log.info('setting language to: %s', lang) os.environ['LANGUAGE'] = lang locale_dir = pkg_resources.resource_filename('plover', 'gui_qt/messages') gettext.install('plover', locale_dir)
import sys from plover import log handler = None try: if sys.platform.startswith('linux'): from plover.oslayer.log_dbus import DbusNotificationHandler handler = DbusNotificationHandler elif sys.platform.startswith('darwin'): from plover.oslayer.log_osx import OSXNotificationHandler handler = OSXNotificationHandler except Exception as e: log.info('could not import platform gui log', exc_info=e) if handler is None: from plover.gui.log_wx import WxNotificationHandler handler = WxNotificationHandler log.add_handler(handler())
def stop(self): log.info('plover-auto-reconnect-machine: stopping') self._stop.set() self._notify() self._engine.hook_disconnect("machine_state_changed", self._on_machine_state_changed)
def start(self): log.info('plover-auto-reconnect-machine: starting') self._engine.hook_connect("machine_state_changed", self._on_machine_state_changed) self._thread.start()
def start(self) -> None: log.info("FANCY_START") self.engine.hook_connect("translated", self.translated) super().start()
def main(): """Launch plover.""" description = "Run the plover stenotype engine. This is a graphical application." parser = argparse.ArgumentParser(description=description) parser.add_argument('--version', action='version', version='%s %s' % (__software_name__.capitalize(), __version__)) parser.add_argument( '-s', '--script', default=None, nargs=argparse.REMAINDER, help='use another plugin console script as main entrypoint, ' 'passing in the rest of the command line arguments, ' 'print list of available scripts when no argument is given') parser.add_argument('-l', '--log-level', choices=['debug', 'info', 'warning', 'error'], default=None, help='set log level') parser.add_argument('-g', '--gui', default=None, help='set gui') args = parser.parse_args(args=sys.argv[1:]) if args.log_level is not None: log.set_level(args.log_level.upper()) log.setup_platform_handler() log.info('Plover %s', __version__) log.info('configuration directory: %s', CONFIG_DIR) if PLATFORM == 'mac': # Fixes PyQt issue on macOS Big Sur. os.environ['QT_MAC_WANTS_LAYER'] = '1' registry.update() if args.gui is None: gui_priority = { 'qt': 1, 'none': -1, } gui_list = sorted(registry.list_plugins('gui'), reverse=True, key=lambda gui: gui_priority.get(gui.name, 0)) gui = gui_list[0].obj else: gui = registry.get_plugin('gui', args.gui).obj try: if args.script is not None: if args.script: # Create a mapping of available console script, # with the following priorities (highest first): # - {project_name}-{version}:{script_name} # - {project_name}:{script_name} # - {script_name} console_scripts = {} for e in sorted( pkg_resources.iter_entry_points('console_scripts'), key=lambda e: (e.dist, e.name)): for key in ( '%s-%s:%s' % (e.dist.project_name, e.dist.version, e.name), '%s:%s' % (e.dist.project_name, e.name), e.name, ): console_scripts[key] = e entrypoint = console_scripts.get(args.script[0]) if entrypoint is None: log.error('no such script: %s', args.script[0]) code = 1 else: sys.argv = args.script try: code = entrypoint.load()() except SystemExit as e: code = e.code if code is None: code = 0 else: print('available script(s):') dist = None for e in sorted( pkg_resources.iter_entry_points('console_scripts'), key=lambda e: (str(e.dist), e.name)): if dist != e.dist: dist = e.dist print('%s:' % dist) print('- %s' % e.name) code = 0 os._exit(code) # Ensure only one instance of Plover is running at a time. with Controller() as controller: if controller.is_owner: # Not other instance, regular startup. if PLATFORM == 'mac': import appnope appnope.nope() init_config_dir() # This must be done after calling init_config_dir, so # Plover's configuration directory actually exists. log.setup_logfile() config = Config(CONFIG_FILE) code = gui.main(config, controller) else: log.info( 'another instance is running, sending `focus` command') # Other instance? Try focusing the main window. try: controller.send_command('focus') except ConnectionRefusedError: log.error('connection to existing instance failed, ' 'force cleaning before restart') # Assume the previous instance died, leaving # a stray socket, try cleaning it... if not controller.force_cleanup(): raise # ...and restart. code = -1 else: code = 0 except: gui.show_error('Unexpected error', traceback.format_exc()) code = 2 if code == -1: # Restart. args = sys.argv[:] if args[0].endswith('.py') or args[0].endswith('.pyc'): # We're running from source. spec = sys.modules['__main__'].__spec__ assert sys.argv[0] == spec.origin args[0:1] = [sys.executable, '-m', spec.name] # Execute atexit handlers. atexit._run_exitfuncs() if PLATFORM == 'win': # Workaround https://bugs.python.org/issue19066 subprocess.Popen(args, cwd=os.getcwd()) code = 0 else: os.execv(args[0], args) os._exit(code)
def layoutChanged_(self, event): log.info('Mac keyboard layout changed, updating') layout._update_layout()
import sys from plover import log handler = None try: if sys.platform.startswith('linux'): from plover.gui.log_dbus import DbusNotificationHandler handler = DbusNotificationHandler elif sys.platform.startswith('darwin'): from plover.gui.log_osx import OSXNotificationHandler handler = OSXNotificationHandler except Exception as e: log.info('could not import platform gui log', exc_info=e) if handler is None: from plover.gui.log_wx import WxNotificationHandler handler = WxNotificationHandler log.add_handler(handler())
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] } # 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'] machine_class = registry.get_plugin('machine', machine_type).obj 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)
# Copyright (c) 2013 Hesky Fisher # See LICENSE.txt for details. "Manager for stenotype machines types." from plover.machine.geminipr import Stenotype as geminipr from plover.machine.txbolt import Stenotype as txbolt from plover.machine.sidewinder import Stenotype as sidewinder from plover.machine.stentura import Stenotype as stentura from plover.machine.passport import Stenotype as passport from plover import log try: from plover.machine.treal import Stenotype as treal except Exception as e: log.info("Unable to use Treal on this machine: %s", str(e)) treal = None class NoSuchMachineException(Exception): def __init__(self, id): self._id = id def __str__(self): return "Unrecognized machine type: {}".format(self._id) class Registry(object): def __init__(self): self._machines = {} self._aliases = {}
def main(): """Launch plover.""" description = "Run the plover stenotype engine. This is a graphical application." parser = argparse.ArgumentParser(description=description) parser.add_argument('--version', action='version', version='%s %s' % (__software_name__.capitalize(), __version__)) parser.add_argument( '-s', '--script', default=None, nargs=argparse.REMAINDER, help='use another plugin console script as main entrypoint, ' 'passing in the rest of the command line arguments, ' 'print list of available scripts when no argument is given') parser.add_argument('-l', '--log-level', choices=['debug', 'info', 'warning', 'error'], default=None, help='set log level') parser.add_argument('-g', '--gui', default=None, help='set gui') args = parser.parse_args(args=sys.argv[1:]) if args.log_level is not None: log.set_level(args.log_level.upper()) log.setup_platform_handler() log.info('Plover %s', __version__) log.info('configuration directory: %s', CONFIG_DIR) log.info('plugins directory: %s', PLUGINS_DIR) registry.update() if args.gui is None: gui_priority = { 'qt': 1, 'none': -1, } gui_list = sorted(registry.list_plugins('gui'), reverse=True, key=lambda gui: gui_priority.get(gui.name, 0)) gui = gui_list[0].obj else: gui = registry.get_plugin('gui', args.gui).obj try: if args.script is not None: if args.script: # Create a mapping of available console script, # with the following priorities (highest first): # - {project_name}-{version}:{script_name} # - {project_name}:{script_name} # - {script_name} console_scripts = {} for e in sorted( pkg_resources.iter_entry_points('console_scripts'), key=lambda e: (e.dist, e.name)): for key in ( '%s-%s:%s' % (e.dist.project_name, e.dist.version, e.name), '%s:%s' % (e.dist.project_name, e.name), e.name, ): console_scripts[key] = e entrypoint = console_scripts.get(args.script[0]) if entrypoint is None: log.error('no such script: %s', args.script[0]) code = 1 else: sys.argv = args.script try: code = entrypoint.load()() except SystemExit as e: code = e.code if code is None: code = 0 else: print('available script(s):') dist = None for e in sorted( pkg_resources.iter_entry_points('console_scripts'), key=lambda e: (str(e.dist), e.name)): if dist != e.dist: dist = e.dist print('%s:' % dist) print('- %s' % e.name) code = 0 os._exit(code) # Ensure only one instance of Plover is running at a time. with plover.oslayer.processlock.PloverLock(): if sys.platform.startswith('darwin'): appnope.nope() init_config_dir() # This must be done after calling init_config_dir, so # Plover's configuration directory actually exists. log.setup_logfile() config = Config() config.target_file = CONFIG_FILE code = gui.main(config) with open(config.target_file, 'wb') as f: config.save(f) except plover.oslayer.processlock.LockNotAcquiredException: gui.show_error('Error', 'Another instance of Plover is already running.') code = 1 except: gui.show_error('Unexpected error', traceback.format_exc()) code = 2 if code == -1: # Restart. args = sys.argv[:] if args[0].endswith('.py') or args[0].endswith('.pyc'): # We're running from source. assert args[0] == __file__ args[0:1] = [sys.executable, '-m', __spec__.name] # Execute atexit handlers. atexit._run_exitfuncs() if sys.platform.startswith('win32'): # Workaround https://bugs.python.org/issue19066 subprocess.Popen(args, cwd=os.getcwd()) code = 0 else: os.execv(args[0], args) os._exit(code)
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']) 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 = registry.get_plugin('machine', machine_type).resolve() 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 dictionaries. dictionaries_files = config['dictionary_file_names'] copy_default_dictionaries(dictionaries_files) 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 _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)
# See LICENSE.txt for details. "Manager for stenotype machines types." from plover.machine.geminipr import Stenotype as geminipr from plover.machine.txbolt import Stenotype as txbolt from plover.machine.sidewinder import Stenotype as sidewinder from plover.machine.stentura import Stenotype as stentura from plover.machine.stenturait import StenotypeIT as stenturait from plover.machine.passport import Stenotype as passport from plover import log try: from plover.machine.treal import Stenotype as treal except Exception as e: log.info('Unable to use Treal on this machine: %s', str(e)) treal = None class NoSuchMachineException(Exception): def __init__(self, id): self._id = id def __str__(self): return 'Unrecognized machine type: {}'.format(self._id) class Registry(object): def __init__(self): self._machines = {} self._aliases = {}
def main(): """Launch plover.""" description = "Run the plover stenotype engine. This is a graphical application." parser = argparse.ArgumentParser(description=description) parser.add_argument('--version', action='version', version='%s %s' % (__software_name__.capitalize(), __version__)) parser.add_argument('-s', '--script', default=None, nargs=argparse.REMAINDER, help='use another plugin console script as main entrypoint, ' 'passing in the rest of the command line arguments, ' 'print list of available scripts when no argument is given') parser.add_argument('-l', '--log-level', choices=['debug', 'info', 'warning', 'error'], default=None, help='set log level') parser.add_argument('-g', '--gui', default=None, help='set gui') args = parser.parse_args(args=sys.argv[1:]) if args.log_level is not None: log.set_level(args.log_level.upper()) log.setup_platform_handler() log.info('Plover %s', __version__) log.info('configuration directory: %s', CONFIG_DIR) registry.update() if args.gui is None: gui_priority = { 'qt': 1, 'none': -1, } gui_list = sorted(registry.list_plugins('gui'), reverse=True, key=lambda gui: gui_priority.get(gui.name, 0)) gui = gui_list[0].obj else: gui = registry.get_plugin('gui', args.gui).obj try: if args.script is not None: if args.script: # Create a mapping of available console script, # with the following priorities (highest first): # - {project_name}-{version}:{script_name} # - {project_name}:{script_name} # - {script_name} console_scripts = {} for e in sorted(pkg_resources.iter_entry_points('console_scripts'), key=lambda e: (e.dist, e.name)): for key in ( '%s-%s:%s' % (e.dist.project_name, e.dist.version, e.name), '%s:%s' % (e.dist.project_name, e.name), e.name, ): console_scripts[key] = e entrypoint = console_scripts.get(args.script[0]) if entrypoint is None: log.error('no such script: %s', args.script[0]) code = 1 else: sys.argv = args.script try: code = entrypoint.load()() except SystemExit as e: code = e.code if code is None: code = 0 else: print('available script(s):') dist = None for e in sorted(pkg_resources.iter_entry_points('console_scripts'), key=lambda e: (str(e.dist), e.name)): if dist != e.dist: dist = e.dist print('%s:' % dist) print('- %s' % e.name) code = 0 os._exit(code) # Ensure only one instance of Plover is running at a time. with processlock.PloverLock(): if sys.platform.startswith('darwin'): appnope.nope() init_config_dir() # This must be done after calling init_config_dir, so # Plover's configuration directory actually exists. log.setup_logfile() config = Config() config.target_file = CONFIG_FILE code = gui.main(config) with open(config.target_file, 'wb') as f: config.save(f) except processlock.LockNotAcquiredException: gui.show_error('Error', 'Another instance of Plover is already running.') code = 1 except: gui.show_error('Unexpected error', traceback.format_exc()) code = 2 if code == -1: # Restart. args = sys.argv[:] if args[0].endswith('.py') or args[0].endswith('.pyc'): # We're running from source. assert args[0] == __file__ args[0:1] = [sys.executable, '-m', __spec__.name] # Execute atexit handlers. atexit._run_exitfuncs() if sys.platform.startswith('win32'): # Workaround https://bugs.python.org/issue19066 subprocess.Popen(args, cwd=os.getcwd()) code = 0 else: os.execv(args[0], args) os._exit(code)