Mercurial > libervia-backend
diff sat/core/sat_main.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 9446f1ea9eac |
children | 189e38fb11ff |
line wrap: on
line diff
--- a/sat/core/sat_main.py Wed Jun 27 07:51:29 2018 +0200 +++ b/sat/core/sat_main.py Wed Jun 27 20:14:46 2018 +0200 @@ -27,6 +27,7 @@ from sat.core import xmpp from sat.core import exceptions from sat.core.log import getLogger + log = getLogger(__name__) from sat.core.constants import Const as C from sat.memory import memory @@ -43,26 +44,31 @@ import uuid try: - from collections import OrderedDict # only available from python 2.7 + from collections import OrderedDict # only available from python 2.7 except ImportError: from ordereddict import OrderedDict class SAT(service.Service): - def __init__(self): self._cb_map = {} # map from callback_id to callbacks - self._menus = OrderedDict() # dynamic menus. key: callback_id, value: menu data (dictionnary) + self._menus = ( + OrderedDict() + ) # dynamic menus. key: callback_id, value: menu data (dictionnary) self._menus_paths = {} # path to id. key: (menu_type, lower case tuple of path), value: menu id self.initialised = defer.Deferred() self.profiles = {} self.plugins = {} - self.ns_map = {u'x-data': u'jabber:x:data'} # map for short name to whole namespace, - # extended by plugins with registerNamespace + self.ns_map = { + u"x-data": u"jabber:x:data" + } # map for short name to whole namespace, + # extended by plugins with registerNamespace self.memory = memory.Memory(self) - self.trigger = trigger.TriggerManager() # trigger are used to change SàT behaviour + self.trigger = ( + trigger.TriggerManager() + ) # trigger are used to change SàT behaviour - bridge_name = self.memory.getConfig('', 'bridge', 'dbus') + bridge_name = self.memory.getConfig("", "bridge", "dbus") bridge_module = dynamic_import.bridge(bridge_name) if bridge_module is None: @@ -79,28 +85,42 @@ self.bridge.register_method("getFeatures", self.getFeatures) self.bridge.register_method("profileNameGet", self.memory.getProfileName) self.bridge.register_method("profilesListGet", self.memory.getProfilesList) - self.bridge.register_method("getEntityData", lambda jid_, keys, profile: self.memory.getEntityData(jid.JID(jid_), keys, profile)) + self.bridge.register_method( + "getEntityData", + lambda jid_, keys, profile: self.memory.getEntityData( + jid.JID(jid_), keys, profile + ), + ) self.bridge.register_method("getEntitiesData", self.memory._getEntitiesData) self.bridge.register_method("profileCreate", self.memory.createProfile) self.bridge.register_method("asyncDeleteProfile", self.memory.asyncDeleteProfile) self.bridge.register_method("profileStartSession", self.memory.startSession) - self.bridge.register_method("profileIsSessionStarted", self.memory._isSessionStarted) + self.bridge.register_method( + "profileIsSessionStarted", self.memory._isSessionStarted + ) self.bridge.register_method("profileSetDefault", self.memory.profileSetDefault) self.bridge.register_method("connect", self._connect) self.bridge.register_method("disconnect", self.disconnect) self.bridge.register_method("getContacts", self.getContacts) self.bridge.register_method("getContactsFromGroup", self.getContactsFromGroup) self.bridge.register_method("getMainResource", self.memory._getMainResource) - self.bridge.register_method("getPresenceStatuses", self.memory._getPresenceStatuses) + self.bridge.register_method( + "getPresenceStatuses", self.memory._getPresenceStatuses + ) self.bridge.register_method("getWaitingSub", self.memory.getWaitingSub) self.bridge.register_method("messageSend", self._messageSend) self.bridge.register_method("getConfig", self._getConfig) self.bridge.register_method("setParam", self.setParam) self.bridge.register_method("getParamA", self.memory.getStringParamA) self.bridge.register_method("asyncGetParamA", self.memory.asyncGetStringParamA) - self.bridge.register_method("asyncGetParamsValuesFromCategory", self.memory.asyncGetParamsValuesFromCategory) + self.bridge.register_method( + "asyncGetParamsValuesFromCategory", + self.memory.asyncGetParamsValuesFromCategory, + ) self.bridge.register_method("getParamsUI", self.memory.getParamsUI) - self.bridge.register_method("getParamsCategories", self.memory.getParamsCategories) + self.bridge.register_method( + "getParamsCategories", self.memory.getParamsCategories + ) self.bridge.register_method("paramsRegisterApp", self.memory.paramsRegisterApp) self.bridge.register_method("historyGet", self.memory._historyGet) self.bridge.register_method("setPresence", self._setPresence) @@ -135,12 +155,14 @@ def full_version(self): """Return the full version of SàT (with release name and extra data when in development mode)""" version = self.version - if version[-1] == 'D': + if version[-1] == "D": # we are in debug version, we add extra data try: return self._version_cache except AttributeError: - self._version_cache = u"{} « {} » ({})".format(version, C.APP_RELEASE_NAME, utils.getRepositoryData(sat)) + self._version_cache = u"{} « {} » ({})".format( + version, C.APP_RELEASE_NAME, utils.getRepositoryData(sat) + ) return self._version_cache else: return version @@ -158,8 +180,11 @@ ui_contact_list.ContactList(self) ui_profile_manager.ProfileManager(self) except Exception as e: - log.error(_(u"Could not initialize backend: {reason}").format( - reason = str(e).decode('utf-8', 'ignore'))) + log.error( + _(u"Could not initialize backend: {reason}").format( + reason=str(e).decode("utf-8", "ignore") + ) + ) sys.exit(1) self.initialised.callback(None) log.info(_(u"Backend is ready")) @@ -180,43 +205,69 @@ # just use a client, and plugin blacklisting should be possible in sat.conf plugins_path = os.path.dirname(sat.plugins.__file__) plugin_glob = "plugin*." + C.PLUGIN_EXT - plug_lst = [os.path.splitext(plugin)[0] for plugin in map(os.path.basename, glob(os.path.join(plugins_path, plugin_glob)))] + plug_lst = [ + os.path.splitext(plugin)[0] + for plugin in map( + os.path.basename, glob(os.path.join(plugins_path, plugin_glob)) + ) + ] plugins_to_import = {} # plugins we still have to import for plug in plug_lst: - plugin_path = 'sat.plugins.' + plug + plugin_path = "sat.plugins." + plug try: __import__(plugin_path) except exceptions.MissingModule as e: self._unimport_plugin(plugin_path) - log.warning(u"Can't import plugin [{path}] because of an unavailale third party module:\n{msg}".format( - path=plugin_path, msg=e)) + log.warning( + u"Can't import plugin [{path}] because of an unavailale third party module:\n{msg}".format( + path=plugin_path, msg=e + ) + ) continue except exceptions.CancelError as e: - log.info(u"Plugin [{path}] cancelled its own import: {msg}".format(path=plugin_path, msg=e)) + log.info( + u"Plugin [{path}] cancelled its own import: {msg}".format( + path=plugin_path, msg=e + ) + ) self._unimport_plugin(plugin_path) continue except Exception as e: import traceback - log.error(_(u"Can't import plugin [{path}]:\n{error}").format(path=plugin_path, error=traceback.format_exc())) + + log.error( + _(u"Can't import plugin [{path}]:\n{error}").format( + path=plugin_path, error=traceback.format_exc() + ) + ) self._unimport_plugin(plugin_path) continue mod = sys.modules[plugin_path] plugin_info = mod.PLUGIN_INFO - import_name = plugin_info['import_name'] + import_name = plugin_info["import_name"] - plugin_modes = plugin_info[u'modes'] = set(plugin_info.setdefault(u"modes", C.PLUG_MODE_DEFAULT)) + plugin_modes = plugin_info[u"modes"] = set( + plugin_info.setdefault(u"modes", C.PLUG_MODE_DEFAULT) + ) # if the plugin is an entry point, it must work in component mode - if plugin_info[u'type'] == C.PLUG_TYPE_ENTRY_POINT: + if plugin_info[u"type"] == C.PLUG_TYPE_ENTRY_POINT: # if plugin is an entrypoint, we cache it if C.PLUG_MODE_COMPONENT not in plugin_modes: - log.error(_(u"{type} type must be used with {mode} mode, ignoring plugin").format( - type = C.PLUG_TYPE_ENTRY_POINT, mode = C.PLUG_MODE_COMPONENT)) + log.error( + _( + u"{type} type must be used with {mode} mode, ignoring plugin" + ).format(type=C.PLUG_TYPE_ENTRY_POINT, mode=C.PLUG_MODE_COMPONENT) + ) self._unimport_plugin(plugin_path) continue if import_name in plugins_to_import: - log.error(_(u"Name conflict for import name [{import_name}], can't import plugin [{name}]").format(**plugin_info)) + log.error( + _( + u"Name conflict for import name [{import_name}], can't import plugin [{name}]" + ).format(**plugin_info) + ) continue plugins_to_import[import_name] = (plugin_path, mod, plugin_info) while True: @@ -227,7 +278,9 @@ if not plugins_to_import: break - def _import_plugins_from_dict(self, plugins_to_import, import_name=None, optional=False): + def _import_plugins_from_dict( + self, plugins_to_import, import_name=None, optional=False + ): """Recursively import and their dependencies in the right order @param plugins_to_import(dict): key=import_name and values=(plugin_path, module, plugin_info) @@ -235,14 +288,16 @@ @param optional(bool): if False and plugin is not found, an ImportError exception is raised """ if import_name in self.plugins: - log.debug(u'Plugin {} already imported, passing'.format(import_name)) + log.debug(u"Plugin {} already imported, passing".format(import_name)) return if not import_name: import_name, (plugin_path, mod, plugin_info) = plugins_to_import.popitem() else: if not import_name in plugins_to_import: if optional: - log.warning(_(u"Recommended plugin not found: {}").format(import_name)) + log.warning( + _(u"Recommended plugin not found: {}").format(import_name) + ) return msg = u"Dependency not found: {}".format(import_name) log.error(msg) @@ -252,21 +307,33 @@ recommendations = plugin_info.setdefault("recommendations", []) for to_import in dependencies + recommendations: if to_import not in self.plugins: - log.debug(u'Recursively import dependency of [%s]: [%s]' % (import_name, to_import)) + log.debug( + u"Recursively import dependency of [%s]: [%s]" + % (import_name, to_import) + ) try: - self._import_plugins_from_dict(plugins_to_import, to_import, to_import not in dependencies) + self._import_plugins_from_dict( + plugins_to_import, to_import, to_import not in dependencies + ) except ImportError as e: - log.warning(_(u"Can't import plugin {name}: {error}").format(name=plugin_info['name'], error=e)) + log.warning( + _(u"Can't import plugin {name}: {error}").format( + name=plugin_info["name"], error=e + ) + ) if optional: return raise e - log.info("importing plugin: {}".format(plugin_info['name'])) + log.info("importing plugin: {}".format(plugin_info["name"])) # we instanciate the plugin here try: - self.plugins[import_name] = getattr(mod, plugin_info['main'])(self) + self.plugins[import_name] = getattr(mod, plugin_info["main"])(self) except Exception as e: - log.warning(u'Error while loading plugin "{name}", ignoring it: {error}' - .format(name=plugin_info['name'], error=e)) + log.warning( + u'Error while loading plugin "{name}", ignoring it: {error}'.format( + name=plugin_info["name"], error=e + ) + ) if optional: return raise ImportError(u"Error during initiation") @@ -276,7 +343,7 @@ self.plugins[import_name].is_handler = False # we keep metadata as a Class attribute self.plugins[import_name]._info = plugin_info - #TODO: test xmppclient presence and register handler parent + # TODO: test xmppclient presence and register handler parent def pluginsUnload(self): """Call unload method on every loaded plugin, if exists @@ -296,11 +363,11 @@ defers_list.append(defer.maybeDeferred(unload)) return defers_list - def _connect(self, profile_key, password='', options=None): + def _connect(self, profile_key, password="", options=None): profile = self.memory.getProfileName(profile_key) return self.connect(profile, password, options) - def connect(self, profile, password='', options=None, max_retries=C.XMPP_MAX_RETRIES): + def connect(self, profile, password="", options=None, max_retries=C.XMPP_MAX_RETRIES): """Connect a profile (i.e. connect client.component to XMPP server) Retrieve the individual parameters, authenticate the profile @@ -316,7 +383,8 @@ @raise exceptions.PasswordError: Profile password is wrong """ if options is None: - options={} + options = {} + def connectProfile(dummy=None): if self.isConnected(profile): log.info(_("already connected !")) @@ -375,15 +443,19 @@ features.append(features_d) d_list = defer.DeferredList(features) + def buildFeatures(result, import_names): assert len(result) == len(import_names) ret = {} - for name, (success, data) in zip (import_names, result): + for name, (success, data) in zip(import_names, result): if success: ret[name] = data else: - log.warning(u"Error while getting features for {name}: {failure}".format( - name=name, failure=data)) + log.warning( + u"Error while getting features for {name}: {failure}".format( + name=name, failure=data + ) + ) ret[name] = {} return ret @@ -392,6 +464,7 @@ def getContacts(self, profile_key): client = self.getClient(profile_key) + def got_roster(dummy): ret = [] for item in client.roster.getItems(): # we get all items for client's roster @@ -467,14 +540,14 @@ @return: list of clients """ if not profile_key: - raise exceptions.DataError(_(u'profile_key must not be empty')) + raise exceptions.DataError(_(u"profile_key must not be empty")) try: profile = self.memory.getProfileName(profile_key, True) except exceptions.ProfileUnknownError: return [] if profile == C.PROF_KEY_ALL: return self.profiles.values() - elif profile[0] == '@': # only profile keys can start with "@" + elif profile[0] == "@": # only profile keys can start with "@" raise exceptions.ProfileKeyUnknown return [self.profiles[profile]] @@ -485,7 +558,7 @@ @param name: name of the option @return: unicode representation of the option """ - return unicode(self.memory.getConfig(section, name, '')) + return unicode(self.memory.getConfig(section, name, "")) def logErrback(self, failure_): """generic errback logging @@ -495,12 +568,12 @@ log.error(_(u"Unexpected error: {}".format(failure_))) return failure_ - # namespaces + # namespaces def registerNamespace(self, short_name, namespace): """associate a namespace to a short name""" if short_name in self.ns_map: - raise exceptions.ConflictError(u'this short name is already used') + raise exceptions.ConflictError(u"this short name is already used") self.ns_map[short_name] = namespace def getNamespaces(self): @@ -509,10 +582,7 @@ def getSessionInfos(self, profile_key): """compile interesting data on current profile session""" client = self.getClient(profile_key) - data = { - "jid": client.jid.full(), - "started": unicode(int(client.started)), - } + data = {"jid": client.jid.full(), "started": unicode(int(client.started))} return defer.succeed(data) # local dirs @@ -531,11 +601,11 @@ """ # FIXME: component and profile are parsed with **kwargs because of python 2 limitations # once moved to python 3, this can be fixed - component = kwargs.pop('component', False) - profile = kwargs.pop('profile', True) + component = kwargs.pop("component", False) + profile = kwargs.pop("profile", True) assert not kwargs - path_elts = [self.memory.getConfig('', 'local_dir')] + path_elts = [self.memory.getConfig("", "local_dir")] if component: path_elts.append(C.COMPONENTS_DIR) path_elts.append(regex.pathEscape(dir_name)) @@ -561,7 +631,7 @@ """ profile = self.memory.getProfileName(profile_key) if not profile: - log.error(_('asking connection status for a non-existant profile')) + log.error(_("asking connection status for a non-existant profile")) raise exceptions.ProfileUnknownError(profile_key) if profile not in self.profiles: return False @@ -569,28 +639,47 @@ ## XMPP methods ## - def _messageSend(self, to_jid_s, message, subject=None, mess_type='auto', extra=None, profile_key=C.PROF_KEY_NONE): + def _messageSend( + self, + to_jid_s, + message, + subject=None, + mess_type="auto", + extra=None, + profile_key=C.PROF_KEY_NONE, + ): client = self.getClient(profile_key) to_jid = jid.JID(to_jid_s) - #XXX: we need to use the dictionary comprehension because D-Bus return its own types, and pickle can't manage them. TODO: Need to find a better way - return client.sendMessage(to_jid, message, subject, mess_type, {unicode(key): unicode(value) for key, value in extra.items()}) + # XXX: we need to use the dictionary comprehension because D-Bus return its own types, and pickle can't manage them. TODO: Need to find a better way + return client.sendMessage( + to_jid, + message, + subject, + mess_type, + {unicode(key): unicode(value) for key, value in extra.items()}, + ) def _setPresence(self, to="", show="", statuses=None, profile_key=C.PROF_KEY_NONE): return self.setPresence(jid.JID(to) if to else None, show, statuses, profile_key) - def setPresence(self, to_jid=None, show="", statuses=None, profile_key=C.PROF_KEY_NONE): + def setPresence( + self, to_jid=None, show="", statuses=None, profile_key=C.PROF_KEY_NONE + ): """Send our presence information""" if statuses is None: statuses = {} profile = self.memory.getProfileName(profile_key) assert profile - priority = int(self.memory.getParamA("Priority", "Connection", profile_key=profile)) + priority = int( + self.memory.getParamA("Priority", "Connection", profile_key=profile) + ) self.profiles[profile].presence.available(to_jid, show, statuses, priority) - #XXX: FIXME: temporary fix to work around openfire 3.7.0 bug (presence is not broadcasted to generating resource) - if '' in statuses: - statuses[C.PRESENCE_STATUSES_DEFAULT] = statuses.pop('') - self.bridge.presenceUpdate(self.profiles[profile].jid.full(), show, - int(priority), statuses, profile) + # XXX: FIXME: temporary fix to work around openfire 3.7.0 bug (presence is not broadcasted to generating resource) + if "" in statuses: + statuses[C.PRESENCE_STATUSES_DEFAULT] = statuses.pop("") + self.bridge.presenceUpdate( + self.profiles[profile].jid.full(), show, int(priority), statuses, profile + ) def subscription(self, subs_type, raw_jid, profile_key): """Called to manage subscription @@ -600,7 +689,10 @@ profile = self.memory.getProfileName(profile_key) assert profile to_jid = jid.JID(raw_jid) - log.debug(_(u'subsciption request [%(subs_type)s] for %(jid)s') % {'subs_type': subs_type, 'jid': to_jid.full()}) + log.debug( + _(u"subsciption request [%(subs_type)s] for %(jid)s") + % {"subs_type": subs_type, "jid": to_jid.full()} + ) if subs_type == "subscribe": self.profiles[profile].presence.subscribe(to_jid) elif subs_type == "subscribed": @@ -671,12 +763,41 @@ def findFeaturesSet(self, *args, **kwargs): return self.memory.disco.findFeaturesSet(*args, **kwargs) - def _findByFeatures(self, namespaces, identities, bare_jids, service, roster, own_jid, local_device, profile_key): + def _findByFeatures( + self, + namespaces, + identities, + bare_jids, + service, + roster, + own_jid, + local_device, + profile_key, + ): client = self.getClient(profile_key) - return self.findByFeatures(client, namespaces, identities, bare_jids, service, roster, own_jid, local_device) + return self.findByFeatures( + client, + namespaces, + identities, + bare_jids, + service, + roster, + own_jid, + local_device, + ) @defer.inlineCallbacks - def findByFeatures(self, client, namespaces, identities=None, bare_jids=False, service=True, roster=True, own_jid=True, local_device=False): + def findByFeatures( + self, + client, + namespaces, + identities=None, + bare_jids=False, + service=True, + roster=True, + own_jid=True, + local_device=False, + ): """retrieve all services or contacts managing a set a features @param namespaces(list[unicode]): features which must be handled @@ -697,7 +818,9 @@ if not identities: identities = None if not namespaces and not identities: - raise exceptions.DataError("at least one namespace or one identity must be set") + raise exceptions.DataError( + "at least one namespace or one identity must be set" + ) found_service = {} found_own = {} found_roster = {} @@ -705,9 +828,14 @@ services_jids = yield self.findFeaturesSet(client, namespaces) for service_jid in services_jids: infos = yield self.getDiscoInfos(client, service_jid) - if identities is not None and not set(infos.identities.keys()).issuperset(identities): + if identities is not None and not set(infos.identities.keys()).issuperset( + identities + ): continue - found_identities = [(cat, type_, name or u'') for (cat, type_), name in infos.identities.iteritems()] + found_identities = [ + (cat, type_, name or u"") + for (cat, type_), name in infos.identities.iteritems() + ] found_service[service_jid.full()] = found_identities jids = [] @@ -716,8 +844,10 @@ if own_jid: jids.append(client.jid.userhostJID()) - for found, jids in ((found_own, [client.jid.userhostJID()]), - (found_roster, client.roster.getJids())): + for found, jids in ( + (found_own, [client.jid.userhostJID()]), + (found_roster, client.roster.getJids()), + ): for jid_ in jids: if jid_.resource: if bare_jids: @@ -737,9 +867,14 @@ continue infos = yield self.getDiscoInfos(client, full_jid) if infos.features.issuperset(namespaces): - if identities is not None and not set(infos.identities.keys()).issuperset(identities): + if identities is not None and not set( + infos.identities.keys() + ).issuperset(identities): continue - found_identities = [(cat, type_, name or u'') for (cat, type_), name in infos.identities.iteritems()] + found_identities = [ + (cat, type_, name or u"") + for (cat, type_), name in infos.identities.iteritems() + ] found[full_jid.full()] = found_identities defer.returnValue((found_service, found_own, found_roster)) @@ -750,7 +885,13 @@ log.debug(u"Killing action {} for timeout".format(keep_id)) client.actions[keep_id] - def actionNew(self, action_data, security_limit=C.NO_SECURITY_LIMIT, keep_id=None, profile=C.PROF_KEY_NONE): + def actionNew( + self, + action_data, + security_limit=C.NO_SECURITY_LIMIT, + keep_id=None, + profile=C.PROF_KEY_NONE, + ): """Shortcut to bridge.actionNew which generate and id and keep for retrieval @param action_data(dict): action data (see bridge documentation) @@ -763,7 +904,7 @@ id_ = unicode(uuid.uuid4()) if keep_id is not None: client = self.getClient(profile) - action_timer = reactor.callLater(60*30, self._killAction, keep_id, client) + action_timer = reactor.callLater(60 * 30, self._killAction, keep_id, client) client.actions[keep_id] = (action_data, id_, security_limit, action_timer) self.bridge.actionNew(action_data, id_, security_limit, profile) @@ -776,7 +917,9 @@ client = self.getClient(profile) return [action_tuple[:-1] for action_tuple in client.actions.itervalues()] - def registerProgressCb(self, progress_id, callback, metadata=None, profile=C.PROF_KEY_NONE): + def registerProgressCb( + self, progress_id, callback, metadata=None, profile=C.PROF_KEY_NONE + ): """Register a callback called when progress is requested for id""" if metadata is None: metadata = {} @@ -795,7 +938,7 @@ def _progressGet(self, progress_id, profile): data = self.progressGet(progress_id, profile) - return {k: unicode(v) for k,v in data.iteritems()} + return {k: unicode(v) for k, v in data.iteritems()} def progressGet(self, progress_id, profile): """Return a dict with progress information @@ -837,7 +980,10 @@ profile = client.profile progress_dict = {} progress_all[profile] = progress_dict - for progress_id, (dummy, progress_metadata) in client._progress_cb.iteritems(): + for ( + progress_id, + (dummy, progress_metadata), + ) in client._progress_cb.iteritems(): progress_dict[progress_id] = progress_metadata return progress_all @@ -870,7 +1016,7 @@ one_shot(bool): True to delete callback once it have been called @return: id of the registered callback """ - callback_id = kwargs.pop('force_id', None) + callback_id = kwargs.pop("force_id", None) if callback_id is None: callback_id = str(uuid.uuid4()) else: @@ -878,12 +1024,14 @@ raise exceptions.ConflictError(_(u"id already registered")) self._cb_map[callback_id] = (callback, args, kwargs) - if "one_shot" in kwargs: # One Shot callback are removed after 30 min + if "one_shot" in kwargs: # One Shot callback are removed after 30 min + def purgeCallback(): try: self.removeCallback(callback_id) except KeyError: pass + reactor.callLater(1800, purgeCallback) return callback_id @@ -906,14 +1054,16 @@ - C.BOOL_TRUE - C.BOOL_FALSE """ - # FIXME: security limit need to be checked here + # FIXME: security limit need to be checked here try: client = self.getClient(profile_key) except exceptions.NotFound: # client is not available yet profile = self.memory.getProfileName(profile_key) if not profile: - raise exceptions.ProfileUnknownError(_(u'trying to launch action with a non-existant profile')) + raise exceptions.ProfileUnknownError( + _(u"trying to launch action with a non-existant profile") + ) else: profile = client.profile # we check if the action is kept, and remove it @@ -922,7 +1072,7 @@ except KeyError: pass else: - action_tuple[-1].cancel() # the last item is the action timer + action_tuple[-1].cancel() # the last item is the action timer del client.actions[callback_id] try: @@ -933,17 +1083,20 @@ if kwargs.get("with_data", False): if data is None: raise exceptions.DataError("Required data for this callback is missing") - args,kwargs=list(args)[:],kwargs.copy() # we don't want to modify the original (kw)args + args, kwargs = ( + list(args)[:], + kwargs.copy(), + ) # we don't want to modify the original (kw)args args.insert(0, data) kwargs["profile"] = profile del kwargs["with_data"] - if kwargs.pop('one_shot', False): + if kwargs.pop("one_shot", False): self.removeCallback(callback_id) return defer.maybeDeferred(callback, *args, **kwargs) - #Menus management + # Menus management def _getMenuCanonicalPath(self, path): """give canonical form of path @@ -954,7 +1107,14 @@ """ return tuple((p.lower().strip() for p in path)) - def importMenu(self, path, callback, security_limit=C.NO_SECURITY_LIMIT, help_string="", type_=C.MENU_GLOBAL): + def importMenu( + self, + path, + callback, + security_limit=C.NO_SECURITY_LIMIT, + help_string="", + type_=C.MENU_GLOBAL, + ): """register a new menu for frontends @param path(iterable[unicode]): path to go to the menu (category/subcategory/.../item) (e.g.: ("File", "Open")) @@ -989,34 +1149,40 @@ callback, args, kwargs = self._cb_map[callback_id] except KeyError: raise exceptions.DataError("Unknown callback id") - kwargs["with_data"] = True # we have to be sure that we use extra data + kwargs["with_data"] = True # we have to be sure that we use extra data else: raise exceptions.DataError("Unknown callback type") for menu_data in self._menus.itervalues(): - if menu_data['path'] == path and menu_data['type'] == type_: - raise exceptions.ConflictError(_("A menu with the same path and type already exists")) + if menu_data["path"] == path and menu_data["type"] == type_: + raise exceptions.ConflictError( + _("A menu with the same path and type already exists") + ) path_canonical = self._getMenuCanonicalPath(path) menu_key = (type_, path_canonical) if menu_key in self._menus_paths: - raise exceptions.ConflictError(u"this menu path is already used: {path} ({menu_key})".format( - path=path_canonical, menu_key=menu_key)) + raise exceptions.ConflictError( + u"this menu path is already used: {path} ({menu_key})".format( + path=path_canonical, menu_key=menu_key + ) + ) - menu_data = {'path': tuple(path), - 'path_canonical': path_canonical, - 'security_limit': security_limit, - 'help_string': help_string, - 'type': type_ - } + menu_data = { + "path": tuple(path), + "path_canonical": path_canonical, + "security_limit": security_limit, + "help_string": help_string, + "type": type_, + } self._menus[callback_id] = menu_data self._menus_paths[menu_key] = callback_id return callback_id - def getMenus(self, language='', security_limit=C.NO_SECURITY_LIMIT): + def getMenus(self, language="", security_limit=C.NO_SECURITY_LIMIT): """Return all menus registered @param language: language used for translation, or empty string for default @@ -1032,24 +1198,36 @@ """ ret = [] for menu_id, menu_data in self._menus.iteritems(): - type_ = menu_data['type'] - path = menu_data['path'] - menu_security_limit = menu_data['security_limit'] - if security_limit!=C.NO_SECURITY_LIMIT and (menu_security_limit==C.NO_SECURITY_LIMIT or menu_security_limit>security_limit): + type_ = menu_data["type"] + path = menu_data["path"] + menu_security_limit = menu_data["security_limit"] + if security_limit != C.NO_SECURITY_LIMIT and ( + menu_security_limit == C.NO_SECURITY_LIMIT + or menu_security_limit > security_limit + ): continue languageSwitch(language) path_i18n = [_(elt) for elt in path] languageSwitch() - extra = {} # TODO: manage extra data like icon + extra = {} # TODO: manage extra data like icon ret.append((menu_id, type_, path, path_i18n, extra)) return ret - def _launchMenu(self, menu_type, path, data=None, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): + def _launchMenu( + self, + menu_type, + path, + data=None, + security_limit=C.NO_SECURITY_LIMIT, + profile_key=C.PROF_KEY_NONE, + ): client = self.getClient(profile_key) return self.launchMenu(client, menu_type, path, data, security_limit) - def launchMenu(self, client, menu_type, path, data=None, security_limit=C.NO_SECURITY_LIMIT): + def launchMenu( + self, client, menu_type, path, data=None, security_limit=C.NO_SECURITY_LIMIT + ): """launch action a menu action @param menu_type(unicode): type of menu to launch @@ -1064,11 +1242,14 @@ try: callback_id = self._menus_paths[menu_key] except KeyError: - raise exceptions.NotFound(u"Can't find menu {path} ({menu_type})".format( - path=canonical_path, menu_type=menu_type)) + raise exceptions.NotFound( + u"Can't find menu {path} ({menu_type})".format( + path=canonical_path, menu_type=menu_type + ) + ) return self.launchCallback(callback_id, data, client.profile) - def getMenuHelp(self, menu_id, language=''): + def getMenuHelp(self, menu_id, language=""): """return the help string of the menu @param menu_id: id of the menu (same as callback_id) @@ -1081,6 +1262,6 @@ except KeyError: raise exceptions.DataError("Trying to access an unknown menu") languageSwitch(language) - help_string = _(menu_data['help_string']) + help_string = _(menu_data["help_string"]) languageSwitch() return help_string