diff sat/plugins/plugin_exp_pubsub_schema.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 989b622faff6
children fee60f17ebac
line wrap: on
line diff
--- a/sat/plugins/plugin_exp_pubsub_schema.py	Wed Jul 31 11:31:22 2019 +0200
+++ b/sat/plugins/plugin_exp_pubsub_schema.py	Tue Aug 13 19:08:41 2019 +0200
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
 # SAT plugin for Pubsub Schemas
@@ -20,7 +20,7 @@
 from collections import Iterable
 import copy
 import itertools
-from zope.interface import implements
+from zope.interface import implementer
 from twisted.words.protocols.jabber import jid
 from twisted.words.protocols.jabber.xmlstream import XMPPHandler
 from twisted.internet import defer
@@ -38,23 +38,23 @@
 
 log = getLogger(__name__)
 
-NS_SCHEMA = u"https://salut-a-toi/protocol/schema:0"
+NS_SCHEMA = "https://salut-a-toi/protocol/schema:0"
 
 PLUGIN_INFO = {
-    C.PI_NAME: u"PubSub Schema",
-    C.PI_IMPORT_NAME: u"PUBSUB_SCHEMA",
-    C.PI_TYPE: u"EXP",
+    C.PI_NAME: "PubSub Schema",
+    C.PI_IMPORT_NAME: "PUBSUB_SCHEMA",
+    C.PI_TYPE: "EXP",
     C.PI_PROTOCOLS: [],
-    C.PI_DEPENDENCIES: [u"XEP-0060", u"IDENTITY"],
-    C.PI_MAIN: u"PubsubSchema",
-    C.PI_HANDLER: u"yes",
-    C.PI_DESCRIPTION: _(u"""Handle Pubsub data schemas"""),
+    C.PI_DEPENDENCIES: ["XEP-0060", "IDENTITY"],
+    C.PI_MAIN: "PubsubSchema",
+    C.PI_HANDLER: "yes",
+    C.PI_DESCRIPTION: _("""Handle Pubsub data schemas"""),
 }
 
 
 class PubsubSchema(object):
     def __init__(self, host):
-        log.info(_(u"PubSub Schema initialization"))
+        log.info(_("PubSub Schema initialization"))
         self.host = host
         self._p = self.host.plugins["XEP-0060"]
         self._i = self.host.plugins["IDENTITY"]
@@ -64,7 +64,7 @@
             in_sign="sss",
             out_sign="s",
             method=self._getSchema,
-            async=True,
+            async_=True,
         )
         host.bridge.addMethod(
             "psSchemaSet",
@@ -72,15 +72,16 @@
             in_sign="ssss",
             out_sign="",
             method=self._setSchema,
-            async=True,
+            async_=True,
         )
         host.bridge.addMethod(
             "psSchemaUIGet",
             ".plugin",
             in_sign="sss",
             out_sign="s",
-            method=utils.partial(self._getUISchema, default_node=None),
-            async=True,
+            method=lambda service, nodeIdentifier, profile_key: self._getUISchema(
+                service, nodeIdentifier, default_node=None, profile_key=profile_key),
+            async_=True,
         )
         host.bridge.addMethod(
             "psItemsFormGet",
@@ -88,7 +89,7 @@
             in_sign="ssssiassa{ss}s",
             out_sign="(asa{ss})",
             method=self._getDataFormItems,
-            async=True,
+            async_=True,
         )
         host.bridge.addMethod(
             "psItemFormSend",
@@ -96,7 +97,7 @@
             in_sign="ssa{sas}ssa{ss}s",
             out_sign="s",
             method=self._sendDataFormItem,
-            async=True,
+            async_=True,
         )
 
     def getHandler(self, client):
@@ -104,7 +105,7 @@
 
     def _getSchemaBridgeCb(self, schema_elt):
         if schema_elt is None:
-            return u""
+            return ""
         return schema_elt.toXml()
 
     def _getSchema(self, service, nodeIdentifier, profile_key=C.PROF_KEY_NONE):
@@ -135,7 +136,7 @@
         @return (domish.Element, None): schema (<x> element)
             None if not schema has been set on this node
         """
-        iq_elt = client.IQ(u"get")
+        iq_elt = client.IQ("get")
         if service is not None:
             iq_elt["to"] = service.full()
         pubsub_elt = iq_elt.addElement((NS_SCHEMA, "pubsub"))
@@ -163,12 +164,12 @@
             the form should not be modified if copy_form is not set
         """
         if schema is None:
-            log.debug(_(u"unspecified schema, we need to request it"))
+            log.debug(_("unspecified schema, we need to request it"))
             schema = yield self.getSchema(client, service, nodeIdentifier)
             if schema is None:
                 raise exceptions.DataError(
                     _(
-                        u"no schema specified, and this node has no schema either, we can't construct the data form"
+                        "no schema specified, and this node has no schema either, we can't construct the data form"
                     )
                 )
         elif isinstance(schema, data_form.Form):
@@ -179,7 +180,7 @@
         try:
             form = data_form.Form.fromElement(schema)
         except data_form.Error as e:
-            raise exceptions.DataError(_(u"Invalid Schema: {msg}").format(msg=e))
+            raise exceptions.DataError(_("Invalid Schema: {msg}").format(msg=e))
         form.formType = form_type
         defer.returnValue(form)
 
@@ -192,7 +193,7 @@
                      profile_key=C.PROF_KEY_NONE):
         if not nodeIdentifier:
             if not default_node:
-                raise ValueError(_(u"nodeIndentifier needs to be set"))
+                raise ValueError(_("nodeIndentifier needs to be set"))
             nodeIdentifier = default_node
         client = self.host.getClient(profile_key)
         service = None if not service else jid.JID(service)
@@ -233,7 +234,7 @@
         client = self.host.getClient(profile_key)
         service = jid.JID(service) if service else None
         if not node:
-            raise exceptions.DataError(_(u"empty node is not allowed"))
+            raise exceptions.DataError(_("empty node is not allowed"))
         if schema:
             schema = generic.parseXml(schema.encode("utf-8"))
         else:
@@ -276,7 +277,7 @@
         if not nodeIdentifier:
             if not default_node:
                 raise ValueError(
-                    _(u"default_node must be set if nodeIdentifier is not set")
+                    _("default_node must be set if nodeIdentifier is not set")
                 )
             nodeIdentifier = default_node
         # we need the initial form to get options of fields when suitable
@@ -296,7 +297,7 @@
         items, metadata = items_data
         items_xmlui = []
         for item_elt in items:
-            for x_elt in item_elt.elements((data_form.NS_X_DATA, u"x")):
+            for x_elt in item_elt.elements((data_form.NS_X_DATA, "x")):
                 form = data_form.Form.fromElement(x_elt)
                 if form_ns and form.formNamespace != form_ns:
                     continue
@@ -307,9 +308,9 @@
                     #        are not checked
                     prepend=(
                         ("label", "id"),
-                        ("text", item_elt["id"], u"id"),
+                        ("text", item_elt["id"], "id"),
                         ("label", "publisher"),
-                        ("text", item_elt.getAttribute("publisher", ""), u"publisher"),
+                        ("text", item_elt.getAttribute("publisher", ""), "publisher"),
                     ),
                     filters=filters,
                     read_only=False,
@@ -336,7 +337,7 @@
             extra,
             deserialise=True,
         )
-        d.addCallback(lambda ret: ret or u"")
+        d.addCallback(lambda ret: ret or "")
         return d
 
     @defer.inlineCallbacks
@@ -361,22 +362,22 @@
             client, service, nodeIdentifier, schema, form_type="submit"
         )
 
-        for name, values_list in values.iteritems():
+        for name, values_list in values.items():
             try:
                 field = form.fields[name]
             except KeyError:
                 log.warning(
-                    _(u"field {name} doesn't exist, ignoring it").format(name=name)
+                    _("field {name} doesn't exist, ignoring it").format(name=name)
                 )
                 continue
-            if isinstance(values_list, basestring) or not isinstance(
+            if isinstance(values_list, str) or not isinstance(
                 values_list, Iterable
             ):
                 values_list = [values_list]
             if deserialise:
-                if field.fieldType == u"boolean":
+                if field.fieldType == "boolean":
                     values_list = [C.bool(v) for v in values_list]
-                elif field.fieldType == u"text-multi":
+                elif field.fieldType == "text-multi":
                     # for text-multi, lines must be put on separate values
                     values_list = list(
                         itertools.chain(*[v.splitlines() for v in values_list])
@@ -384,9 +385,9 @@
                 elif xml_tools.isXHTMLField(field):
                    values_list = [generic.parseXml(v.encode("utf-8"))
                                   for v in values_list]
-                elif u"jid" in (field.fieldType or u""):
+                elif "jid" in (field.fieldType or ""):
                     values_list = [jid.JID(v) for v in values_list]
-            if u"list" in (field.fieldType or u""):
+            if "list" in (field.fieldType or ""):
                 # for lists, we check that given values are allowed in form
                 allowed_values = [o.value for o in field.options]
                 values_list = [v for v in values_list if v in allowed_values]
@@ -419,26 +420,26 @@
 
         main use case is using a textbox for labels
         """
-        if widget_type != u"textbox":
+        if widget_type != "textbox":
             return widget_type, args, kwargs
-        widget_type = u"list"
-        options = [o for o in args.pop(0).split(u"\n") if o]
+        widget_type = "list"
+        options = [o for o in args.pop(0).split("\n") if o]
         kwargs = {
             "options": options,
             "name": kwargs.get("name"),
-            "styles": (u"noselect", u"extensible", u"reducible"),
+            "styles": ("noselect", "extensible", "reducible"),
         }
         return widget_type, args, kwargs
 
     def dateFilter(self, form_xmlui, widget_type, args, kwargs):
         """Convert a string with a date to a unix timestamp"""
-        if widget_type != u"string" or not args[0]:
+        if widget_type != "string" or not args[0]:
             return widget_type, args, kwargs
         # we convert XMPP date to timestamp
         try:
-            args[0] = unicode(date_utils.date_parse(args[0]))
+            args[0] = str(date_utils.date_parse(args[0]))
         except Exception as e:
-            log.warning(_(u"Can't parse date field: {msg}").format(msg=e))
+            log.warning(_("Can't parse date field: {msg}").format(msg=e))
         return widget_type, args, kwargs
 
     ## Helper methods ##
@@ -479,7 +480,7 @@
         #      have to modify them
         if C.bool(extra.get("labels_as_list", C.BOOL_FALSE)):
             filters = filters.copy()
-            filters[u"labels"] = self.textbox2ListFilter
+            filters["labels"] = self.textbox2ListFilter
         client, service, node, max_items, extra, sub_id = self.prepareBridgeGet(
             service, node, max_items, sub_id, extra, profile_key
         )
@@ -536,7 +537,7 @@
             item_elt = items_data[0][0]
         except Exception as e:
             log.warning(
-                _(u"Can't get previous item, update ignored: {reason}").format(
+                _("Can't get previous item, update ignored: {reason}").format(
                     reason=e
                 )
             )
@@ -546,13 +547,13 @@
             if form is None:
                 log.warning(
                     _(
-                        u"Can't parse previous item, update ignored: data form not found"
+                        "Can't parse previous item, update ignored: data form not found"
                     ).format(reason=e)
                 )
             else:
-                for name, field in form.fields.iteritems():
+                for name, field in form.fields.items():
                     if name not in values:
-                        values[name] = u"\n".join(unicode(v) for v in field.values)
+                        values[name] = "\n".join(str(v) for v in field.values)
 
     def _set(self, service, node, values, schema=None, item_id=None, extra=None,
              default_node=None, form_ns=None, fill_author=True,
@@ -578,7 +579,7 @@
             default_node=default_node,
             fill_author=fill_author,
         )
-        d.addCallback(lambda ret: ret or u"")
+        d.addCallback(lambda ret: ret or "")
         return d
 
     @defer.inlineCallbacks
@@ -605,15 +606,15 @@
             extra = {}
         if not node:
             if default_node is None:
-                raise ValueError(_(u"default_node must be set if node is not set"))
+                raise ValueError(_("default_node must be set if node is not set"))
             node = default_node
         now = utils.xmpp_date()
         if not item_id:
             values["created"] = now
-        elif extra.get(u"update", False):
+        elif extra.get("update", False):
             if item_id is None:
                 raise exceptions.DataError(
-                    _(u'if extra["update"] is set, item_id must be set too')
+                    _('if extra["update"] is set, item_id must be set too')
                 )
             yield self.copyMissingValues(client, service, node, item_id, form_ns, values)
 
@@ -630,8 +631,8 @@
         defer.returnValue(item_id)
 
 
+@implementer(iwokkel.IDisco)
 class SchemaHandler(XMPPHandler):
-    implements(iwokkel.IDisco)
 
     def getDiscoInfo(self, requestor, service, nodeIdentifier=""):
         return [disco.DiscoFeature(NS_SCHEMA)]