diff sat_frontends/quick_frontend/quick_app.py @ 3028:ab2696e34d29

Python 3 port: /!\ this is a huge commit /!\ starting from this commit, SàT is needs Python 3.6+ /!\ SàT maybe be instable or some feature may not work anymore, this will improve with time This patch port backend, bridge and frontends to Python 3. Roughly this has been done this way: - 2to3 tools has been applied (with python 3.7) - all references to python2 have been replaced with python3 (notably shebangs) - fixed files not handled by 2to3 (notably the shell script) - several manual fixes - fixed issues reported by Python 3 that where not handled in Python 2 - replaced "async" with "async_" when needed (it's a reserved word from Python 3.7) - replaced zope's "implements" with @implementer decorator - temporary hack to handle data pickled in database, as str or bytes may be returned, to be checked later - fixed hash comparison for password - removed some code which is not needed anymore with Python 3 - deactivated some code which needs to be checked (notably certificate validation) - tested with jp, fixed reported issues until some basic commands worked - ported Primitivus (after porting dependencies like urwid satext) - more manual fixes
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:08:41 +0200
parents e7cbe662838b
children f8e3789912d0
line wrap: on
line diff
--- a/sat_frontends/quick_frontend/quick_app.py	Wed Jul 31 11:31:22 2019 +0200
+++ b/sat_frontends/quick_frontend/quick_app.py	Tue Aug 13 19:08:41 2019 +0200
@@ -40,12 +40,12 @@
 
 try:
     # FIXME: to be removed when an acceptable solution is here
-    unicode("")  # XXX: unicode doesn't exist in pyjamas
+    str("")  # XXX: unicode doesn't exist in pyjamas
 except (
     TypeError,
     AttributeError,
 ):  # Error raised is not the same depending on pyjsbuild options
-    unicode = str
+    str = str
 
 
 class ProfileManager(object):
@@ -139,7 +139,7 @@
         )
 
     def _plug_profile_getFeaturesEb(self, failure):
-        log.error(u"Couldn't get features: {}".format(failure))
+        log.error("Couldn't get features: {}".format(failure))
         self._plug_profile_getFeaturesCb({})
 
     def _plug_profile_getFeaturesCb(self, features):
@@ -154,14 +154,14 @@
         self._plug_profile_gotCachedValues({})
 
     def _plug_profile_failedCachedValues(self, failure):
-        log.error(u"Couldn't get cached values: {}".format(failure))
+        log.error("Couldn't get cached values: {}".format(failure))
         self._plug_profile_gotCachedValues({})
 
     def _plug_profile_gotCachedValues(self, cached_values):
         contact_list = self.host.contact_lists[self.profile]
         # add the contact list and its listener
-        for entity_s, data in cached_values.iteritems():
-            for key, value in data.iteritems():
+        for entity_s, data in cached_values.items():
+            for key, value in data.items():
                 self.host.entityDataUpdatedHandler(entity_s, key, value, self.profile)
 
         if not self.connected:
@@ -203,7 +203,7 @@
 
         for contact in presences:
             for res in presences[contact]:
-                jabber_id = (u"%s/%s" % (jid.JID(contact).bare, res)) if res else contact
+                jabber_id = ("%s/%s" % (jid.JID(contact).bare, res)) if res else contact
                 show = presences[contact][res][0]
                 priority = presences[contact][res][1]
                 statuses = presences[contact][res][2]
@@ -216,7 +216,7 @@
                 self.profile,
                 callback=lambda data, contact=contact: gotEntityData(data, contact),
                 errback=lambda failure, contact=contact: log.debug(
-                    u"No cache data for {}".format(contact)
+                    "No cache data for {}".format(contact)
                 ),
             )
 
@@ -238,7 +238,7 @@
         return profile in self._profiles
 
     def __iter__(self):
-        return self._profiles.iterkeys()
+        return iter(self._profiles.keys())
 
     def __getitem__(self, profile):
         return self._profiles[profile]
@@ -246,11 +246,11 @@
     def __len__(self):
         return len(self._profiles)
 
-    def iteritems(self):
-        return self._profiles.iteritems()
+    def items(self):
+        return self._profiles.items()
 
-    def itervalues(self):
-        return self._profiles.itervalues()
+    def values(self):
+        return self._profiles.values()
 
     def plug(self, profile):
         if profile in self._profiles:
@@ -271,7 +271,7 @@
         del self._profiles[profile]
 
     def chooseOneProfile(self):
-        return self._profiles.keys()[0]
+        return list(self._profiles.keys())[0]
 
 
 class QuickApp(object):
@@ -350,13 +350,13 @@
         self.ns_map = ns_map
 
     def _namespacesGetEb(self, failure_):
-        log.error(_(u"Can't get namespaces map: {msg}").format(msg=failure_))
+        log.error(_("Can't get namespaces map: {msg}").format(msg=failure_))
 
     def _encryptionPluginsGetCb(self, plugins):
         self.encryption_plugins = plugins
 
     def _encryptionPluginsGetEb(self, failure_):
-        log.warning(_(u"Can't retrieve encryption plugins: {msg}").format(msg=failure_))
+        log.warning(_("Can't retrieve encryption plugins: {msg}").format(msg=failure_))
 
     def onBridgeConnected(self):
         self.bridge.namespacesGet(
@@ -402,13 +402,13 @@
 
     def _bridgeEb(self, failure):
         if isinstance(failure, exceptions.BridgeExceptionNoService):
-            print(_(u"Can't connect to SàT backend, are you sure it's launched ?"))
+            print((_("Can't connect to SàT backend, are you sure it's launched ?")))
             sys.exit(1)
         elif isinstance(failure, exceptions.BridgeInitError):
-            print(_(u"Can't init bridge"))
+            print((_("Can't init bridge")))
             sys.exit(1)
         else:
-            print(_(u"Error while initialising bridge: {}".format(failure)))
+            print((_("Error while initialising bridge: {}".format(failure))))
 
     @property
     def current_profile(self):
@@ -459,10 +459,10 @@
             or if connection has been lost and a reconnection is needed
         """
         if state:
-            log.debug(u"we are synchronised with server")
+            log.debug("we are synchronised with server")
             if self.AUTO_RESYNC:
                 # we are resynchronising all widgets
-                log.debug(u"doing a full widgets resynchronisation")
+                log.debug("doing a full widgets resynchronisation")
                 for w in self.widgets:
                     try:
                         resync = w.resync
@@ -474,7 +474,7 @@
 
             self._sync = state
         else:
-            log.debug(u"we have lost synchronisation with server")
+            log.debug("we have lost synchronisation with server")
             self._sync = state
             # we've lost synchronisation, all widgets must be notified
             # note: this is always called independently of AUTO_RESYNC
@@ -496,7 +496,7 @@
         @param with_profile (boolean): True if the signal concerns a specific profile,
             in that case the profile name has to be passed by the caller
         """
-        log.debug(u"registering signal {name}".format(name=function_name))
+        log.debug("registering signal {name}".format(name=function_name))
         if handler is None:
             handler = getattr(self, "{}{}".format(function_name, "Handler"))
         if not with_profile:
@@ -582,7 +582,7 @@
             pass
         else:
             profile = kwargs.get("profile")
-            for listener, profiles_filter in listeners.iteritems():
+            for listener, profiles_filter in listeners.items():
                 if profile is None or not profiles_filter or profile in profiles_filter:
                     listener(*args, **kwargs)
 
@@ -617,7 +617,7 @@
         cached_signals = self.signals_cache.pop(profile, [])
         for function_name, handler, args, kwargs in cached_signals:
             log.debug(
-                u"Calling cached signal [%s] with args %s and kwargs %s"
+                "Calling cached signal [%s] with args %s and kwargs %s"
                 % (function_name, args, kwargs)
             )
             handler(*args, **kwargs)
@@ -632,7 +632,7 @@
         if not errback:
 
             def errback(failure):
-                log.error(_(u"Can't connect profile [%s]") % failure)
+                log.error(_("Can't connect profile [%s]") % failure)
                 try:
                     module = failure.module
                 except AttributeError:
@@ -790,8 +790,8 @@
             widget.onMessageState(uid, status, profile)
 
     def messageSend(self, to_jid, message, subject=None, mess_type="auto", extra=None, callback=None, errback=None, profile_key=C.PROF_KEY_NONE):
-        if not subject and not extra and (not message or message == {u'': u''}):
-            log.debug(u"Not sending empty message")
+        if not subject and not extra and (not message or message == {'': ''}):
+            log.debug("Not sending empty message")
             return
 
         if subject is None:
@@ -812,7 +812,7 @@
             return
 
         self.bridge.messageSend(
-            unicode(to_jid),
+            str(to_jid),
             message,
             subject,
             mess_type,
@@ -857,8 +857,8 @@
     def mucRoomJoinedHandler(self, room_jid_s, occupants, user_nick, subject, profile):
         """Called when a MUC room is joined"""
         log.debug(
-            u"Room [{room_jid}] joined by {profile}, users presents:{users}".format(
-                room_jid=room_jid_s, profile=profile, users=occupants.keys()
+            "Room [{room_jid}] joined by {profile}, users presents:{users}".format(
+                room_jid=room_jid_s, profile=profile, users=list(occupants.keys())
             )
         )
         room_jid = jid.JID(room_jid_s)
@@ -876,7 +876,7 @@
     def mucRoomLeftHandler(self, room_jid_s, profile):
         """Called when a MUC room is left"""
         log.debug(
-            u"Room [%(room_jid)s] left by %(profile)s"
+            "Room [%(room_jid)s] left by %(profile)s"
             % {"room_jid": room_jid_s, "profile": profile}
         )
         room_jid = jid.JID(room_jid_s)
@@ -893,7 +893,7 @@
         )
         chat_widget.changeUserNick(old_nick, new_nick)
         log.debug(
-            u"user [%(old_nick)s] is now known as [%(new_nick)s] in room [%(room_jid)s]"
+            "user [%(old_nick)s] is now known as [%(new_nick)s] in room [%(room_jid)s]"
             % {"old_nick": old_nick, "new_nick": new_nick, "room_jid": room_jid}
         )
 
@@ -905,7 +905,7 @@
         )
         chat_widget.setSubject(subject)
         log.debug(
-            u"new subject for room [%(room_jid)s]: %(subject)s"
+            "new subject for room [%(room_jid)s]: %(subject)s"
             % {"room_jid": room_jid, "subject": subject}
         )
 
@@ -974,7 +974,7 @@
         main_notif_dict = self.profiles[profile].notifications
 
         if entity is C.ENTITY_ALL:
-            selected_notifs = main_notif_dict.itervalues()
+            selected_notifs = iter(main_notif_dict.values())
             exact_jid = False
         else:
             if entity is None:
@@ -989,7 +989,7 @@
         for notifs_from_select in selected_notifs:
 
             if type_ is None:
-                type_notifs = notifs_from_select.itervalues()
+                type_notifs = iter(notifs_from_select.values())
             else:
                 type_notifs = (notifs_from_select.get(type_, []),)
 
@@ -1080,10 +1080,10 @@
         callbacks.append((callback, errback))
 
     def progressStartedHandler(self, pid, metadata, profile):
-        log.info(u"Progress {} started".format(pid))
+        log.info("Progress {} started".format(pid))
 
     def progressFinishedHandler(self, pid, metadata, profile):
-        log.info(u"Progress {} finished".format(pid))
+        log.info("Progress {} finished".format(pid))
         try:
             callbacks = self._progress_ids.pop(pid)
         except KeyError:
@@ -1095,7 +1095,7 @@
         self.callListeners("progressFinished", pid, metadata, profile=profile)
 
     def progressErrorHandler(self, pid, err_msg, profile):
-        log.warning(u"Progress {pid} error: {err_msg}".format(pid=pid, err_msg=err_msg))
+        log.warning("Progress {pid} error: {err_msg}".format(pid=pid, err_msg=err_msg))
         try:
             callbacks = self._progress_ids.pop(pid)
         except KeyError:
@@ -1109,7 +1109,7 @@
     def _subscribe_cb(self, answer, data):
         entity, profile = data
         type_ = "subscribed" if answer else "unsubscribed"
-        self.bridge.subscription(type_, unicode(entity.bare), profile_key=profile)
+        self.bridge.subscription(type_, str(entity.bare), profile_key=profile)
 
     def subscribeHandler(self, type, raw_jid, profile):
         """Called when a subsciption management signal is received"""
@@ -1118,18 +1118,18 @@
             # this is a subscription confirmation, we just have to inform user
             # TODO: call self.getEntityMBlog to add the new contact blogs
             self.showDialog(
-                _(u"The contact {contact} has accepted your subscription").format(
+                _("The contact {contact} has accepted your subscription").format(
                     contact=entity.bare
                 ),
-                _(u"Subscription confirmation"),
+                _("Subscription confirmation"),
             )
         elif type == "unsubscribed":
             # this is a subscription refusal, we just have to inform user
             self.showDialog(
-                _(u"The contact {contact} has refused your subscription").format(
+                _("The contact {contact} has refused your subscription").format(
                     contact=entity.bare
                 ),
-                _(u"Subscription refusal"),
+                _("Subscription refusal"),
                 "error",
             )
         elif type == "subscribe":
@@ -1137,8 +1137,8 @@
             # TODO: use sat.stdui.ui_contact_list to display the groups selector
             self.showDialog(
                 _(
-                    u"The contact {contact} wants to subscribe to your presence"
-                    u".\nDo you accept ?"
+                    "The contact {contact} wants to subscribe to your presence"
+                    ".\nDo you accept ?"
                 ).format(contact=entity.bare),
                 _("Subscription confirmation"),
                 "yes/no",
@@ -1147,11 +1147,11 @@
             )
 
     def _debugHandler(self, action, parameters, profile):
-        if action == u"widgets_dump":
+        if action == "widgets_dump":
             from pprint import pformat
-            log.info(u"Widgets dump:\n{data}".format(data=pformat(self.widgets._widgets)))
+            log.info("Widgets dump:\n{data}".format(data=pformat(self.widgets._widgets)))
         else:
-            log.warning(u"Unknown debug action: {action}".format(action=action))
+            log.warning("Unknown debug action: {action}".format(action=action))
 
 
     def showDialog(self, message, title, type="info", answer_cb=None, answer_data=None):
@@ -1178,11 +1178,11 @@
         pass  # FIXME
 
     def dialogFailure(self, failure):
-        log.warning(u"Failure: {}".format(failure))
+        log.warning("Failure: {}".format(failure))
 
     def progressIdHandler(self, progress_id, profile):
         """Callback used when an action result in a progress id"""
-        log.info(u"Progress ID received: {}".format(progress_id))
+        log.info("Progress ID received: {}".format(progress_id))
 
     def isHidden(self):
         """Tells if the frontend window is hidden.
@@ -1193,11 +1193,11 @@
 
     def paramUpdateHandler(self, name, value, namespace, profile):
         log.debug(
-            _(u"param update: [%(namespace)s] %(name)s = %(value)s")
+            _("param update: [%(namespace)s] %(name)s = %(value)s")
             % {"namespace": namespace, "name": name, "value": value}
         )
         if (namespace, name) == ("Connection", "JabberID"):
-            log.debug(_(u"Changing JID to %s") % value)
+            log.debug(_("Changing JID to %s") % value)
             self.profiles[profile].whoami = jid.JID(value)
         elif (namespace, name) == ("General", C.SHOW_OFFLINE_CONTACTS):
             self.contact_lists[profile].showOfflineContacts(C.bool(value))
@@ -1264,13 +1264,13 @@
 
         # we ignore metadata
         action_data = {
-            k: v for k, v in action_data.iteritems() if not k.startswith("meta_")
+            k: v for k, v in action_data.items() if not k.startswith("meta_")
         }
 
         if action_data:
             raise exceptions.DataError(
-                u"Not all keys in action_data are managed ({keys})".format(
-                    keys=", ".join(action_data.keys())
+                "Not all keys in action_data are managed ({keys})".format(
+                    keys=", ".join(list(action_data.keys()))
                 )
             )
 
@@ -1348,10 +1348,10 @@
 
     def _avatarGetEb(self, failure_, entity, contact_list):
         # FIXME: bridge needs a proper error handling
-        if "NotFound" in unicode(failure_):
-            log.info(u"No avatar found for {entity}".format(entity=entity))
+        if "NotFound" in str(failure_):
+            log.info("No avatar found for {entity}".format(entity=entity))
         else:
-            log.warning(u"Can't get avatar: {}".format(failure_))
+            log.warning("Can't get avatar: {}".format(failure_))
         contact_list.setCache(entity, "avatar", self.getDefaultAvatar(entity))
 
     def getAvatar(
@@ -1383,7 +1383,7 @@
                 avatar = None
         if avatar is None:
             self.bridge.avatarGet(
-                unicode(entity),
+                str(entity),
                 cache_only,
                 hash_only,
                 profile=profile,
@@ -1413,7 +1413,7 @@
     def onExit(self):
         """Must be called when the frontend is terminating"""
         to_unplug = []
-        for profile, profile_manager in self.profiles.iteritems():
+        for profile, profile_manager in self.profiles.items():
             if profile_manager.connected and profile_manager.autodisconnect:
                 # The user wants autodisconnection
                 self.disconnect(profile)