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