Exemple #1
0
def Init():
    ftpath = os.path.realpath(__file__)
    ftpath = os.path.dirname(ftpath)
    ftpath = os.path.join(ftpath, 'stream')

    plugins = Plugins(ftpath)
    plugins.loads()

    Redirect()#.log()

    keys = {
            'digit': string.digits,
            'lower': string.ascii_lowercase,
            'upper': string.ascii_uppercase,
            'punc': string.punctuation,
            'mult': ['<tab>', '<bs>', '<cr>', '<space>', '<esc>', '<c-j>']
            }

    for cls, v in keys.items():
        for k in v:
            key = k
            name = k
            if k == '|': name = key = '\\|'
            if k == '\\': name = '\\\\'

            if key == '"' : name = '\\%s' % key

            if cls == 'mult':
                name = name.replace('<', '<lt>')

            command='inoremap <expr> %s Input_Monitor("%s", "%s")' % \
                            (key, cls, name)
            vim.command(command)
Exemple #2
0
def Init():
    ftpath = os.path.realpath(__file__)
    ftpath = os.path.dirname(ftpath)
    ftpath = os.path.join(ftpath, 'prompt')

    plugins = Plugins(ftpath)
    plugins.loads()
    log.info(__Handles)
Exemple #3
0
 def __init__(self):
     self.log = logging.getLogger('disper')
     self.log.setLevel(logging.WARNING)
     self._options_init()
     self.plugins = Plugins(self)
     #self.plugins.call('init') # can't really do here since list of plugins isn't read yet
     # add default options
     # TODO do initial parsing too so errors can be traced to config
     self.options_append(self.config_read_default())
Exemple #4
0
    def __init__(self, filename=None, data_path=None):
        # Based in Django's approach -> http://code.djangoproject.com/svn/django/trunk/django/__init__.py
        self.version = __import__('pytrainer').get_version()
        #Process command line options
        self.startup_options = self.get_options()
        #Setup logging
        self.environment = Environment(platform.get_platform(),
                                       self.startup_options.conf_dir)
        self.environment.create_directories()
        self.set_logging(self.startup_options.log_level,
                         self.startup_options.log_type)
        logging.debug('>>')
        logging.debug("pytrainer version %s" % (self.version))
        self.data_path = data_path
        self.date = Date()
        self.ddbb = None
        # Checking profile
        logging.debug('Checking configuration and profile...')
        self.profile = Profile(self.environment, self.data_path, self)
        self.uc = UC()
        self.windowmain = None
        self.ddbb = DDBB(self.profile, self)
        logging.debug('connecting to DDBB')
        self.ddbb.connect()

        initialize_data(self.ddbb, self.environment.conf_dir)

        self._sport_service = SportService(self.ddbb)
        self.record = Record(self._sport_service, data_path, self)
        self.athlete = Athlete(data_path, self)
        self.stats = Stats(self._sport_service, self)
        pool_size = self.profile.getIntValue("pytraining",
                                             "activitypool_size",
                                             default=1)
        self.activitypool = ActivityPool(self, size=pool_size)
        #preparamos la ventana principal
        self.windowmain = Main(self._sport_service,
                               data_path,
                               self,
                               self.version,
                               gpxDir=self.profile.gpxdir)
        self.date = Date(self.windowmain.calendar)
        self.waypoint = Waypoint(data_path, self)
        self.extension = Extension(data_path, self)
        self.plugins = Plugins(data_path, self)
        self.importdata = Importdata(self._sport_service, data_path, self,
                                     self.profile)
        self.loadPlugins()
        self.loadExtensions()
        self.windowmain.setup()
        self.windowmain.on_calendar_selected(None)
        self.refreshMainSportList()
        self.windowmain.run()
        logging.debug('<<')
class Executor:
    plugins = None

    def process_command(self, message):
        # 1. Разбор строки как словаря
        message_dict = json.loads(message)
        print('message_dict: %s' % message_dict)
        # 2. Проверка на безопасность
        if "key" in message_dict and message_dict["key"] == app.settings.key:
            print('Прошли проверку безопасности.')
            command = None
            # Проверка наличия команды
            if "command" in message_dict:
                command = message_dict["command"]
                # Уточнение типа команды
                if "plugin" in message_dict:
                    plugin = message_dict["plugin"]
                    if plugin:
                        print('Need plugin: %s' % plugin)
                # Запускаем указанную команду
                print('We will run next command: %s' % command)
                if plugin:
                    plugin_command = command[0]
                    plugin_args = command[1:]
                    if plugin in self.plugins.available:
                        # Плагин есть в загруженных
                        if plugin_command in self.plugins.available[plugin].functions.available:
                            # Run function
                            self.plugins.available[plugin].functions.available[plugin_command].func(plugin_args)

                        else:
                            print('Function "%s" not found in that plugin.' % plugin_command)
                    else:
                        print('Plugin "%s" not found.' % plugin)
                else:
                    # Если команда не требует плагина - просто выполняем её.
                    subprocess.run(command)

    def __init__(self):
        self.plugins = Plugins()
        self.plugins.print()
Exemple #6
0
 def __init__(self):
     self.log = logging.getLogger("disper")
     self.log.setLevel(logging.WARNING)
     self._options_init()
     self.plugins = Plugins(self)
     # self.plugins.call('init') # can't really do here since list of plugins isn't read yet
     self.switcher = Switcher()
     # add default options
     # TODO do initial parsing too so errors can be traced to config
     conffile = os.path.join(os.getenv("HOME"), ".disper", "config")
     if os.path.exists(conffile):
         f = open(conffile, "r")
         opts = ""
         for l in f.readlines():
             opts += l.split("#", 1)[0] + " "
         f.close()
         self.options_append(shlex.split(opts))
Exemple #7
0
 def __init__(self,filename = None, data_path = None):
     #Version constants
     self.version ="1.10.0-dev"
     #Process command line options
     self.startup_options = self.get_options()
     #Setup logging
     self.environment = Environment(platform.get_platform(), self.startup_options.conf_dir)
     self.environment.create_directories()
     self.set_logging(self.startup_options.log_level, self.startup_options.log_type)
     logging.debug('>>')
     logging.debug("PyTrainer version %s" % (self.version))
     self.data_path = data_path
     self.date = Date()
     self.ddbb = None
     # Checking profile
     logging.debug('Checking configuration and profile...')
     self.profile = Profile(self.environment, self.data_path,self)
     self.uc = UC()
     self.windowmain = None
     self.ddbb = DDBB(self.profile, self)
     logging.debug('connecting to DDBB')
     self.ddbb.connect()
     
     initialize_data(self.ddbb, self.environment.conf_dir)
         
     self._sport_service = SportService(self.ddbb)
     self.record = Record(self._sport_service, data_path, self)
     self.athlete = Athlete(data_path,self)
     self.stats = Stats(self._sport_service, self)
     pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1)
     self.activitypool = ActivityPool(self, size=pool_size)
     #preparamos la ventana principal
     self.windowmain = Main(self._sport_service, data_path,self,self.version, gpxDir=self.profile.gpxdir)
     self.date = Date(self.windowmain.calendar)
     self.waypoint = Waypoint(data_path,self)
     self.extension = Extension(data_path, self)
     self.plugins = Plugins(data_path, self)
     self.importdata = Importdata(self._sport_service, data_path, self, self.profile)
     self.loadPlugins()
     self.loadExtensions()
     self.windowmain.setup()
     self.windowmain.on_calendar_selected(None)
     self.refreshMainSportList()
     self.windowmain.run()
     logging.debug('<<')
class PluginLoaderTest(unittest.TestCase):

    def setUp(self):
        configuration = config.Configuration('tests/plugins/test_pluginloader.config.json')
        self.plugins = Plugins(configuration)

    def tearDown(self):
        pass

    def test_config_one(self):
        plugins = self.plugins.all_plugins()
        watchers = plugins.get("watchers")
        watcher_names = [watcher.name for watcher in watchers]
        watcher_names.sort()

        self.assertEqual(watcher_names, ["tests/plugins/test_pluginloader_testplugins/debug"])

        self.assertIsNotNone(plugins.get("hourly"))
        self.assertIsNotNone(plugins.get("seven_minutes"))
Exemple #9
0
class PluginLoaderTest(unittest.TestCase):
    def setUp(self):
        configuration = config.Configuration(
            'tests/plugins/test_pluginloader.config.json')
        self.plugins = Plugins(configuration)

    def tearDown(self):
        pass

    def test_config_one(self):
        plugins = self.plugins.all_plugins()
        watchers = plugins.get("watchers")
        watcher_names = [watcher.name for watcher in watchers]
        watcher_names.sort()

        self.assertEqual(watcher_names,
                         ["tests/plugins/test_pluginloader_testplugins/debug"])

        self.assertIsNotNone(plugins.get("hourly"))
        self.assertIsNotNone(plugins.get("seven_minutes"))
Exemple #10
0
class Loader(Owner):
    def __init__(self, init_cfg: dict, init_state: dict, path: dict,
                 sig: SignalHandlerDummy):
        self._sig = sig
        self.reload = False
        self._restore_filename = None
        self._lock = threading.Lock()
        self._stts_lock = threading.Lock()
        self._join_lock = threading.Lock()

        self._pub = PubSub()
        self._sig.set_wakeup_callback(
            lambda: self.sub_call('default', 'terminal_stop', True))

        self._logger = logger.Logger(self)
        proxies.add_logger(self._logger.add('Proxy'))

        self._cfg = ConfigHandler(cfg=init_cfg,
                                  state=init_state,
                                  path=path,
                                  log=self._logger.add('CFG'),
                                  owner=self)
        self._logger.init(cfg=self._cfg, owner=self)
        self._log = self._logger.add('SYSTEM')

        self._listen = Listener(cfg=self._cfg,
                                log=self._logger.add('REC'),
                                owner=self)
        self._notifier = MajordomoNotifier(cfg=self._cfg,
                                           log=self._logger.add('Notifier'),
                                           owner=self)
        self._tts = stts.TextToSpeech(cfg=self._cfg,
                                      log=self._logger.add('TTS'))
        self._play = Player(cfg=self._cfg,
                            log=self._logger.add('Player'),
                            owner=self)
        self._music = music_constructor(cfg=self._cfg,
                                        logger=self._logger,
                                        owner=self)
        self._stt = stts.SpeechToText(cfg=self._cfg,
                                      log=self._logger.add('STT'),
                                      owner=self)
        self._mm = ModuleManager(cfg=self._cfg,
                                 log=self._logger.add('MM'),
                                 owner=self)
        self._updater = Updater(cfg=self._cfg,
                                log=self._logger.add('Updater'),
                                owner=self)
        self._backup = Backup(cfg=self._cfg,
                              log=self._logger.add('Backup'),
                              owner=self)
        self._terminal = MDTerminal(cfg=self._cfg,
                                    log=self._logger.add('Terminal'),
                                    owner=self)
        self._server = server_constructor(cfg=self._cfg,
                                          logger=self._logger,
                                          owner=self)
        self._plugins = Plugins(cfg=self._cfg,
                                log=self._logger.add('Plugins'),
                                owner=self)
        self._duplex_pool = DuplexPool(cfg=self._cfg,
                                       log=self._logger.add('DP'),
                                       owner=self)

        self._discovery = DiscoveryServer(cfg=self._cfg,
                                          log=self._logger.add('Discovery'))

    def start_all_systems(self):
        self._music.start()
        self._play.start()
        self._play.say_info(F(
            'Приветствую. Голосовой терминал настраивается, три... два... один...'
        ),
                            0,
                            wait=0.5)
        self._stt.start()
        self._cfg.start()
        self._notifier.start()
        self._mm.start()
        self._updater.start()
        self._terminal.start()
        self._server.start()
        self._discovery.start()
        self._backup.start()
        self._plugins.start()

        self.messenger(
            lambda: self.log(available_version_msg(self._cfg.version_info),
                             logger.INFO), None)
        self.sub_call('default', 'version', self._cfg.version_str)
        self.volume_callback(self.get_volume())

    def stop_all_systems(self):
        self._cfg.config_save(final=True)
        self.join_thread(self._plugins)
        self._mm.stop()
        self.join_thread(self._discovery)
        self.join_thread(self._server)
        self.join_thread(self._terminal)
        self.join_thread(self._backup)
        self.join_thread(self._updater)
        self.join_thread(self._notifier)
        self.join_thread(self._duplex_pool)

        self._play.quiet()
        self._play.kill_popen()
        self._play.say_info(F('Голосовой терминал завершает свою работу.'))

        self._stt.stop()
        self._play.stop()
        self.join_thread(self._music)

        if self._restore_filename:
            self._backup.restore(self._restore_filename)
            self._restore_filename = ''

        self.join_thread(self._logger.remote_log)
        self._pub.stopping = True
        self._logger.join()
        self._pub.join()

        self._pub.report()

    def log(self, msg: str, lvl=logger.DEBUG):
        self._log(msg, lvl)

    def join_thread(self, obj):
        def obj_log(msg_: str, lvl=logger.DEBUG):
            if log_present:
                obj.log(msg_, lvl)

        def diagnostic_msg() -> str:
            _call = getattr(obj, 'diagnostic_msg', None)
            return ' {}'.format(_call()) if callable(_call) else ''

        with self._join_lock:
            close_signal = getattr(obj, 'close_signal', None)
            if close_signal:
                close_signal()
            if not obj.work:
                return
            log_present = callable(getattr(obj, 'log', None))
            obj.work = False
            obj_log('stopping...')
            stop_time = time.time()
            obj.join()
            stop_time = time.time() - stop_time
            if not obj.is_alive():
                obj_log('stop.', logger.INFO)
            else:
                obj_log('stopping error.', logger.ERROR)
                name_ = '.'.join(getattr(obj.log, 'name',
                                         [''])) if log_present else None
                name_ = name_ or str(obj)
                msg = 'Thread \'{}\' stuck and not stopping in {}!{}'.format(
                    name_, pretty_time(stop_time), diagnostic_msg())
                self.log(msg, logger.ERROR)

    def subscribe(self, event, callback, channel='default') -> bool:
        return self._pub.subscribe(event, callback, channel)

    def unsubscribe(self, event, callback, channel='default') -> bool:
        return self._pub.unsubscribe(event, callback, channel)

    def registration(self, event: str, channel='default'):
        return self._pub.registration(event, channel)

    def has_subscribers(self, event: str, channel='default') -> bool:
        return self._pub.has_subscribers(event, channel)

    def events_list(self, channel='default') -> list:
        return self._pub.events_list(channel)

    def send_notify(self, event: str, *args, **kwargs):
        return self._pub.sub_call('default', event, *args, **kwargs)

    def sub_call(self, channel: str, event: str, *args, **kwargs):
        return self._pub.sub_call(channel, event, *args, **kwargs)

    @staticmethod
    def messenger(call, callback, *args, **kwargs) -> bool:
        return Messenger(call, callback, *args, **kwargs)()

    def insert_module(self, module) -> bool:
        return self._mm.insert_module(module)

    def extract_module(self, callback) -> bool:
        return self._mm.extract_module(callback)

    def insert_detectors(self, detector):
        detector = prepare_detectors(detector)
        if not detector:
            return

        def callback():
            with self._lock:
                detectors.DETECTORS.update(detector)
                self.__reconfigure_terminal(detector)

        # noinspection PyTypeChecker
        self.terminal_call('callme', callback, save_time=False)

    def extract_detectors(self, detector):
        detector = prepare_detectors(detector, True)
        if not detector:
            return

        def callback():
            with self._lock:
                [detectors.DETECTORS.pop(x, None) for x in detector]
                self.__reconfigure_terminal(detector)

        # noinspection PyTypeChecker
        self.terminal_call('callme', callback, save_time=False)

    def add_stt_provider(self, name: str, entrypoint) -> bool:
        with self._stts_lock:
            if name not in STT.PROVIDERS:
                STT.PROVIDERS[name] = entrypoint
                return True
            return False

    def remove_stt_provider(self, name: str):
        with self._stts_lock:
            try:
                return STT.PROVIDERS.pop(name)
            except KeyError:
                return None

    def add_tts_provider(self, name: str, entrypoint) -> bool:
        with self._stts_lock:
            if name not in TTS.PROVIDERS:
                TTS.PROVIDERS[name] = entrypoint
                return True
            return False

    def remove_tts_provider(self, name: str):
        with self._stts_lock:
            try:
                return TTS.PROVIDERS.pop(name)
            except KeyError:
                return None

    def tts_providers(self) -> list:
        with self._stts_lock:
            return list(TTS.PROVIDERS.keys())

    def stt_providers(self) -> list:
        with self._stts_lock:
            return list(STT.PROVIDERS.keys())

    def is_tts_provider(self, name: str) -> bool:
        return name in TTS.PROVIDERS

    def is_stt_provider(self, name: str) -> bool:
        return name in STT.PROVIDERS

    def plugins_status(self, state: str) -> dict:
        return self._plugins.status(state)

    def get_plugin(self, name: str) -> object:
        try:
            return self._plugins.modules[name]
        except KeyError:
            raise RuntimeError('Plugin \'{}\' not found'.format(name))
        except Exception as e:
            raise RuntimeError('Error accessing to plugin \'{}\': {}'.format(
                name, e))

    def list_notifications(self) -> list:
        return self._notifier.list_notifications()

    def add_notifications(self, events: list, is_self=False) -> list:
        return self._notifier.add_notifications(events, is_self)

    def remove_notifications(self, events: list) -> list:
        return self._notifier.remove_notifications(events)

    def say(self,
            msg: str,
            lvl: int = 2,
            alarm=None,
            wait=0,
            is_file: bool = False,
            blocking: int = 0):
        self._play.say(msg, lvl, alarm, wait, is_file, blocking)

    def play(self, file, lvl: int = 2, wait=0, blocking: int = 0):
        self._play.play(file, lvl, wait, blocking)

    def say_info(self,
                 msg: str,
                 lvl: int = 2,
                 alarm=None,
                 wait=0,
                 is_file: bool = False):
        self._play.say_info(msg, lvl, alarm, wait, is_file)

    def set_lvl(self, lvl: int) -> bool:
        return self._play.set_lvl(lvl)

    def clear_lvl(self):
        self._play.clear_lvl()

    def quiet(self):
        self._play.quiet()

    def full_quiet(self):
        self._play.full_quiet()

    def really_busy(self) -> bool:
        return self._play.really_busy()

    @state_cache(interval=0.008)
    def noising(self) -> bool:
        return self._play.noising()

    def kill_popen(self):
        self._play.kill_popen()

    def listen(self,
               hello: str = '',
               deaf: bool = True,
               voice: bool = False) -> tuple:
        return self._stt.listen(hello, deaf, voice)

    def voice_record(self,
                     hello: str or None,
                     save_to: str,
                     convert_rate=None,
                     convert_width=None,
                     limit=8):
        return self._stt.voice_record(hello, save_to, convert_rate,
                                      convert_width, limit)

    def voice_recognition(self,
                          audio,
                          quiet: bool = False,
                          fusion=None) -> str:
        return self._stt.voice_recognition(audio, quiet, fusion)

    @property
    def max_mic_index(self) -> int:
        return self._stt.max_mic_index

    @max_mic_index.setter
    def max_mic_index(self, val: int):
        self._stt.max_mic_index = val

    @property
    def mic_index(self) -> int:
        return self._stt.get_mic_index()

    def phrase_from_files(self, files: list) -> tuple:
        return self._stt.phrase_from_files(files)

    def multiple_recognition(self, file_or_adata, providers: list) -> list:
        return self._stt.multiple_recognition(file_or_adata, providers)

    @property
    def sys_say_chance(self) -> bool:
        return self._stt.sys_say.chance

    def music_state(self) -> str:
        return self._music.state()

    def music_play(self, uri):
        self._music.play(uri)

    def music_pause(self, paused=None):
        self._music.pause(paused)

    @property
    def music_plays(self) -> bool:
        return self._music.plays

    @property
    def music_volume(self):
        return self._music.volume

    @music_volume.setter
    def music_volume(self, vol):
        self._music.volume = vol

    @property
    def music_real_volume(self):
        return self._music.real_volume

    @music_real_volume.setter
    def music_real_volume(self, vol):
        self._music.real_volume = vol

    @property
    def music_track_name(self) -> str or None:
        return self._music.get_track_name()

    def tts(self, msg, realtime: bool = True):
        return self._tts.tts(msg, realtime)

    def ask_again_callback(self):
        self._pub.call('ask_again')

    def voice_activated_callback(self):
        self._pub.call('voice_activated')

    def speech_recognized_callback(self, status: bool):
        if status and self._cfg.gts('alarm_recognized'):
            self.play(self._cfg.path['bimp'])
        self._pub.call(
            'speech_recognized_{}success'.format('' if status else 'un'))

    def record_callback(self, start_stop: bool):
        self._pub.call('start_record' if start_stop else 'stop_record')

    def say_callback(self, start_stop: bool):
        self._pub.call('start_talking' if start_stop else 'stop_talking')

    def speech_recognized(self, start_stop: bool):
        self._pub.call('start_recognized' if start_stop else 'stop_recognized')

    def music_status_callback(self, status: str):
        self._pub.call('music_status',
                       status if status is not None else 'error')

    def music_volume_callback(self, volume: int):
        self._pub.call('music_volume', volume if volume is not None else -1)

    def volume_callback(self, volume: int):
        self._pub.call('volume', volume)

    @property
    def srv_ip(self) -> str:
        return self._cfg['smarthome']['ip']

    def update(self):
        self._updater.update()

    def manual_rollback(self):
        self._updater.manual_rollback()

    def backup_manual(self):
        self._backup.manual_backup()

    def backup_restore(self, filename: str):
        if not self._restore_filename and filename:
            self._restore_filename = filename
            self.die_in(3, reload=True)

    def backup_list(self) -> list:
        return self._backup.backup_list()

    def modules_tester(self, phrase: str, call_me=None, rms=None, model=None):
        return self._mm.tester(phrase, call_me, rms, model)

    def die_in(self, wait, reload=False):
        self.reload = reload
        self._sig.die_in(wait)

    @property
    def get_volume_status(self) -> dict:
        music_volume = self._music.real_volume
        return {
            'volume': self.get_volume(),
            'music_volume': music_volume if music_volume is not None else -1
        }

    def terminal_call(self,
                      cmd: str,
                      data='',
                      lvl: int = 0,
                      save_time: bool = True):
        self._terminal.call(cmd, data, lvl, save_time)

    def terminal_listen(self) -> bool:
        return self._terminal.listening

    def recognition_forever(self, interrupt_check: callable,
                            callback: callable):
        return self._listen.recognition_forever(interrupt_check, callback)

    def get_vad_detector(self,
                         source_or_mic,
                         vad_mode=None,
                         vad_lvl=None,
                         energy_lvl=None,
                         energy_dynamic=None):
        return self._listen.get_vad_detector(source_or_mic, vad_mode, vad_lvl,
                                             energy_lvl, energy_dynamic)

    def detected_fake(self, text: str, rms=None, model=None, cb=None):
        self._listen.detected_fake(text, rms, model, cb)

    def listener_listen(self, r=None, mic=None, vad=None):
        return self._listen.listen(r, mic, vad)

    def background_listen(self):
        return self._listen.background_listen()

    def get_volume(self) -> int:
        control = self._cfg.gt('volume', 'line_out', '')
        card = self._cfg.gt('volume', 'card', 0)
        if not control or control == volume_.UNDEFINED:
            return -2
        return volume_.get_volume(control, card)

    def set_volume(self, vol) -> int:
        control = self._cfg.gt('volume', 'line_out', '')
        card = self._cfg.gt('volume', 'card', 0)
        if not control or control == volume_.UNDEFINED:
            return -2
        try:
            return volume_.set_volume(vol, control, card)
        except RuntimeError as e:
            self.log('set_volume({}): {}'.format(vol, e), logger.WARN)
            return -1

    def settings_from_inside(self, cfg: dict) -> bool:
        with self._lock:
            return self._cfg.update_from_dict(cfg)

    def settings_from_srv(self, cfg: str or dict) -> dict:
        # Reload modules if their settings could be changes
        with self._lock:
            diff = self._cfg.update_from_external(cfg)
            reload_terminal = False
            detector_reconfigure = False
            vad_reconfigure = False
            if diff is None:
                self._cfg.print_cfg_no_change()
                return {}
            lang, lang_check = None, None
            if is_sub_dict('settings',
                           diff) and ('lang' in diff['settings']
                                      or 'lang_check' in diff['settings']):
                # re-init lang
                lang = diff['settings'].pop('lang', None)
                lang_check = diff['settings'].pop('lang_check', None)
                self._cfg.lang_init()
                if lang:
                    # reload phrases
                    self._stt.reload()
                    # reload modules
                    self._mm.reload()
            if is_sub_dict('models', diff):
                # reload models. Reload terminal - later
                self._cfg.models_load()
                reload_terminal = True
            if is_sub_dict('log', diff):
                # reload logger
                self._logger.reload()
            if is_sub_dict('cache', diff):
                # re-check tts cache
                self._cfg.tts_cache_check()
            if is_sub_dict('proxy', diff):
                # re-init proxy
                self._cfg.proxies_init()
            if is_sub_dict('music', diff):
                # reconfigure music server
                self.music_reload()
            if is_sub_dict('update', diff):
                # update 'update' interval
                self._updater.reload()
            if is_sub_dict('backup', diff):
                # update backup interval
                self._backup.reload()
            if is_sub_dict('smarthome', diff):
                if 'allow_addresses' in diff['smarthome']:
                    # re-init allow ip addresses
                    self._cfg.allow_addresses_init()
                if 'disable_server' in diff['smarthome']:
                    # handle [smarthome] disable_server
                    self.messenger(self.server_reload, None)
                # resubscribe
                self._notifier.reload(diff)
                self._duplex_pool.reload()
            if is_sub_dict('noise_suppression', diff):
                # reconfigure APM. Reload terminal - later
                self._cfg.apm_configure()
                reload_terminal = True
            if is_sub_dict('listener', diff):
                reload_terminal = True
                detector_reconfigure = 'detector' in diff['listener']
                vad_reconfigure = bool([
                    key for key in ('vad_mode', 'vad_chrome')
                    if key in diff['listener']
                ])
            if is_sub_dict('settings', diff) or reload_terminal:
                # reload terminal
                # noinspection PyTypeChecker
                self.terminal_call('reload',
                                   (detector_reconfigure, vad_reconfigure),
                                   save_time=False)

            # restore lang's
            if lang is not None:
                diff['settings']['lang'] = lang
            if lang_check is not None:
                diff['settings']['lang_check'] = lang_check

            # check and reload plugins
            self._plugins.reload(diff)
            self._cfg.print_cfg_change()
            self._cfg.config_save()
            return diff

    def music_reload(self):
        self._music = music_constructor(self._cfg, self._logger, self,
                                        self._music)

    def server_reload(self):
        self._server = server_constructor(self._cfg, self._logger, self,
                                          self._server)

    def __reconfigure_terminal(self, detector: set or dict):
        if self._cfg['listener'][
                'detector'] in detector or self._cfg.detector.NAME in detector:
            # noinspection PyProtectedMember
            self._terminal._reload((True, False))
Exemple #11
0
 def __init__(self):
     self.plugins = Plugins()
     self.plugins.print()
Exemple #12
0
class pyTrainer:
    def __init__(self, filename=None, data_path=None):
        # Based on Django's approach -> http://code.djangoproject.com/svn/django/trunk/django/__init__.py
        self.version = __import__('pytrainer').get_version()
        #Process command line options
        self.startup_options = self.get_options()
        #Setup logging
        self.environment = Environment(self.startup_options.conf_dir,
                                       data_path)
        self.environment.create_directories()
        self.environment.clear_temp_dir()
        self.set_logging(self.startup_options.log_level,
                         self.startup_options.log_type)
        logging.debug('>>')
        logging.info("pytrainer version %s" % (self.version))
        self.data_path = data_path

        # Checking profile
        logging.debug('Checking configuration and profile...')
        self.profile = Profile()
        # Write the default config to disk
        self.profile.saveProfile()
        self.uc = UC()
        self.profilewindow = None
        self.ddbb = DDBB(self.profile.sqlalchemy_url)
        logging.debug('connecting to DDBB')
        self.ddbb.connect()

        logging.info('Checking if some upgrade action is needed...')
        initialize_data(self.ddbb, self.environment.conf_dir)

        # Loading shared services
        logging.debug('Loading sport service...')
        self._sport_service = SportService(self.ddbb)
        logging.debug('Loading record service...')
        self.record = Record(self._sport_service, data_path, self)
        logging.debug('Loading athlete service...')
        self.athlete = Athlete(data_path, self)
        logging.debug('Loading stats service...')
        self.stats = Stats(self)
        logging.debug('Initializing activity pool...')
        pool_size = self.profile.getIntValue("pytraining",
                                             "activitypool_size",
                                             default=1)
        self.activitypool = ActivityService(self, size=pool_size)

        #Loading main window
        self.windowmain = None
        logging.debug('Loading main window...')
        self.windowmain = Main(self._sport_service,
                               data_path,
                               self,
                               self.version,
                               gpxDir=self.profile.gpxdir)

        # Select initial date depending on user's preference
        self.selectInitialDate()

        logging.debug('Loading waypoint service...')
        self.waypoint = WaypointService(data_path, self)
        logging.debug('Loading extension service...')
        self.extension = Extension(data_path, self)
        logging.debug('Loading plugins service...')
        self.plugins = Plugins(data_path, self)
        self.importdata = Importdata(self._sport_service, data_path, self,
                                     self.profile)
        logging.debug('Loading plugins...')
        self.loadPlugins()
        logging.debug('Loading extensions...')
        self.loadExtensions()
        logging.debug('Setting values for graphs, maps and waypoint editor...')
        self.windowmain.setup()
        self.windowmain.on_calendar_selected(None)
        logging.debug('Refreshing sport list... is this needed?')
        self.refreshMainSportList()
        logging.debug('Launching main window...')
        self.windowmain.run()
        logging.debug('<<')

    def get_options(self):
        '''
        Define usage and accepted options for command line startup

        returns: options - dict with option: value pairs
        '''
        usage = '''usage: %prog [options]

        For more help on valid options try:
           %prog -h '''
        parser = OptionParser(usage=usage)
        parser.set_defaults(log_level=logging.WARNING,
                            validate=False,
                            equip=False,
                            newgraph=True,
                            conf_dir=None,
                            log_type="file")
        parser.add_option("-d",
                          "--debug",
                          action="store_const",
                          const=logging.DEBUG,
                          dest="log_level",
                          help="enable logging at debug level")
        parser.add_option("-i",
                          "--info",
                          action="store_const",
                          const=logging.INFO,
                          dest="log_level",
                          help="enable logging at info level")
        parser.add_option("-w",
                          "--warn",
                          action="store_const",
                          const=logging.WARNING,
                          dest="log_level",
                          help="enable logging at warning level")
        parser.add_option("--error",
                          action="store_const",
                          const=logging.ERROR,
                          dest="log_level",
                          help="enable logging at error level")
        parser.add_option(
            "--valid",
            action="store_true",
            dest="validate",
            help=
            "enable validation of files imported by plugins (details at info or debug logging level) - note plugin must support validation"
        )
        parser.add_option("--oldgraph",
                          action="store_false",
                          dest="newgraph",
                          help="Turn off new graphing approach")
        parser.add_option(
            "--newgraph",
            action="store_true",
            dest="newgraph",
            help="Deprecated Option: Turn on new graphing approach")
        parser.add_option(
            "--confdir",
            dest="conf_dir",
            help=
            "Specify the directory where application configuration will be stored."
        )
        parser.add_option(
            "--logtype",
            dest="log_type",
            metavar="TYPE",
            type="choice",
            choices=["file", "console"],
            help=
            "Specify where logging should be output to. TYPE is one of 'file' (default), or 'console'."
        )
        (options, args) = parser.parse_args()
        return options

    def set_logging(self, level, log_type):
        '''Setup rotating log file with customized format'''
        if ("console" == log_type):
            handler = logging.StreamHandler(sys.stdout)
        else:
            handler = logging.handlers.RotatingFileHandler(
                self.environment.log_file, maxBytes=100000, backupCount=5)
        formatter = logging.Formatter(
            '%(asctime)s|%(levelname)s|%(module)s|%(funcName)s|%(message)s')
        handler.setFormatter(formatter)
        logging.getLogger('').addHandler(handler)
        self.set_logging_level(self.startup_options.log_level)

    def set_logging_level(self, level):
        '''Set level of information written to log'''
        logging.debug("Setting logger to level: " + str(level))
        logging.getLogger('').setLevel(level)
        logging.getLogger('sqlalchemy.engine').setLevel(level)

    def quit(self):
        logging.debug('--')
        logging.info("Exit!")
        #self.webservice.stop()
        self.windowmain.gtk_main_quit()
        logging.shutdown()
        sys.exit(
        )  # Any nonzero value is considered "abnormal termination" by shells and the like

    def selectInitialDate(self):
        logging.debug('>>')
        # self.windowmain.calendar comes from SimpleGladeApp initialisation, not really sure how... :?
        self.date = Date(self.windowmain.calendar)
        if self.profile.getValue("pytraining",
                                 "prf_startscreen") == "last_entry":
            logging.info(
                "User selection is to display last entry in start screen")
            last_entry_date = self.record.getLastRecordDateString()
            try:
                logging.info("Last activity found on %s" % last_entry_date)
                self.date.setDate(last_entry_date)
            except:
                logging.error(
                    "No data available regarding last activity date. Default date will be today"
                )
                logging.debug("Traceback: %s" % traceback.format_exc())
        else:
            logging.info(
                "User selection is to display current day in start screen")
        logging.debug('Setting date to %s' %
                      self.date.getDate().strftime("%Y-%m-%d"))
        logging.debug('<<')

    def loadPlugins(self):
        logging.debug('>>')
        activeplugins = self.plugins.getActivePlugins()
        if (len(activeplugins) < 1):
            logging.info("No active plugins")
        else:
            for plugin in activeplugins:
                # From version 1.10 on all file imports are managed via File -> import wizard
                # Only showing garmintools_full and garmin-hr in 'File' dropdown
                plugin_name = os.path.basename(plugin)
                if (plugin_name == "garmintools_full"
                        or plugin_name == "garmin-hr"):
                    txtbutton = self.plugins.loadPlugin(plugin)
                    self.windowmain.addImportPlugin(txtbutton)
                else:
                    logging.debug(
                        'From version 1.10 on, file import plugins are managed via File -> Import. Not displaying plugin '
                        + plugin_name)
        logging.debug('<<')

    def loadExtensions(self):
        logging.debug('>>')
        activeextensions = self.extension.getActiveExtensions()
        if (len(activeextensions) < 1):
            logging.info("No active extensions")
        else:
            for extension in activeextensions:
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.addExtension(txtbutton)
        logging.debug('<<')

    def runPlugin(self, widget, pathPlugin):
        logging.debug('>>')
        self.pluginClass = self.plugins.importClass(pathPlugin)
        pluginFiles = self.pluginClass.run()
        if pluginFiles is not None:
            logging.debug("Plugin returned %d files" % (len(pluginFiles)))
            #process returned GPX files
            for (pluginFile, sport) in pluginFiles:
                if os.path.isfile(pluginFile):
                    logging.info('File exists. Size: %d. Sport: %s' %
                                 (os.path.getsize(pluginFile), sport))
                    if self.record.importFromGPX(pluginFile, sport) is None:
                        logging.error("Error importing file " + pluginFile)
                else:
                    logging.error('File ' + pluginFile + ' not valid')
        else:
            logging.debug("No files returned from Plugin")
        self.refreshListRecords()
        self.refreshGraphView("day")
        logging.debug('<<')

    def runExtension(self, extension, id):
        logging.debug('>>')
        #print("Extension id: %s" % str(id))
        activity = self.activitypool.get_activity(id)
        txtbutton, pathExtension, type = extension
        self.extensionClass = self.extension.importClass(pathExtension)
        self.extensionClass.run(id, activity)
        #if type == "record":
        #   #Si es record le tenemos que crear el googlemaps, el gpx y darle el id de la bbdd
        #   alert = self.extension.runExtension(pathExtension,id)

        logging.debug('<<')

    def refreshMainSportList(self):
        logging.debug('>>')
        sports = self._sport_service.get_all_sports()
        self.windowmain.updateSportList(sports)
        logging.debug('<<')

    def refreshGraphView(self, view, sport=None):
        logging.debug('>>')
        if self.windowmain is None:
            logging.debug("First call to refreshGraphView")
            logging.debug('<<')
            return
        date_selected = self.date.getDate()
        if view == "record":
            logging.debug('record view')
            if self.windowmain.recordview.get_current_page() == 0:
                self.refreshRecordGraphView("info")
            elif self.windowmain.recordview.get_current_page() == 1:
                self.refreshRecordGraphView("graphs")
            elif self.windowmain.recordview.get_current_page() == 2:
                self.refreshRecordGraphView("map")
            elif self.windowmain.recordview.get_current_page() == 3:
                self.refreshRecordGraphView("heartrate")
            elif self.windowmain.recordview.get_current_page() == 4:
                self.refreshRecordGraphView("analytics")
        elif view == "day":
            logging.debug('day view')
            self.windowmain.actualize_dayview(date_selected)
        elif view == "week":
            logging.debug('week view')
            date_range = DateRange.for_week_containing(date_selected)
            self.windowmain.actualize_weekview(date_range)
        elif view == "month":
            logging.debug('month view')
            date_range = DateRange.for_month_containing(date_selected)
            nameMonth, daysInMonth = getNameMonth(date_selected)
            self.windowmain.actualize_monthview(date_range, nameMonth,
                                                daysInMonth)
        elif view == "year":
            logging.debug('year view')
            date_range = DateRange.for_year_containing(date_selected)
            self.windowmain.actualize_yearview(date_range, date_selected.year)
        elif view == "listview":
            logging.debug('list view')
            self.refreshListView()
        elif view == "athlete":
            logging.debug('athlete view')
            self.windowmain.on_athleteview_activate()
        elif view == "stats":
            logging.debug('stats view')
            self.windowmain.on_statsview_activate()
        else:
            print "Unknown view %s" % view
        logging.debug('<<')

    def refreshRecordGraphView(self, view, id_record=None):
        logging.debug('>>')
        logging.info('Working on ' + view + ' graph')
        if id_record is not None:
            #Refresh called for a specific record
            #Select correct record in treeview
            model = self.windowmain.recordTreeView.get_model()
            #Loop through all records in treeview looking for the correct one to highlight
            for i, row in enumerate(model):
                if row[0] == id_record:
                    self.windowmain.recordTreeView.set_cursor(i)
        else:
            selected, iter = self.windowmain.recordTreeView.get_selection(
            ).get_selected()
            if iter:
                id_record = selected.get_value(iter, 0)
            else:
                id_record = None
                view = "info"
        activity = self.activitypool.get_activity(id_record)
        if view == "info":
            self.windowmain.actualize_recordview(activity)
        if view == "graphs":
            self.windowmain.actualize_recordgraph(activity)
        if view == "map":
            self.refreshMapView()
        if view == "heartrate":
            self.windowmain.actualize_heartrategraph(activity)
            self.windowmain.actualize_hrview(activity)
        if view == "analytics":
            self.windowmain.actualize_analytics(activity)
        logging.debug('<<')

    def refreshMapView(self, full_screen=False):
        logging.debug('>>')
        if self.windowmain is None:
            logging.debug('Called before windowmain initialisation')
            logging.debug('<<')
            return
        selected, iter = self.windowmain.recordTreeView.get_selection(
        ).get_selected()
        id_record = selected.get_value(iter, 0)
        activity = self.activitypool.get_activity(id_record)
        logging.debug('Trying to show map for record ' + str(id_record))
        self.windowmain.actualize_map(activity, full_screen)
        logging.debug('<<')

    def refreshListRecords(self):
        logging.debug('>>')
        #Refresh list records
        date = self.date.getDate()
        if self.windowmain.activeSport:
            sport = self._sport_service.get_sport_by_name(
                self.windowmain.activeSport)
        else:
            sport = None
        self.windowmain.actualize_recordTreeView(date)
        #Mark the monthly calendar to show which days have activity?
        record_list = self.record.getRecordDayList(date, sport)
        self.windowmain.actualize_calendar(record_list)
        logging.debug('<<')

    def refreshAthleteView(self):
        logging.debug('>>')
        self.athlete.refresh()
        self.windowmain.actualize_athleteview(self.athlete)
        logging.debug('<<')

    def refreshStatsView(self):
        logging.debug('>>')
        self.stats.refresh()
        self.windowmain.actualize_statsview(
            self.stats, self.activitypool.get_all_activities())
        logging.debug('<<')

    def refreshListView(self, condition=None):
        logging.debug('>>')
        record_list = self.record.getRecordListByCondition(condition)
        self.windowmain.actualize_listview(record_list)
        logging.debug('<<')

    def refreshWaypointView(self, default_waypoint=None, redrawmap=1):
        logging.debug('>>')
        waypoint_list = self.waypoint.getAllWaypoints()
        self.windowmain.actualize_waypointview(waypoint_list, default_waypoint,
                                               redrawmap)
        logging.debug('<<')

    def editExtensions(self):
        logging.debug('>>')
        before = self.extension.getActiveExtensions()
        self.extension.manageExtensions()
        after = self.extension.getActiveExtensions()
        self.setExtensions(before, after)
        logging.debug('<<')

    def importData(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.importdata.runImportdata()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        self.refreshListRecords()
        self.refreshGraphView(self.windowmain.selected_view)
        logging.debug('<<')

    def editGpsPlugins(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.plugins.managePlugins()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        logging.debug('<<')

    def setMenuPlugins(self, activeplugins_before, activeplugins_after):
        logging.debug('>>')
        #Need to check for plugins that have been disabled (were active and now are not)
        for plugin in activeplugins_before:
            if plugin not in activeplugins_after:
                #disabled plugin -> need to unload plugin
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.removeImportPlugin(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for plugin in activeplugins_after:
            if plugin not in activeplugins_before:
                #new active plugin -> need to load plugin
                plugin_name = os.path.basename(plugin)
                if (plugin_name == "garmintools_full"
                        or plugin_name == "garmin-hr"):
                    txtbutton = self.plugins.loadPlugin(plugin)
                    self.windowmain.addImportPlugin(txtbutton)
                else:
                    logging.debug(
                        'From version 1.10 on file import plugins are managed via File -> Import. Not displaying plugin '
                        + plugin_name)
        logging.debug('<<')

    def setExtensions(self, before, after):
        logging.debug('>>')
        #Need to check for extensions that have been disabled (were active and now are not)
        for extension in before:
            if extension not in after:
                #disabled extension -> need to unload extension
                print "Need to disable extension %s " % extension
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.removeExtension(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for extension in after:
            if extension not in before:
                #new active extension -> need to load extension
                logging.debug("Enabling extension %s " % extension)
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.addExtension(txtbutton)
        logging.debug('<<')

    def newRecord(self,
                  title=None,
                  distance=None,
                  time=None,
                  upositive=None,
                  unegative=None,
                  bpm=None,
                  calories=None,
                  comment=None,
                  view=None):
        logging.debug('>>')
        date = self.date.getDate()
        self.record.newRecord(date, title, distance, time, upositive,
                              unegative, bpm, calories, comment)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def editRecord(self, id_record, view=None):
        logging.debug("Editing record with id: '%s'", id_record)
        self.record.editRecord(id_record)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeRecord(self, id_record, confirm=False, view=None):
        logging.debug('>>')
        if confirm:
            activity = self.activitypool.get_activity(id_record)
            self.activitypool.remove_activity_from_db(activity)
        else:
            msg = _("Delete this database entry?")
            params = [id_record, True]
            warning = Warning(self.data_path, self.removeRecord, params)
            warning.set_text(msg)
            warning.run()
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeWaypoint(self, id_waypoint, confirm=False):
        logging.debug('>>')
        if confirm:
            self.waypoint.removeWaypoint(id_waypoint)
            self.refreshWaypointView()
        else:
            msg = _("Delete this waypoint?")
            params = [id_waypoint, True]
            warning = Warning(self.data_path, self.removeWaypoint, params)
            warning.set_text(msg)
            warning.run()
        logging.debug('<<')

    def updateWaypoint(self, id_waypoint, lat, lon, name, desc, sym):
        logging.debug('>>')
        self.waypoint.updateWaypoint(id_waypoint, lat, lon, name, desc, sym)
        self.refreshWaypointView(id_waypoint)
        logging.debug('<<')

    def exportCsv(self):
        logging.debug('>>')
        from save import Save
        save = Save(self.data_path, self.record)
        save.run()
        logging.debug('<<')

    def editProfile(self):
        logging.debug('>>')
        from gui.windowprofile import WindowProfile
        self.profile.refreshConfiguration()
        if self.profilewindow is None:
            self.profilewindow = WindowProfile(self._sport_service,
                                               self.data_path,
                                               self.profile,
                                               pytrainer_main=self)
            logging.debug("setting data values")
            self.profilewindow.setValues(self.profile.configuration)
            self.profilewindow.run()
            self.profilewindow = None
        else:
            self.profilewindow.setValues(self.profile.configuration)
            self.profilewindow.present()
        self.profile.refreshConfiguration()

        self.activitypool.clear_pool()
        self.windowmain.setup()
        logging.debug('<<')
Exemple #13
0
    def __init__(self, filename=None, data_path=None):
        # Based on Django's approach -> http://code.djangoproject.com/svn/django/trunk/django/__init__.py
        self.version = __import__('pytrainer').get_version()
        #Process command line options
        self.startup_options = self.get_options()
        #Setup logging
        self.environment = Environment(self.startup_options.conf_dir,
                                       data_path)
        self.environment.create_directories()
        self.environment.clear_temp_dir()
        self.set_logging(self.startup_options.log_level,
                         self.startup_options.log_type)
        logging.debug('>>')
        logging.info("pytrainer version %s" % (self.version))
        self.data_path = data_path

        # Checking profile
        logging.debug('Checking configuration and profile...')
        self.profile = Profile()
        # Write the default config to disk
        self.profile.saveProfile()
        self.uc = UC()
        self.profilewindow = None
        self.ddbb = DDBB(self.profile.sqlalchemy_url)
        logging.debug('connecting to DDBB')
        self.ddbb.connect()

        logging.info('Checking if some upgrade action is needed...')
        initialize_data(self.ddbb, self.environment.conf_dir)

        # Loading shared services
        logging.debug('Loading sport service...')
        self._sport_service = SportService(self.ddbb)
        logging.debug('Loading record service...')
        self.record = Record(self._sport_service, data_path, self)
        logging.debug('Loading athlete service...')
        self.athlete = Athlete(data_path, self)
        logging.debug('Loading stats service...')
        self.stats = Stats(self)
        logging.debug('Initializing activity pool...')
        pool_size = self.profile.getIntValue("pytraining",
                                             "activitypool_size",
                                             default=1)
        self.activitypool = ActivityService(self, size=pool_size)

        #Loading main window
        self.windowmain = None
        logging.debug('Loading main window...')
        self.windowmain = Main(self._sport_service,
                               data_path,
                               self,
                               self.version,
                               gpxDir=self.profile.gpxdir)

        # Select initial date depending on user's preference
        self.selectInitialDate()

        logging.debug('Loading waypoint service...')
        self.waypoint = WaypointService(data_path, self)
        logging.debug('Loading extension service...')
        self.extension = Extension(data_path, self)
        logging.debug('Loading plugins service...')
        self.plugins = Plugins(data_path, self)
        self.importdata = Importdata(self._sport_service, data_path, self,
                                     self.profile)
        logging.debug('Loading plugins...')
        self.loadPlugins()
        logging.debug('Loading extensions...')
        self.loadExtensions()
        logging.debug('Setting values for graphs, maps and waypoint editor...')
        self.windowmain.setup()
        self.windowmain.on_calendar_selected(None)
        logging.debug('Refreshing sport list... is this needed?')
        self.refreshMainSportList()
        logging.debug('Launching main window...')
        self.windowmain.run()
        logging.debug('<<')
Exemple #14
0
    def __init__(self, init_cfg: dict, init_state: dict, path: dict,
                 sig: SignalHandlerDummy):
        self._sig = sig
        self.reload = False
        self._restore_filename = None
        self._lock = threading.Lock()
        self._stts_lock = threading.Lock()
        self._join_lock = threading.Lock()

        self._pub = PubSub()
        self._sig.set_wakeup_callback(
            lambda: self.sub_call('default', 'terminal_stop', True))

        self._logger = logger.Logger(self)
        proxies.add_logger(self._logger.add('Proxy'))

        self._cfg = ConfigHandler(cfg=init_cfg,
                                  state=init_state,
                                  path=path,
                                  log=self._logger.add('CFG'),
                                  owner=self)
        self._logger.init(cfg=self._cfg, owner=self)
        self._log = self._logger.add('SYSTEM')

        self._listen = Listener(cfg=self._cfg,
                                log=self._logger.add('REC'),
                                owner=self)
        self._notifier = MajordomoNotifier(cfg=self._cfg,
                                           log=self._logger.add('Notifier'),
                                           owner=self)
        self._tts = stts.TextToSpeech(cfg=self._cfg,
                                      log=self._logger.add('TTS'))
        self._play = Player(cfg=self._cfg,
                            log=self._logger.add('Player'),
                            owner=self)
        self._music = music_constructor(cfg=self._cfg,
                                        logger=self._logger,
                                        owner=self)
        self._stt = stts.SpeechToText(cfg=self._cfg,
                                      log=self._logger.add('STT'),
                                      owner=self)
        self._mm = ModuleManager(cfg=self._cfg,
                                 log=self._logger.add('MM'),
                                 owner=self)
        self._updater = Updater(cfg=self._cfg,
                                log=self._logger.add('Updater'),
                                owner=self)
        self._backup = Backup(cfg=self._cfg,
                              log=self._logger.add('Backup'),
                              owner=self)
        self._terminal = MDTerminal(cfg=self._cfg,
                                    log=self._logger.add('Terminal'),
                                    owner=self)
        self._server = server_constructor(cfg=self._cfg,
                                          logger=self._logger,
                                          owner=self)
        self._plugins = Plugins(cfg=self._cfg,
                                log=self._logger.add('Plugins'),
                                owner=self)
        self._duplex_pool = DuplexPool(cfg=self._cfg,
                                       log=self._logger.add('DP'),
                                       owner=self)

        self._discovery = DiscoveryServer(cfg=self._cfg,
                                          log=self._logger.add('Discovery'))
 def setUp(self):
     configuration = config.Configuration('tests/plugins/test_pluginloader.config.json')
     self.plugins = Plugins(configuration)
Exemple #16
0
class Disper:

    # static information
    name = "disper"
    version = "0.3.0"
    prefix = build.prefix
    prefix_share = build.prefix_share

    # option parsing
    argv = []
    parser = None  # option parser object
    options = None  # parsed options
    args = None  # parsed arguments

    # real work
    switcher = None  # switcher object
    plugins = None  # plugins object
    log = None

    def __init__(self):
        self.log = logging.getLogger("disper")
        self.log.setLevel(logging.WARNING)
        self._options_init()
        self.plugins = Plugins(self)
        # self.plugins.call('init') # can't really do here since list of plugins isn't read yet
        self.switcher = Switcher()
        # add default options
        # TODO do initial parsing too so errors can be traced to config
        conffile = os.path.join(os.getenv("HOME"), ".disper", "config")
        if os.path.exists(conffile):
            f = open(conffile, "r")
            opts = ""
            for l in f.readlines():
                opts += l.split("#", 1)[0] + " "
            f.close()
            self.options_append(shlex.split(opts))

    def _options_init(self):
        """initialize default command-line options"""
        usage = "usage: %prog [options] (-l|-s|-c|-e|-p|-i)"
        version = " ".join(map(str, [self.name, self.version]))
        self.parser = optparse.OptionParser(usage=usage, version=version)

        self.add_option(
            "-v", "--verbose", action="store_const", dest="debug", const=logging.INFO, help="show what's happening"
        )
        self.add_option(
            "-q",
            "--quiet",
            action="store_const",
            dest="debug",
            const=logging.ERROR,
            help="be quiet and only show errors",
        )
        self.add_option(
            "-r",
            "--resolution",
            dest="resolution",
            help='set resolution, e.g. "800x600", or "auto" to detect the display\'s preferred '
            + 'resolution, or "max" to use the maximum resolution advertised. For extend it '
            + "is possible to enter a single resolution for all displays or a comma-separated "
            + "list of resolutions (one for each display). Beware that many displays advertise "
            + 'resolutions they can not fully show, so "max" is not advised.',
        )
        self.add_option(
            "-d",
            "--displays",
            dest="displays",
            help='comma-separated list of displays to operate on, or "auto" to detect; '
            + "the first is the primary display.",
        )
        self.add_option(
            "-t",
            "--direction",
            dest="direction",
            choices=["left", "right", "top", "bottom"],
            help='where to extend displays: "left", "right", "top", or "bottom"',
        )
        self.add_option(
            "",
            "--scaling",
            dest="scaling",
            choices=["default", "native", "scaled", "centered", "aspect-scaled"],
            help='flat-panel scaling mode: "default", "native", "scaled", "centered", or "aspect-scaled"',
        )
        self.add_option(
            "",
            "--plugins",
            dest="plugins",
            help='comma-separated list of plugins to enable. Special names: "user" for all user plugins '
            + 'in ~/.disper/hooks; "all" for all plugins found; "none" for no plugins.',
        )
        self.add_option(
            "",
            "--cycle-stages",
            dest="cycle_stages",
            help="colon-separated list command-line arguments to cycle through",
        )

        group = optparse.OptionGroup(self.parser, "Actions", "Select exactly one of the following actions")
        self._add_option(
            group,
            "-l",
            "--list",
            action="append_const",
            const="list",
            dest="actions",
            help="list the attached displays",
        )
        self._add_option(
            group,
            "-s",
            "--single",
            action="append_const",
            const="single",
            dest="actions",
            help="only enable the primary display",
        )
        self._add_option(
            group,
            "-S",
            "--secondary",
            action="append_const",
            const="secondary",
            dest="actions",
            help="only enable the secondary display",
        )
        self._add_option(
            group, "-c", "--clone", action="append_const", const="clone", dest="actions", help="clone displays"
        )
        self._add_option(
            group, "-e", "--extend", action="append_const", const="extend", dest="actions", help="extend displays"
        )
        self._add_option(
            group,
            "-p",
            "--export",
            action="append_const",
            const="export",
            dest="actions",
            help="export current settings to standard output",
        )
        self._add_option(
            group,
            "-i",
            "--import",
            action="append_const",
            const="import",
            dest="actions",
            help="import current settings from standard input",
        )
        self._add_option(
            group,
            "-C",
            "--cycle",
            action="append_const",
            const="cycle",
            dest="actions",
            help="cycle through the list of cycle stages",
        )
        self.parser.add_option_group(group)

    def add_option(self, *args, **kwargs):
        """adds an option to the parser. Implements append_const for Python<2.5 too"""
        return self._add_option(self.parser, *args, **kwargs)

    def _add_option(self, obj, *args, **kwargs):
        """portable optarg add_option function that implements the append_const
        action for Python versions below 2.5; has an extra first argument as
        the object on which add_option should be called."""
        if sys.hexversion < 0x020500F0 and "action" in kwargs and kwargs["action"] == "append_const":
            # after: http://permalink.gmane.org/gmane.comp.python.optik.user/284
            def append_const_cb(const):
                def cb(opt, opt_str, value, parser):
                    if not getattr(parser.values, opt.dest):
                        setattr(parser.values, opt.dest, list())
                    getattr(parser.values, opt.dest).append(const)

                return cb

            kwargs["action"] = "callback"
            kwargs["callback"] = append_const_cb(kwargs["const"])
            del kwargs["const"]
        return obj.add_option(*args, **kwargs)

    def options_append(self, args):
        """parses command-line options; can be called multiple times"""
        self.argv += args

    def options_parse(self, args=None):
        """parses command-line options given; adds options to current list if set"""
        if args:
            self.options_append(args)
        (self.options, self.args) = self.parser.parse_args(self.argv)
        # need exactly one action
        if not self.options.actions:
            self.options.actions = []
        elif len(self.options.actions) > 1:
            self.parser.error(
                "conflicting actions, please specify exactly one action: " + ", ".join(self.options.actions)
            )
            raise SystemExit(2)

        if "import" in self.options.actions or "export" in self.options.actions:
            if self.options.resolution:
                self.log.warning("specified resolution ignored for %s" % self.options.actions[0])
            if self.options.displays:
                self.log.warning("specified displays ignored for %s" % self.options.actions[0])

        # apply defaults here to be able to detect if they were set explicitly or not
        if not self.options.direction:
            self.options.direction = "right"
        if not self.options.resolution:
            self.options.resolution = "auto"
        if not self.options.displays:
            self.options.displays = "auto"
        if not self.options.scaling:
            self.options.scaling = "default"
        if not self.options.debug:
            self.options.debug = logging.WARNING
        if self.options.plugins == None:
            self.options.plugins = "user"
        self.log.setLevel(self.options.debug)
        self.options.plugins = map(lambda x: x.strip(), self.options.plugins.split(","))
        if self.options.displays != "auto":
            self.options.displays = map(lambda x: x.strip(), self.options.displays.split(","))
        if self.options.resolution not in ["auto", "max"]:
            self.options.resolution = map(lambda x: x.strip(), self.options.resolution.split(","))
        self.plugins.set_enabled(self.options.plugins)

    def switch(self):
        """Switch to configuration as specified in the options"""
        if len(self.options.actions) == 0:
            self.log.info("no action specified")
            # show help if no action specified
            self.parser.print_help()
            raise SystemExit(2)
        if "single" in self.options.actions:
            if self.options.displays != "auto":
                self.log.warning("specified displays ignored for single")
            self.switch_primary()
        elif "secondary" in self.options.actions:
            if self.options.displays != "auto":
                self.log.warning("specified displays ignored for secondary")
            self.switch_secondary()
        elif "clone" in self.options.actions:
            self.switch_clone()
        elif "extend" in self.options.actions:
            self.switch_extend()
        elif "export" in self.options.actions:
            print self.export_config()
        elif "import" in self.options.actions:
            self.import_config("\n".join(sys.stdin))
        elif "cycle" in self.options.actions:
            self._cycle(self.options.cycle_stages.split(":"))
        elif "list" in self.options.actions:
            # list displays with resolutions
            displays = self.options.displays
            if displays == "auto":
                displays = self.switcher.get_displays()
            for disp in displays:
                res = self.switcher.get_resolutions_display(disp)
                res.sort()
                print "display %s: %s" % (disp, self.switcher.get_display_name(disp))
                print " resolutions: " + str(res)
        else:
            self.log.critical("program error, unrecognised action: " + ", ".join(self.options.actions))
            raise SystemExit(2)

    def switch_primary(self, res=None):
        """Only enable primary display.
           @param res resolution to use; or 'auto' for default or None for option"""
        return self.switch_single(self.switcher.get_primary_display())

    def switch_secondary(self, res=None):
        """Only enable secondary display.
           @param res resolution to use; or 'auto' for default or None for option"""
        primary = self.switcher.get_primary_display()
        try:
            display = [x for x in self.switcher.get_displays() if x != primary][0]
        except IndexError:
            self.log.critical("No secondary display found, falling back to primary.")
            return self.switch_single(primary, res)
        return self.switch_single(display, res)

    def switch_single(self, display=None, res=None):
        """Only enable one display.
           @param display display to enable; or 'auto' for primary or None for option
           @param res resolution to use; or 'auto' for default or None for option"""
        if not display:
            display = self.options.displays
        if display == "auto":
            display = self.switcher.get_primary_display()
        elif isinstance(display, list) and len(display) > 1:
            self.log.warning("single output requested but multiple specified; using first one")
            display = display[0]
        if display:
            display = [display]
        return self.switch_clone(display, res)

    def switch_clone(self, displays=None, res=None):
        """Clone displays.
           @param displays list of displays; or 'auto' for default or None for option
           @param res resolution; or 'auto' for default, 'max' for max or None for option"""
        # figure out displays
        if not displays:
            displays = self.options.displays
        if displays == "auto":
            displays = self.switcher.get_displays()
            self.log.info("auto-detected displays: " + ", ".join(displays))
        else:
            self.log.info("using specified displays: " + ", ".join(displays))
        # figure out resolutions
        if not res:
            res = self.options.resolution
            if type(res) == list or type(res) == tuple:
                if len(res) != 1:
                    raise TypeError("need single resolution for clone")
                res = res[0]
        if res == "auto" or res == "max":
            r = self.switcher.get_resolutions(displays).common()
            if len(r) == 0:
                self.log.critical("displays share no common resolution")
                raise SystemExit(1)
            if res == "max":  # ignore any preferred resolution
                for s in r:
                    s.weight = 0
            res = sorted(r)[-1]
        else:
            res = Resolution(res)
        # and switch
        result = self.switcher.switch_clone(displays, res)
        self.plugins.set_layout_clone(displays, res)
        self.plugins.call("switch")
        return result

    def switch_extend(self, displays=None, direction=None, ress=None):
        """Extend displays.
           @param displays list of displays; or 'auto for default or None for option
           @param direction direction to extend; or None for option
           @param ress list of resolutions; or 'auto' for default or 'max' for max or None for option"""
        # figure out displays
        if not displays:
            displays = self.options.displays
        if displays == "auto":
            displays = self.switcher.get_displays()
            self.log.info("auto-detected displays: " + ", ".join(displays))
        else:
            self.log.info("using specified displays: " + ", ".join(displays))
        # figure out resolutions
        if not ress:
            ress = self.options.resolution
        if ress == "max":  # max resolution for each
            # override auto-detection weights and get highest resolution
            ress = self.switcher.get_resolutions(displays)
            for rl in ress.values():
                for r in rl:
                    r.weight = 0
            ress = ress.select()
            self.log.info("maximum resolutions for displays: " + str(ress))
        elif ress == "auto":  # use preferred resolution for each
            ress = self.switcher.get_resolutions(displays).select()
            self.log.info("preferred resolutions for displays: " + str(ress))
        else:  # list of resolutions specified
            ress = ResolutionSelection(ress, displays)
            if len(ress) == 1:
                ress = ress * len(displays)
            elif len(ress) != len(displays):
                self.log.critical(
                    'resolution: must specify either "auto", "max", a single value, or one for each display'
                )
                raise SystemExit(2)
            self.log.info("selected resolutions for displays: " + str(ress))
        # figure out direction
        if not direction:
            direction = self.options.direction
        # and switch
        result = self.switcher.switch_extend(displays, direction, ress)
        self.plugins.set_layout_extend(displays, direction, ress)
        self.plugins.call("switch")
        return result

    def export_config(self):
        return self.switcher.export_config()

    def import_config(self, data):
        result = self.switcher.import_config(data)
        self.plugins.call("switch")
        return result

    def _cycle(self, stages):
        # read last state
        stage = 0
        disperconf = os.path.join(os.getenv("HOME"), ".disper")
        statefile = os.path.join(disperconf, "last_cycle_stage")
        if os.path.exists(statefile):
            f = open(statefile, "r")
            stage = int(f.readline())
            f.close()
        # apply next
        stage += 1
        if stage >= len(stages):
            stage = 0
        self.argv = filter(lambda x: x != "-C" and x != "--cycle", self.argv)
        self.options_parse(shlex.split(stages[stage]))
        try:
            self.switch()
        finally:
            # write new state to file; do it here to make sure that a
            # failing configuration doesn't block the cycling
            if not os.path.exists(disperconf):
                os.mkdir(disperconf)
            f = open(statefile, "w")
            f.write(str(stage) + "\n")
            f.close()
Exemple #17
0
class Disper:

    # static information
    name = 'disper'
    version = '0.3.1'
    prefix = build.prefix
    prefix_share = build.prefix_share

    # option parsing
    argv = []
    parser = None  # option parser object
    options = None  # parsed options
    args = None  # parsed arguments

    # real work
    _switcher = None  # switcher object, see Disper.switcher()
    plugins = None  # plugins object
    log = None
    conffile = None  # last configuration file read

    def __init__(self):
        self.log = logging.getLogger('disper')
        self.log.setLevel(logging.WARNING)
        self._options_init()
        self.plugins = Plugins(self)
        #self.plugins.call('init') # can't really do here since list of plugins isn't read yet
        # add default options
        # TODO do initial parsing too so errors can be traced to config
        self.options_append(self.config_read_default())

    def _options_init(self):
        '''initialize default command-line options'''
        usage = "usage: %prog [options] (-l|-s|-c|-e|-p|-i)"
        version = ' '.join(map(str, [self.name, self.version]))
        self.parser = optparse.OptionParser(usage=usage, version=version)

        self.add_option('-v',
                        '--verbose',
                        action='store_const',
                        dest='debug',
                        const=logging.INFO,
                        help='show what\'s happening')
        self.add_option('-q',
                        '--quiet',
                        action='store_const',
                        dest='debug',
                        const=logging.ERROR,
                        help='be quiet and only show errors')
        self.add_option(
            '-r',
            '--resolution',
            dest='resolution',
            help=
            'set resolution, e.g. "800x600", or "auto" to detect the display\'s preferred '
            +
            'resolution, "max" to use the maximum resolution advertised, or "off" to disable '
            +
            'the display entirely. For extend it is possible to enter a single resolution for '
            +
            'all displays or a comma-separated list of resolutions (one for each display). '
            +
            'Beware that many displays advertise resolutions they can not fully show, '
            + 'so "max" is not advised.')
        self.add_option(
            '-d',
            '--displays',
            dest='displays',
            help=
            'comma-separated list of displays to operate on, or "auto" to detect; '
            + 'the first is the primary display.')
        self.add_option(
            '-t',
            '--direction',
            dest='direction',
            choices=['left', 'right', 'top', 'bottom'],
            help='where to extend displays: "left", "right", "top", or "bottom"'
        )
        self.add_option(
            '',
            '--scaling',
            dest='scaling',
            choices=[
                'default', 'native', 'scaled', 'centered', 'aspect-scaled'
            ],
            help=
            'flat-panel scaling mode: "default", "native", "scaled", "centered", or "aspect-scaled"'
        )
        self.add_option(
            '',
            '--plugins',
            dest='plugins',
            help=
            'comma-separated list of plugins to enable. Special names: "user" for all user plugins '
            +
            'in %s/hooks; "all" for all plugins found; "none" for no plugins.'
            % (os.environ.get('XDG_CONFIG_HOME',
                              os.path.join('~', '.config', 'disper'))))
        self.add_option(
            '',
            '--cycle-stages',
            dest='cycle_stages',
            default='-c:-s:-S',
            help=
            'colon-separated list command-line arguments to cycle through; "-S:-c:-s" by default'
        )

        group = optparse.OptionGroup(
            self.parser, 'Actions',
            'Select exactly one of the following actions')
        self._add_option(group,
                         '-l',
                         '--list',
                         action='append_const',
                         const='list',
                         dest='actions',
                         help='list the attached displays')
        self._add_option(group,
                         '-s',
                         '--single',
                         action='append_const',
                         const='single',
                         dest='actions',
                         help='only enable the primary display')
        self._add_option(group,
                         '-S',
                         '--secondary',
                         action='append_const',
                         const='secondary',
                         dest='actions',
                         help='only enable the secondary display')
        self._add_option(group,
                         '-c',
                         '--clone',
                         action='append_const',
                         const='clone',
                         dest='actions',
                         help='clone displays')
        self._add_option(group,
                         '-e',
                         '--extend',
                         action='append_const',
                         const='extend',
                         dest='actions',
                         help='extend displays')
        self._add_option(group,
                         '-p',
                         '--export',
                         action='append_const',
                         const='export',
                         dest='actions',
                         help='export current settings to standard output')
        self._add_option(group,
                         '-i',
                         '--import',
                         action='append_const',
                         const='import',
                         dest='actions',
                         help='import current settings from standard input')
        self._add_option(group,
                         '-C',
                         '--cycle',
                         action='append_const',
                         const='cycle',
                         dest='actions',
                         help='cycle through the list of cycle stages')
        self.parser.add_option_group(group)

    def add_option(self, *args, **kwargs):
        '''adds an option to the parser. Implements append_const for Python<2.5 too'''
        return self._add_option(self.parser, *args, **kwargs)

    def _add_option(self, obj, *args, **kwargs):
        '''portable optarg add_option function that implements the append_const
        action for Python versions below 2.5; has an extra first argument as
        the object on which add_option should be called.'''
        if sys.hexversion < 0x020500f0 and 'action' in kwargs and \
                kwargs['action'] == 'append_const':
            # after: http://permalink.gmane.org/gmane.comp.python.optik.user/284
            def append_const_cb(const):
                def cb(opt, opt_str, value, parser):
                    if not getattr(parser.values, opt.dest):
                        setattr(parser.values, opt.dest, list())
                    getattr(parser.values, opt.dest).append(const)

                return cb

            kwargs['action'] = 'callback'
            kwargs['callback'] = append_const_cb(kwargs['const'])
            del kwargs['const']
        return obj.add_option(*args, **kwargs)

    def options_append(self, args):
        '''parses command-line options; can be called multiple times'''
        self.argv += args

    def options_parse(self, args=None):
        '''parses command-line options given; adds options to current list if set'''
        if args: self.options_append(args)
        (self.options, self.args) = self.parser.parse_args(self.argv)
        # need exactly one action
        if not self.options.actions: self.options.actions = []
        elif len(self.options.actions) > 1:
            self.parser.error(
                'conflicting actions, please specify exactly one action: ' +
                ', '.join(self.options.actions))
            raise SystemExit(2)

        if 'import' in self.options.actions or 'export' in self.options.actions:
            if self.options.resolution:
                self.log.warning('specified resolution ignored for %s' %
                                 self.options.actions[0])
            if self.options.displays:
                self.log.warning('specified displays ignored for %s' %
                                 self.options.actions[0])

        # apply defaults here to be able to detect if they were set explicitly or not
        if not self.options.direction: self.options.direction = "right"
        if not self.options.resolution: self.options.resolution = "auto"
        if not self.options.displays: self.options.displays = "auto"
        if not self.options.scaling: self.options.scaling = "default"
        if not self.options.debug: self.options.debug = logging.WARNING
        if self.options.plugins == None: self.options.plugins = "user"
        self.log.setLevel(self.options.debug)
        self.options.plugins = map(lambda x: x.strip(),
                                   self.options.plugins.split(','))
        if self.options.displays != 'auto':
            self.options.displays = map(lambda x: x.strip(),
                                        self.options.displays.split(','))
        if self.options.resolution not in ['auto', 'max', 'off']:
            self.options.resolution = map(lambda x: x.strip(),
                                          self.options.resolution.split(','))
        self.plugins.set_enabled(self.options.plugins)

    def config_read_default(self):
        '''Return default options from configuration files'''
        # Read old-style and XDG-style configuration files
        home = os.environ.get('HOME', '/')
        xdg_config_dirs = [os.path.join(home, '.disper')] + \
                          [os.environ.get('XDG_CONFIG_HOME', os.path.join(home, '.config', 'disper'))] + \
                          os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg/disper').split(':')
        xdg_config_dirs = filter(lambda x: x and os.path.exists(x),
                                 xdg_config_dirs)
        # since later configuration files override previous ones, reverse order of reading
        # TODO allow override of action, since multiple actions would now conflict
        xdg_config_dirs = reversed(xdg_config_dirs)
        opts = ''
        for d in xdg_config_dirs:
            conffile = os.path.join(d, 'config')
            if not os.path.exists(conffile): continue
            f = open(conffile, 'r')
            opts = ''
            for l in f.readlines():
                opts += l.split('#', 1)[0] + ' '
            f.close()
            # remember which configuration file was read last
            self.conffile = conffile
        return shlex.split(opts)

    def switch(self):
        '''Switch to configuration as specified in the options'''
        if len(self.options.actions) == 0:
            self.log.info('no action specified')
            # show help if no action specified
            self.parser.print_help()
            raise SystemExit(2)
        if 'single' in self.options.actions:
            self.switch_primary()
        elif 'secondary' in self.options.actions:
            self.switch_secondary()
        elif 'clone' in self.options.actions:
            self.switch_clone()
        elif 'extend' in self.options.actions:
            self.switch_extend()
        elif 'export' in self.options.actions:
            print self.export_config()
        elif 'import' in self.options.actions:
            self.import_config('\n'.join(sys.stdin))
        elif 'cycle' in self.options.actions:
            self._cycle(self.options.cycle_stages.split(':'))
        elif 'list' in self.options.actions:
            # list displays with resolutions
            displays = self.options.displays
            if displays == 'auto':
                displays = self.switcher().get_displays()
            for disp in displays:
                res = self.switcher().get_resolutions_display(disp)
                res.sort()
                print 'display %s: %s' % (
                    disp, self.switcher().get_display_name(disp))
                print ' resolutions: ' + str(res)
        else:
            self.log.critical('program error, unrecognised action: ' +
                              ', '.join(self.options.actions))
            raise SystemExit(2)

    def switch_primary(self, res=None):
        '''Only enable primary display.
           @param res resolution to use; or 'auto' for default or None for option'''
        if self.options.displays and self.options.displays != 'auto':
            return self.switch_single(self.options.displays[0])
        else:
            return self.switch_single(self.switcher().get_primary_display())

    def switch_secondary(self, res=None):
        '''Only enable secondary display.
           @param res resolution to use; or 'auto' for default or None for option'''
        if self.options.displays and self.options.displays != 'auto':
            if len(self.options.displays) >= 2:
                return self.switch_single(self.options.displays[1])
            else:
                self.log.critical(
                    'No secondary display found, falling back to primary.')
                return self.switch_single(self.options.displays[0])
        else:
            primary = self.switcher().get_primary_display()
            try:
                display = [
                    x for x in self.switcher().get_displays() if x != primary
                ][0]
            except IndexError:
                self.log.critical(
                    'No secondary display found, falling back to primary.')
                return self.switch_single(primary, res)
            return self.switch_single(display, res)

    def switch_single(self, display=None, res=None):
        '''Only enable one display.
           @param display display to enable; or 'auto' for primary or None for option
           @param res resolution to use; or 'auto' for default or None for option'''
        if not display: display = self.options.displays
        if display == 'auto':
            display = self.switcher().get_primary_display()
        elif isinstance(display, list) and len(display) > 1:
            self.log.warning(
                'single output requested but multiple specified; using first one'
            )
            display = display[0]
        if display: display = [display]
        return self.switch_clone(display, res)

    def switch_clone(self, displays=None, res=None):
        '''Clone displays.
           @param displays list of displays; or 'auto' for default or None for option
           @param res resolution; or 'auto' for default, 'max' for max, 'off' to disable
                  the display, 'none' or None for option'''
        # figure out displays
        if not displays: displays = self.options.displays
        if displays == 'auto':
            displays = self.switcher().get_displays()
            self.log.info('auto-detected displays: ' + ', '.join(displays))
        else:
            self.log.info('using specified displays: ' + ', '.join(displays))
        # figure out resolutions
        if not res:
            res = self.options.resolution
            if type(res) == list or type(res) == tuple:
                if len(res) != 1:
                    raise TypeError('need single resolution for clone')
                res = res[0]
        if res in ['auto', 'max']:
            r = self.switcher().get_resolutions(displays).common()
            if len(r) == 0:
                self.log.critical('displays share no common resolution')
                raise SystemExit(1)
            if res == 'max':  # ignore any preferred resolution
                for s in r:
                    s.weight = 0
            res = sorted(r)[-1]
        else:
            res = Resolution(res)
        # and switch
        result = self.switcher().switch_clone(displays, res)
        self.plugins.set_layout_clone(displays, res)
        self.plugins.call('switch')
        return result

    def switch_extend(self, displays=None, direction=None, ress=None):
        '''Extend displays.
           @param displays list of displays; or 'auto for default or None for option
           @param direction direction to extend; or None for option
           @param ress list of resolutions; or 'auto' for default or 'max' for max or None for option'''
        # figure out displays
        if not displays: displays = self.options.displays
        if displays == 'auto':
            displays = self.switcher().get_displays()
            self.log.info('auto-detected displays: ' + ', '.join(displays))
        else:
            self.log.info('using specified displays: ' + ', '.join(displays))
        # figure out resolutions
        if not ress: ress = self.options.resolution
        if ress == 'max':  # max resolution for each
            # override auto-detection weights and get highest resolution
            ress = self.switcher().get_resolutions(displays)
            for rl in ress.values():
                for r in rl:
                    r.weight = 0
            ress = ress.select()
            self.log.info('maximum resolutions for displays: ' + str(ress))
        elif ress == 'auto':  # use preferred resolution for each
            ress = self.switcher().get_resolutions(displays).select()
            self.log.info('preferred resolutions for displays: ' + str(ress))
        else:  # list of resolutions specified
            ress = ResolutionSelection(ress, displays)
            if len(ress) == 1:
                ress = ress * len(displays)
            elif len(ress) != len(displays):
                self.log.critical(
                    'resolution: must specify either "auto", "max", a single value, or one for each display'
                )
                raise SystemExit(2)
            self.log.info('selected resolutions for displays: ' + str(ress))
        # figure out direction
        if not direction: direction = self.options.direction
        # and switch
        result = self.switcher().switch_extend(displays, direction, ress)
        self.plugins.set_layout_extend(displays, direction, ress)
        self.plugins.call('switch')
        return result

    def export_config(self):
        return self.switcher().export_config()

    def import_config(self, data):
        result = self.switcher().import_config(data)
        self.plugins.call('switch')
        return result

    def _cycle(self, stages):
        # read last state
        stage = 0
        disperconf = None
        # TODO use X root window hint instead of file (which doesn't adhere to XDG)
        if self.conffile:
            disperconf = os.path.dirname(self.conffile)
        else:
            home = os.environ.get('HOME', '/')
            disperconf = os.environ.get(
                'XDG_CONFIG_HOME', os.path.join(home, '.config', 'disper'))
        statefile = os.path.join(disperconf, 'last_cycle_stage')
        self.log.debug('Cycle state file: ' + statefile)
        if os.path.exists(statefile):
            f = open(statefile, 'r')
            stage = int(f.readline())
            f.close()
        # apply next
        stage += 1
        if stage >= len(stages): stage = 0
        self.argv = filter(lambda x: x != '-C' and x != '--cycle', self.argv)
        self.options_parse(shlex.split(stages[stage]))
        try:
            self.switch()
        finally:
            # write new state to file; do it here to make sure that a
            # failing configuration doesn't block the cycling
            if not os.path.exists(disperconf):
                self.log.info(
                    'Creating disper configuration directory for statefile: ' +
                    disperconf)
                os.mkdir(disperconf)
            f = open(statefile, 'w')
            f.write(str(stage) + '\n')
            f.close()

    def switcher(self):
        '''Return switcher object (singleton).
        This is implemented as a method, so that it can be created only when
        needed to avoid errors when displaying help.'''
        if not self._switcher:
            self._switcher = Switcher()
        return self._switcher
Exemple #18
0
class pyTrainer:
    def __init__(self,filename = None, data_path = None):
        #Version constants
        self.version ="1.10.0-dev"
        #Process command line options
        self.startup_options = self.get_options()
        #Setup logging
        self.environment = Environment(platform.get_platform(), self.startup_options.conf_dir)
        self.environment.create_directories()
        self.set_logging(self.startup_options.log_level, self.startup_options.log_type)
        logging.debug('>>')
        logging.debug("PyTrainer version %s" % (self.version))
        self.data_path = data_path
        self.date = Date()
        self.ddbb = None
        # Checking profile
        logging.debug('Checking configuration and profile...')
        self.profile = Profile(self.environment, self.data_path,self)
        self.uc = UC()
        self.windowmain = None
        self.ddbb = DDBB(self.profile, self)
        logging.debug('connecting to DDBB')
        self.ddbb.connect()
        
        initialize_data(self.ddbb, self.environment.conf_dir)
            
        self._sport_service = SportService(self.ddbb)
        self.record = Record(self._sport_service, data_path, self)
        self.athlete = Athlete(data_path,self)
        self.stats = Stats(self._sport_service, self)
        pool_size = self.profile.getIntValue("pytraining","activitypool_size", default=1)
        self.activitypool = ActivityPool(self, size=pool_size)
        #preparamos la ventana principal
        self.windowmain = Main(self._sport_service, data_path,self,self.version, gpxDir=self.profile.gpxdir)
        self.date = Date(self.windowmain.calendar)
        self.waypoint = Waypoint(data_path,self)
        self.extension = Extension(data_path, self)
        self.plugins = Plugins(data_path, self)
        self.importdata = Importdata(self._sport_service, data_path, self, self.profile)
        self.loadPlugins()
        self.loadExtensions()
        self.windowmain.setup()
        self.windowmain.on_calendar_selected(None)
        self.refreshMainSportList()
        self.windowmain.run()
        logging.debug('<<')


    def get_options(self):
        '''
        Define usage and accepted options for command line startup

        returns: options - dict with option: value pairs
        '''
        usage = '''usage: %prog [options]

        For more help on valid options try:
           %prog -h '''
        parser = OptionParser(usage=usage)
        parser.set_defaults(log_level=logging.ERROR, validate=False, equip=False, newgraph=True, conf_dir=None, log_type="file")
        parser.add_option("-d", "--debug", action="store_const", const=logging.DEBUG, dest="log_level", help="enable logging at debug level")
        parser.add_option("-i", "--info", action="store_const", const=logging.INFO, dest="log_level", help="enable logging at info level")
        parser.add_option("-w", "--warn", action="store_const", const=logging.WARNING, dest="log_level", help="enable logging at warning level")
        parser.add_option("--valid", action="store_true", dest="validate", help="enable validation of files imported by plugins (details at info or debug logging level) - note plugin must support validation")
        parser.add_option("--oldgraph", action="store_false", dest="newgraph", help="Turn off new graphing approach")
        parser.add_option("--newgraph", action="store_true", dest="newgraph", help="Deprecated Option: Turn on new graphing approach")
        parser.add_option("--confdir", dest="conf_dir", help="Specify the directory where application configuration will be stored.")
        parser.add_option("--logtype", dest="log_type", metavar="TYPE",  type="choice" , choices=["file", "console"], help="Specify where logging should be output to. TYPE is one of 'file' (default), or 'console'.")
        (options, args) = parser.parse_args()
        return options

    def set_logging(self, level, log_type):
        '''Setup rotating log file with customized format'''
        if("console" == log_type):
            handler = logging.StreamHandler(sys.stdout)
        else:
            handler = logging.handlers.RotatingFileHandler(self.environment.log_file, maxBytes=100000, backupCount=5)
        formatter = logging.Formatter('%(asctime)s|%(levelname)s|%(module)s|%(funcName)s|%(message)s')
        handler.setFormatter(formatter)
        logging.getLogger('').addHandler(handler)
        self.set_logging_level(self.startup_options.log_level)

    def set_logging_level(self, level):
        '''Set level of information written to log'''
        logging.debug("Setting logger to level: "+ str(level))
        logging.getLogger('').setLevel(level)

    def quit(self):
        logging.debug('--')
        logging.info("Exit!")
        #self.webservice.stop()
        self.windowmain.gtk_main_quit()
        logging.shutdown()
        sys.exit() # Any nonzero value is considered "abnormal termination" by shells and the like

    def loadPlugins(self):
        logging.debug('>>')
        activeplugins = self.plugins.getActivePlugins()
        if (len(activeplugins)<1):
             logging.info("No active plugins")
        else:
             for plugin in activeplugins:
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.addImportPlugin(txtbutton)
        logging.debug('<<')

    def loadExtensions(self):
        logging.debug('>>')
        activeextensions = self.extension.getActiveExtensions()
        if (len(activeextensions)<1):
             logging.info("No active extensions")
        else:
             for extension in activeextensions:
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.addExtension(txtbutton)
        logging.debug('<<')

    def runPlugin(self,widget,pathPlugin):
        logging.debug('>>')
        self.pluginClass = self.plugins.importClass(pathPlugin)
        pluginFiles = self.pluginClass.run()
        if pluginFiles is not None:
            logging.debug("Plugin returned %d files" % (len(pluginFiles)) )
            #process returned GPX files
            for (pluginFile, sport) in pluginFiles:
                if os.path.isfile(pluginFile):
                    logging.info('File exists. Size: %d. Sport: %s' % (os.path.getsize(pluginFile), sport))
                    if self.record.importFromGPX(pluginFile, sport) is None:
                        logging.error("Error importing file "+pluginFile)
                else:
                    logging.error('File '+pluginFile+' not valid')
        else:
            logging.debug("No files returned from Plugin")
        self.refreshListRecords()
        self.refreshGraphView("day")
        logging.debug('<<')

    def runExtension(self,extension,id):
        logging.debug('>>')
        #print("Extension id: %s" % str(id))
        activity = self.activitypool.get_activity(id)
        txtbutton,pathExtension,type = extension
        self.extensionClass = self.extension.importClass(pathExtension)
        self.extensionClass.run(id, activity)
        #if type == "record":
        #   #Si es record le tenemos que crear el googlemaps, el gpx y darle el id de la bbdd
        #   alert = self.extension.runExtension(pathExtension,id)

        logging.debug('<<')

    def refreshMainSportList(self):
        logging.debug('>>')
        sports = self._sport_service.get_all_sports()
        self.windowmain.updateSportList(sports)
        logging.debug('<<')

    def refreshGraphView(self, view, sport=None):
        logging.debug('>>')
        if self.windowmain is None:
            logging.debug("First call to refreshGraphView")
            logging.debug('<<')
            return
        date_selected = self.date.getDate()
        if view=="record":
             logging.debug('record view')
             if self.windowmain.recordview.get_current_page()==0:
                self.refreshRecordGraphView("info")
             elif self.windowmain.recordview.get_current_page()==1:
                self.refreshRecordGraphView("graphs")
             elif self.windowmain.recordview.get_current_page()==2:
                self.refreshRecordGraphView("map")
             elif self.windowmain.recordview.get_current_page()==3:
                self.refreshRecordGraphView("heartrate")
             elif self.windowmain.recordview.get_current_page()==4:
                self.refreshRecordGraphView("analytics")
        elif view=="day":
             logging.debug('day view')
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordList(date_selected, sport_id)
             self.windowmain.actualize_dayview(record_list=record_list)
             #selected,iter = self.windowmain.recordTreeView.get_selection().get_selected()
        elif view=="week":
             logging.debug('week view')
             date_range = DateRange.for_week_containing(date_selected)
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordPeriod(date_range, sport_id)
             self.windowmain.actualize_weekview(record_list, date_range)
        elif view=="month":
             logging.debug('month view')
             date_range = DateRange.for_month_containing(date_selected)
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordPeriod(date_range, sport_id)
             nameMonth, daysInMonth = self.date.getNameMonth(date_selected)
             self.windowmain.actualize_monthview(record_list, nameMonth)
             self.windowmain.actualize_monthgraph(record_list, daysInMonth)
        elif view=="year":
             logging.debug('year view')
             date_range = DateRange.for_year_containing(date_selected)
             sport = self.windowmain.activeSport
             sport_id = self.record.getSportId(sport)
             record_list = self.record.getrecordPeriod(date_range, sport_id)
             self.windowmain.actualize_yearview(record_list, date_selected.year)
             self.windowmain.actualize_yeargraph(record_list)
        elif view=="listview":
            logging.debug('list view')
            self.refreshListView()
        elif view=="athlete":
            logging.debug('athlete view')
            self.windowmain.on_athleteview_activate()
        elif view=="stats":
            logging.debug('stats view')
            self.windowmain.on_statsview_activate()
        else:
            print "Unknown view %s" % view
        logging.debug('<<')
        
    def refreshRecordGraphView(self, view, id_record=None):
        logging.debug('>>')
        logging.info('Working on '+view+' graph')
        if id_record is not None:
			#Refresh called for a specific record
            #Select correct record in treeview
            model = self.windowmain.recordTreeView.get_model()
            #Loop through all records in treeview looking for the correct one to highlight
            for i,row in enumerate(model):
				if row[0] == id_record:
					self.windowmain.recordTreeView.set_cursor(i)
        else:
            selected,iter = self.windowmain.recordTreeView.get_selection().get_selected()
            if iter:
                id_record = selected.get_value(iter,0)
            else:
                id_record = None
                view="info"
        activity = self.activitypool.get_activity(id_record)
        if view=="info":
            self.windowmain.actualize_recordview(activity)
        if view=="graphs":
            self.windowmain.actualize_recordgraph(activity)
        if view=="map":
             self.refreshMapView()
        if view=="heartrate":
             self.windowmain.actualize_heartrategraph(activity)
             self.windowmain.actualize_hrview(activity)
        if view=="analytics":
             self.windowmain.actualize_analytics(activity)
        logging.debug('<<')

    def refreshMapView(self, full_screen=False):
        logging.debug('>>')
        if self.windowmain is None:
            logging.debug('Called before windowmain initialisation')
            logging.debug('<<')
            return
        selected,iter = self.windowmain.recordTreeView.get_selection().get_selected()
        id_record = selected.get_value(iter,0)
        activity = self.activitypool.get_activity(id_record)
        logging.debug('Trying to show map for record '+str(id_record))
        self.windowmain.actualize_map(activity, full_screen)
        logging.debug('<<')

    def refreshListRecords(self):
        logging.debug('>>')
        #Refresh list view
        #self.refreshListView() # old variant
        self.refreshListView(self.windowmain.listsearch.condition)
        #Refresh list records
        date = self.date.getDate()
        sport = self.windowmain.activeSport
        id_sport = self.record.getSportId(sport)
        record_ids = self.record.getrecordList(date, id_sport)
        self.windowmain.actualize_recordTreeView(record_ids)
        #Mark the monthly calendar to show which days have activity?
        record_list = self.record.getRecordDayList(date, id_sport)
        self.windowmain.actualize_calendar(record_list)
        logging.debug('<<')

    def refreshAthleteView(self):
        logging.debug('>>')
        self.athlete.refresh()
        self.windowmain.actualize_athleteview(self.athlete)
        logging.debug('<<')

    def refreshStatsView(self):
        logging.debug('>>')
        self.stats.refresh()
        self.windowmain.actualize_statsview(self.stats, self.record.getAllRecordList())
        logging.debug('<<')

    def refreshListView(self,condition=None):
        logging.debug('>>')
        record_list = self.record.getRecordListByCondition(condition)
        self.windowmain.actualize_listview(record_list)
        logging.debug('<<')

    def refreshWaypointView(self,default_waypoint=None,redrawmap=1):
        logging.debug('>>')
        waypoint_list = self.waypoint.getAllWaypoints()
        self.windowmain.actualize_waypointview(waypoint_list,default_waypoint,redrawmap)
        logging.debug('<<')

    def editExtensions(self):
        logging.debug('>>')
        before = self.extension.getActiveExtensions()
        self.extension.manageExtensions()
        after = self.extension.getActiveExtensions()
        self.setExtensions(before, after)
        logging.debug('<<')

    def importData(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.importdata.runImportdata()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        self.refreshListRecords()
        self.refreshGraphView(self.windowmain.selected_view)
        logging.debug('<<')

    def editGpsPlugins(self):
        logging.debug('>>')
        activeplugins_before = self.plugins.getActivePlugins()
        self.plugins.managePlugins()
        activeplugins_after = self.plugins.getActivePlugins()
        #Need to check for plugins that have been disabled (were active and now are not)
        self.setMenuPlugins(activeplugins_before, activeplugins_after)
        logging.debug('<<')

    def setMenuPlugins(self, activeplugins_before, activeplugins_after):
        logging.debug('>>')
        #Need to check for plugins that have been disabled (were active and now are not)
        for plugin in activeplugins_before:
            if plugin not in activeplugins_after:
                #disabled plugin -> need to unload plugin
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.removeImportPlugin(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for plugin in activeplugins_after:
            if plugin not in activeplugins_before:
                #new active plugin -> need to load plugin
                txtbutton = self.plugins.loadPlugin(plugin)
                self.windowmain.addImportPlugin(txtbutton)
        logging.debug('<<')

    def setExtensions(self, before, after):
        logging.debug('>>')
        #Need to check for extensions that have been disabled (were active and now are not)
        for extension in before:
            if extension not in after:
                #disabled extension -> need to unload extension
                print "Need to disable extension %s " % extension
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.removeExtension(txtbutton)
        #Need to check for plugins that have been enabled (were not active and now are)
        for extension in after:
            if extension not in before:
                #new active extension -> need to load extension
                logging.debug("Enabling extension %s " % extension)
                txtbutton = self.extension.loadExtension(extension)
                self.windowmain.addExtension(txtbutton)
        logging.debug('<<')

    def newRecord(self,title=None,distance=None,time=None,upositive=None,unegative=None,bpm=None,calories=None,comment=None,view=None):
        logging.debug('>>')
        date = self.date.getDate()
        self.record.newRecord(date, title, distance, time, upositive, unegative, bpm, calories, comment)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def editRecord(self, id_record, view=None):
        logging.debug("Editing record with id: '%s'", id_record)
        self.record.editRecord(id_record)
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeRecord(self, id_record, confirm = False, view=None):
        logging.debug('>>')
        if confirm:
             self.record.removeRecord(id_record)
        else:
             msg = _("Delete this database entry?")
             params = [id_record,True]
             warning = Warning(self.data_path,self.removeRecord,params)
             warning.set_text(msg)
             warning.run()
        self.refreshListRecords()
        if view is not None:
            self.refreshGraphView(view)
        logging.debug('<<')

    def removeWaypoint(self,id_waypoint, confirm = False):
        logging.debug('>>')
        if confirm:
             self.waypoint.removeWaypoint(id_waypoint)
             self.refreshWaypointView()
        else:
             msg = _("Delete this waypoint?")
             params = [id_waypoint,True]
             warning = Warning(self.data_path,self.removeWaypoint,params)
             warning.set_text(msg)
             warning.run()
        logging.debug('<<')

    def updateWaypoint(self,id_waypoint,lat,lon,name,desc,sym):
        logging.debug('>>')
        self.waypoint.updateWaypoint(id_waypoint,lat,lon,name,desc,sym)
        self.refreshWaypointView(id_waypoint)
        logging.debug('<<')

    def exportCsv(self):
        logging.debug('>>')
        from save import Save
        save = Save(self.data_path, self.record)
        save.run()
        logging.debug('<<')

    def editProfile(self):
        logging.debug('>>')
        self.profile.editProfile(self._sport_service)
        self.activitypool.clear_pool()
        self.windowmain.setup()
        logging.debug('<<')
Exemple #19
0
 def setUp(self):
     configuration = config.Configuration(
         'tests/plugins/test_pluginloader.config.json')
     self.plugins = Plugins(configuration)
Exemple #20
0
        credential_key = getpass.getpass('Credential Key:')
    credential_manager = CredentialManager(credentials_file, credential_key)
    config.credential_manager = credential_manager

    ## -- test just resets the db everytime --
    from models import Base
    from db import engine
    if not settings.in_production():
        Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)
    from repos import repotracker
    from plugins import RepoWatcher, Plugins
    from plugins.base import PluginTestError

#-- Load plugins
    loaded_plugins = Plugins(configuration)

    if args.tests:
        print "=======================  Loading plugins ======================="
        plugins = loaded_plugins.enabled_plugins()

        print "=======================  Running Plugin Tests ======================="
        for plugin_area in plugins:
            for plugin in plugins[plugin_area]:
                print "Running test for ", plugin.__module__
                try:
                    plugin.test()
                except PluginTestError, pte:
                    print "Test Failed for ", plugin.__module__
                    print pte.message
                    sys.exit(1)