diff sat_frontends/quick_frontend/quick_chat.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 b5f8cb26ef6f
children 1370323e8f6c
line wrap: on
line diff
--- a/sat_frontends/quick_frontend/quick_chat.py	Wed Jul 31 11:31:22 2019 +0200
+++ b/sat_frontends/quick_frontend/quick_chat.py	Tue Aug 13 19:08:41 2019 +0200
@@ -43,12 +43,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
 
 # FIXME: day_format need to be settable (i18n)
 
@@ -78,23 +78,20 @@
         )
         # is user mentioned here ?
         if self.parent.type == C.CHAT_GROUP and not self.own_mess:
-            for m in msg.itervalues():
+            for m in msg.values():
                 if self.parent.nick.lower() in m.lower():
                     self._mention = True
                     break
         self.handleMe()
         self.widgets = set()  # widgets linked to this message
 
-    def __unicode__(self):
-        return u"Message<{mess_type}>  [{time}]{nick}> {message}".format(
+    def __str__(self):
+        return "Message<{mess_type}>  [{time}]{nick}> {message}".format(
             mess_type=self.type,
             time=self.time_text,
             nick=self.nick,
             message=self.main_message)
 
-    def __str__(self):
-        return self.__unicode__().encode('utf-8', 'ignore')
-
     @property
     def host(self):
         return self.parent.host
@@ -126,28 +123,28 @@
             return self.message[""]
         except KeyError:
             try:
-                lang, mess = self.message.iteritems().next()
+                lang, mess = next(iter(self.message.items()))
                 self.selected_lang = lang
                 return mess
             except StopIteration:
-                log.error(u"Can't find message for uid {}".format(self.uid))
+                log.error("Can't find message for uid {}".format(self.uid))
                 return ""
 
     @property
     def main_message_xhtml(self):
         """rich message"""
-        xhtml = {k: v for k, v in self.extra.iteritems() if "html" in k}
+        xhtml = {k: v for k, v in self.extra.items() if "html" in k}
         if xhtml:
             # FIXME: we only return first found value for now
-            return next(xhtml.itervalues())
+            return next(iter(xhtml.values()))
 
     @property
     def time_text(self):
         """Return timestamp in a nicely formatted way"""
         # if the message was sent before today, we print the full date
         timestamp = time.localtime(self.timestamp)
-        time_format = u"%c" if timestamp < self.parent.day_change else u"%H:%M"
-        return time.strftime(time_format, timestamp).decode(getlocale()[1] or "utf-8")
+        time_format = "%c" if timestamp < self.parent.day_change else "%H:%M"
+        return time.strftime(time_format, timestamp)
 
     @property
     def avatar(self):
@@ -162,7 +159,7 @@
             try:
                 return self.extra["user_nick"]
             except KeyError:
-                log.error(u"extra data is missing user nick for uid {}".format(self.uid))
+                log.error("extra data is missing user nick for uid {}".format(self.uid))
                 return ""
         # FIXME: converted getSpecials to list for pyjamas
         if self.parent.type == C.CHAT_GROUP or entity in list(
@@ -197,8 +194,8 @@
         # TODO: XHTML-IM /me are not handled
         me = False
         # we need to check /me for every message
-        for m in self.message.itervalues():
-            if m.startswith(u"/me "):
+        for m in self.message.values():
+            if m.startswith("/me "):
                 me = True
             else:
                 me = False
@@ -207,8 +204,8 @@
             self.type = C.MESS_TYPE_INFO
             self.extra["info_type"] = "me"
             nick = self.nick
-            for lang, mess in self.message.iteritems():
-                self.message[lang] = u"* " + nick + mess[3:]
+            for lang, mess in self.message.items():
+                self.message[lang] = "* " + nick + mess[3:]
 
 
 class MessageWidget(object):
@@ -245,7 +242,7 @@
     @property
     def jid(self):
         """jid in the room"""
-        return jid.JID(u"{}/{}".format(self.parent.target.bare, self.nick))
+        return jid.JID("{}/{}".format(self.parent.target.bare, self.nick))
 
     @property
     def real_jid(self):
@@ -295,10 +292,10 @@
         if type_ == C.CHAT_GROUP:
             if target.resource:
                 raise exceptions.InternalError(
-                    u"a group chat entity can't have a resource"
+                    "a group chat entity can't have a resource"
                 )
             if nick is None:
-                raise exceptions.InternalError(u"nick must not be None for group chat")
+                raise exceptions.InternalError("nick must not be None for group chat")
 
             self.nick = nick
             self.occupants = {}
@@ -306,7 +303,7 @@
         else:
             if occupants is not None or nick is not None:
                 raise exceptions.InternalError(
-                    u"only group chat can have occupants or nick"
+                    "only group chat can have occupants or nick"
                 )
         self.messages = OrderedDict()  # key: uid, value: Message instance
         self.games = {}  # key=game name (unicode), value=instance of quick_games.RoomGame
@@ -334,25 +331,25 @@
         # FIXME: we don't use getter/setter here because of pyjamas
         # TODO: use proper getter/setter once we get rid of pyjamas
         if self._locked:
-            log.warning(u"{wid} is already locked!".format(wid=self))
+            log.warning("{wid} is already locked!".format(wid=self))
             return
         self._locked = True
         # messageNew signals are cached when locked
         self._cache = OrderedDict()
-        log.debug(u"{wid} is now locked".format(wid=self))
+        log.debug("{wid} is now locked".format(wid=self))
 
     def setUnlocked(self):
         if not self._locked:
-            log.debug(u"{wid} was already unlocked".format(wid=self))
+            log.debug("{wid} was already unlocked".format(wid=self))
             return
         self._locked = False
-        for uid, data in self._cache.iteritems():
+        for uid, data in self._cache.items():
             if uid not in self.messages:
                 self.messageNew(*data)
             else:
-                log.debug(u"discarding message already in history: {data}, ".format(data=data))
+                log.debug("discarding message already in history: {data}, ".format(data=data))
         del self._cache
-        log.debug(u"{wid} is now unlocked".format(wid=self))
+        log.debug("{wid} is now unlocked".format(wid=self))
 
     def postInit(self):
         """Method to be called by frontend after widget is initialised
@@ -404,8 +401,8 @@
         if self._resync_lock:
             return
         self._resync_lock = True
-        log.debug(u"resynchronising {self}".format(self=self))
-        for mess in reversed(self.messages.values()):
+        log.debug("resynchronising {self}".format(self=self))
+        for mess in reversed(list(self.messages.values())):
             if mess.type == C.MESS_TYPE_INFO:
                 continue
             last_message = mess
@@ -417,7 +414,7 @@
         if self.type == C.CHAT_GROUP:
             self.occupantsClear()
             self.host.bridge.mucOccupantsGet(
-                unicode(self.target), self.profile, callback=self.updateOccupants,
+                str(self.target), self.profile, callback=self.updateOccupants,
                 errback=log.error)
         self.historyPrint(
             size=C.HISTORY_LIMIT_NONE,
@@ -427,15 +424,15 @@
 
     ## Widget management ##
 
-    def __unicode__(self):
-        return u"Chat Widget [target: {}, type: {}, profile: {}]".format(
+    def __str__(self):
+        return "Chat Widget [target: {}, type: {}, profile: {}]".format(
             self.target, self.type, self.profile
         )
 
     @staticmethod
     def getWidgetHash(target, profiles):
         profile = list(profiles)[0]
-        return profile + "\n" + unicode(target.bare)
+        return profile + "\n" + str(target.bare)
 
     @staticmethod
     def getPrivateHash(target, profile):
@@ -443,7 +440,7 @@
 
         This method should be used with force_hash to get unique widget for private MUC conversations
         """
-        return (unicode(profile), target)
+        return (str(profile), target)
 
     def addTarget(self, target):
         super(QuickChat, self).addTarget(target)
@@ -456,7 +453,7 @@
         """copy important attribute for a new widget"""
         kwargs["type_"] = self.type
         if self.type == C.CHAT_GROUP:
-            kwargs["occupants"] = {o.nick: o.data for o in self.occupants.itervalues()}
+            kwargs["occupants"] = {o.nick: o.data for o in self.occupants.values()}
         kwargs["subject"] = self.subject
         try:
             kwargs["nick"] = self.nick
@@ -492,7 +489,7 @@
     def setOccupants(self, occupants):
         """Set the whole list of occupants"""
         assert len(self.occupants) == 0
-        for nick, data in occupants.iteritems():
+        for nick, data in occupants.items():
             # XXX: this log is disabled because it's really too verbose
             #      but kept commented as it may be useful for debugging
             # log.debug(u"adding occupant {nick} to {room}".format(
@@ -510,12 +507,12 @@
         updated_occupants = set(occupants)
         left_occupants = local_occupants - updated_occupants
         joined_occupants = updated_occupants - local_occupants
-        log.debug(u"updating occupants for {room}:\n"
-                  u"left: {left_occupants}\n"
-                  u"joined: {joined_occupants}"
+        log.debug("updating occupants for {room}:\n"
+                  "left: {left_occupants}\n"
+                  "joined: {joined_occupants}"
                   .format(room=self.target,
-                          left_occupants=u", ".join(left_occupants),
-                          joined_occupants=u", ".join(joined_occupants)))
+                          left_occupants=", ".join(left_occupants),
+                          joined_occupants=", ".join(joined_occupants)))
         for nick in left_occupants:
             self.removeUser(occupants[nick])
         for nick in joined_occupants:
@@ -533,7 +530,7 @@
         try:
             occupant = self.occupants.pop(nick)
         except KeyError:
-            log.warning(u"Trying to remove an unknown occupant: {}".format(nick))
+            log.warning("Trying to remove an unknown occupant: {}".format(nick))
         else:
             return occupant
 
@@ -602,12 +599,12 @@
         if filters is None:
             filters = {}
         if size == 0:
-            log.debug(u"Empty history requested, skipping")
+            log.debug("Empty history requested, skipping")
             self._onHistoryPrinted()
             return
-        log_msg = _(u"now we print the history")
+        log_msg = _("now we print the history")
         if size != C.HISTORY_LIMIT_DEFAULT:
-            log_msg += _(u" ({} messages)".format(size))
+            log_msg += _(" ({} messages)".format(size))
         log.debug(log_msg)
 
         if self.type == C.CHAT_ONE2ONE:
@@ -661,17 +658,17 @@
                 callback()
 
         def _historyGetEb(err):
-            log.error(_(u"Can't get history: {}").format(err))
+            log.error(_("Can't get history: {}").format(err))
             self._onHistoryPrinted()
             if callback is not None:
                 callback()
 
         self.host.bridge.historyGet(
-            unicode(self.host.profiles[profile].whoami.bare),
-            unicode(target),
+            str(self.host.profiles[profile].whoami.bare),
+            str(target),
             size,
             True,
-            {k: unicode(v) for k,v in filters.iteritems()},
+            {k: str(v) for k,v in filters.items()},
             profile,
             callback=_historyGetCb,
             errback=_historyGetEb,
@@ -683,7 +680,7 @@
             self.messageEncryptionStarted(session_data)
 
     def messageEncryptionGetEb(self, failure_):
-        log.error(_(u"Can't get encryption state: {reason}").format(reason=failure_))
+        log.error(_("Can't get encryption state: {reason}").format(reason=failure_))
 
     def getEncryptionState(self):
         """Retrieve encryption state with current target.
@@ -693,7 +690,7 @@
         """
         if self.type == C.CHAT_GROUP:
             return
-        self.host.bridge.messageEncryptionGet(unicode(self.target.bare), self.profile,
+        self.host.bridge.messageEncryptionGet(str(self.target.bare), self.profile,
                                               callback=self.messageEncryptionGetCb,
                                               errback=self.messageEncryptionGetEb)
 
@@ -715,7 +712,7 @@
             return
 
         if not msg and not subject and type_ != C.MESS_TYPE_INFO:
-            log.warning(u"Received an empty message for uid {}".format(uid))
+            log.warning("Received an empty message for uid {}".format(uid))
             return
 
         if self.type == C.CHAT_GROUP:
@@ -734,7 +731,7 @@
                     pass
                 else:
                     user_data = {
-                        k[5:]: v for k, v in extra.iteritems() if k.startswith("user_")
+                        k[5:]: v for k, v in extra.items() if k.startswith("user_")
                     }
                     if info_type == ROOM_USER_JOINED:
                         self.addUser(user_data)
@@ -747,18 +744,18 @@
         self.messages[uid] = message
 
         if "received_timestamp" in extra:
-            log.warning(u"Delayed message received after history, this should not happen")
+            log.warning("Delayed message received after history, this should not happen")
         self.createMessage(message)
 
     def messageEncryptionStarted(self, session_data):
         self.encrypted = True
-        log.debug(_(u"message encryption started with {target} using {encryption}").format(
-            target=self.target, encryption=session_data[u'name']))
+        log.debug(_("message encryption started with {target} using {encryption}").format(
+            target=self.target, encryption=session_data['name']))
 
     def messageEncryptionStopped(self, session_data):
         self.encrypted = False
-        log.debug(_(u"message encryption stopped with {target} (was using {encryption})")
-                 .format(target=self.target, encryption=session_data[u'name']))
+        log.debug(_("message encryption stopped with {target} (was using {encryption})")
+                 .format(target=self.target, encryption=session_data['name']))
 
     def createMessage(self, message, append=False):
         """Must be implemented by frontend to create and show a new message widget
@@ -810,12 +807,12 @@
                         count = wid.reentered_count = 1
                     nick = wid.mess_data.nick
                     if message.info_type == ROOM_USER_LEFT:
-                        wid.message = _(u"<= {nick} has left the room ({count})").format(
+                        wid.message = _("<= {nick} has left the room ({count})").format(
                             nick=nick, count=count
                         )
                     else:
                         wid.message = _(
-                            u"<=> {nick} re-entered the room ({count})"
+                            "<=> {nick} re-entered the room ({count})"
                         ).format(nick=nick, count=count)
                         wid.reentered_count += 1
                     return True
@@ -845,7 +842,7 @@
         This change the subject on the room itself (i.e. via XMPP),
         while setSubject change the subject of this widget
         """
-        self.host.bridge.mucSubject(unicode(self.target), new_subject, self.profile)
+        self.host.bridge.mucSubject(str(self.target), new_subject, self.profile)
 
     def addGamePanel(self, widget):
         """Insert a game panel to this Chat dialog.
@@ -879,7 +876,7 @@
                 self.occupants[nick].state = state
             except KeyError:
                 log.warning(
-                    u"{nick} not found in {room}, ignoring new chat state".format(
+                    "{nick} not found in {room}, ignoring new chat state".format(
                         nick=nick, room=self.target.bare
                     )
                 )
@@ -902,7 +899,7 @@
                     # entity is not here anymore
                     pass
 
-                for m in self.messages.values():
+                for m in list(self.messages.values()):
                     if m.nick == entity.resource:
                         for w in m.widgets:
                             w.update({"avatar": filename})
@@ -911,8 +908,8 @@
                 entity.bare == self.target.bare
                 or entity.bare == self.host.profiles[profile].whoami.bare
             ):
-                log.info(u"avatar updated for {}".format(entity))
-                for m in self.messages.values():
+                log.info("avatar updated for {}".format(entity))
+                for m in list(self.messages.values()):
                     if m.from_jid.bare == entity.bare:
                         for w in m.widgets:
                             w.update({"avatar": filename})