diff sat_frontends/jp/cmd_pubsub.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 b2f323237fce
children fee60f17ebac
line wrap: on
line diff
--- a/sat_frontends/jp/cmd_pubsub.py	Wed Jul 31 11:31:22 2019 +0200
+++ b/sat_frontends/jp/cmd_pubsub.py	Tue Aug 13 19:08:41 2019 +0200
@@ -18,7 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
-import base
+from . import base
 from sat.core.i18n import _
 from sat.core import exceptions
 from sat_frontends.jp.constants import Const as C
@@ -37,7 +37,7 @@
 
 __commands__ = ["Pubsub"]
 
-PUBSUB_TMP_DIR = u"pubsub"
+PUBSUB_TMP_DIR = "pubsub"
 PUBSUB_SCHEMA_TMP_DIR = PUBSUB_TMP_DIR + "_schema"
 ALLOWED_SUBSCRIPTIONS_OWNER = ("subscribed", "pending", "none")
 
@@ -53,7 +53,7 @@
             use_output=C.OUTPUT_DICT,
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"retrieve node configuration"),
+            help=_("retrieve node configuration"),
         )
         self.need_loop = True
 
@@ -61,29 +61,28 @@
         self.parser.add_argument(
             "-k",
             "--key",
-            type=base.unicode_decoder,
             action="append",
             dest="keys",
-            help=_(u"data key to filter"),
+            help=_("data key to filter"),
         )
 
     def removePrefix(self, key):
-        return key[7:] if key.startswith(u"pubsub#") else key
+        return key[7:] if key.startswith("pubsub#") else key
 
     def filterKey(self, key):
-        return any((key == k or key == u"pubsub#" + k) for k in self.args.keys)
+        return any((key == k or key == "pubsub#" + k) for k in self.args.keys)
 
     def psNodeConfigurationGetCb(self, config_dict):
         key_filter = (lambda k: True) if not self.args.keys else self.filterKey
         config_dict = {
-            self.removePrefix(k): v for k, v in config_dict.iteritems() if key_filter(k)
+            self.removePrefix(k): v for k, v in config_dict.items() if key_filter(k)
         }
         self.output(config_dict)
         self.host.quit()
 
     def psNodeConfigurationGetEb(self, failure_):
         self.disp(
-            u"can't get node configuration: {reason}".format(reason=failure_), error=True
+            "can't get node configuration: {reason}".format(reason=failure_), error=True
         )
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
@@ -107,7 +106,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"create a node"),
+            help=_("create a node"),
         )
         self.need_loop = True
 
@@ -115,36 +114,35 @@
         self.parser.add_argument(
             "-f",
             "--field",
-            type=base.unicode_decoder,
             action="append",
             nargs=2,
             dest="fields",
             default=[],
-            metavar=(u"KEY", u"VALUE"),
-            help=_(u"configuration field to set"),
+            metavar=("KEY", "VALUE"),
+            help=_("configuration field to set"),
         )
         self.parser.add_argument(
             "-F",
             "--full-prefix",
             action="store_true",
-            help=_(u'don\'t prepend "pubsub#" prefix to field names'),
+            help=_('don\'t prepend "pubsub#" prefix to field names'),
         )
 
     def psNodeCreateCb(self, node_id):
         if self.host.verbosity:
-            announce = _(u"node created successfully: ")
+            announce = _("node created successfully: ")
         else:
-            announce = u""
+            announce = ""
         self.disp(announce + node_id)
         self.host.quit()
 
     def psNodeCreateEb(self, failure_):
-        self.disp(u"can't create: {reason}".format(reason=failure_), error=True)
+        self.disp("can't create: {reason}".format(reason=failure_), error=True)
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
     def start(self):
         if not self.args.full_prefix:
-            options = {u"pubsub#" + k: v for k, v in self.args.fields}
+            options = {"pubsub#" + k: v for k, v in self.args.fields}
         else:
             options = dict(self.args.fields)
         self.host.bridge.psNodeCreate(
@@ -155,7 +153,7 @@
             callback=self.psNodeCreateCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't create node: {}"),
+                msg=_("can't create node: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -169,7 +167,7 @@
             "purge",
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"purge a node (i.e. remove all items from it)"),
+            help=_("purge a node (i.e. remove all items from it)"),
         )
         self.need_loop = True
 
@@ -178,26 +176,26 @@
             "-f",
             "--force",
             action="store_true",
-            help=_(u"purge node without confirmation"),
+            help=_("purge node without confirmation"),
         )
 
     def psNodePurgeCb(self):
-        self.disp(_(u"node [{node}] purged successfully").format(node=self.args.node))
+        self.disp(_("node [{node}] purged successfully").format(node=self.args.node))
         self.host.quit()
 
     def start(self):
         if not self.args.force:
             if not self.args.service:
-                message = _(u"Are you sure to purge PEP node [{node_id}]? "
-                            u"This will delete ALL items from it!").format(
+                message = _("Are you sure to purge PEP node [{node_id}]? "
+                            "This will delete ALL items from it!").format(
                     node_id=self.args.node
                 )
             else:
                 message = _(
-                    u"Are you sure to delete node [{node_id}] on service [{service}]? "
-                    u"This will delete ALL items from it!"
+                    "Are you sure to delete node [{node_id}] on service [{service}]? "
+                    "This will delete ALL items from it!"
                 ).format(node_id=self.args.node, service=self.args.service)
-            self.host.confirmOrQuit(message, _(u"node purge cancelled"))
+            self.host.confirmOrQuit(message, _("node purge cancelled"))
 
         self.host.bridge.psNodePurge(
             self.args.service,
@@ -206,7 +204,7 @@
             callback=self.psNodePurgeCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't purge node: {}"),
+                msg=_("can't purge node: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -220,7 +218,7 @@
             "delete",
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"delete a node"),
+            help=_("delete a node"),
         )
         self.need_loop = True
 
@@ -229,24 +227,24 @@
             "-f",
             "--force",
             action="store_true",
-            help=_(u"delete node without confirmation"),
+            help=_("delete node without confirmation"),
         )
 
     def psNodeDeleteCb(self):
-        self.disp(_(u"node [{node}] deleted successfully").format(node=self.args.node))
+        self.disp(_("node [{node}] deleted successfully").format(node=self.args.node))
         self.host.quit()
 
     def start(self):
         if not self.args.force:
             if not self.args.service:
-                message = _(u"Are you sure to delete PEP node [{node_id}] ?").format(
+                message = _("Are you sure to delete PEP node [{node_id}] ?").format(
                     node_id=self.args.node
                 )
             else:
                 message = _(
-                    u"Are you sure to delete node [{node_id}] on service [{service}] ?"
+                    "Are you sure to delete node [{node_id}] on service [{service}] ?"
                 ).format(node_id=self.args.node, service=self.args.service)
-            self.host.confirmOrQuit(message, _(u"node deletion cancelled"))
+            self.host.confirmOrQuit(message, _("node deletion cancelled"))
 
         self.host.bridge.psNodeDelete(
             self.args.service,
@@ -255,7 +253,7 @@
             callback=self.psNodeDeleteCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't delete node: {}"),
+                msg=_("can't delete node: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -271,7 +269,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"set node configuration"),
+            help=_("set node configuration"),
         )
         self.need_loop = True
 
@@ -279,28 +277,27 @@
         self.parser.add_argument(
             "-f",
             "--field",
-            type=base.unicode_decoder,
             action="append",
             nargs=2,
             dest="fields",
             required=True,
-            metavar=(u"KEY", u"VALUE"),
-            help=_(u"configuration field to set (required)"),
+            metavar=("KEY", "VALUE"),
+            help=_("configuration field to set (required)"),
         )
 
     def psNodeConfigurationSetCb(self):
-        self.disp(_(u"node configuration successful"), 1)
+        self.disp(_("node configuration successful"), 1)
         self.host.quit()
 
     def psNodeConfigurationSetEb(self, failure_):
         self.disp(
-            u"can't set node configuration: {reason}".format(reason=failure_), error=True
+            "can't set node configuration: {reason}".format(reason=failure_), error=True
         )
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
     def getKeyName(self, k):
-        if not k.startswith(u"pubsub#"):
-            return u"pubsub#" + k
+        if not k.startswith("pubsub#"):
+            return "pubsub#" + k
         else:
             return k
 
@@ -323,7 +320,7 @@
             "import",
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"import raw XML to a node"),
+            help=_("import raw XML to a node"),
         )
         self.need_loop = True
 
@@ -331,18 +328,18 @@
         self.parser.add_argument(
             "--admin",
             action="store_true",
-            help=_(u"do a pubsub admin request, needed to change publisher"),
+            help=_("do a pubsub admin request, needed to change publisher"),
         )
         self.parser.add_argument(
             "import_file",
-            type=file,
-            help=_(u"path to the XML file with data to import. The file must contain "
-                   u"whole XML of each item to import."),
+            type=argparse.FileType(),
+            help=_("path to the XML file with data to import. The file must contain "
+                   "whole XML of each item to import."),
         )
 
     def psItemsSendCb(self, item_ids):
-        self.disp(_(u'items published with id(s) {item_ids}').format(
-            item_ids=u', '.join(item_ids)))
+        self.disp(_('items published with id(s) {item_ids}').format(
+            item_ids=', '.join(item_ids)))
         self.host.quit()
 
     def start(self):
@@ -364,7 +361,7 @@
 
         if not all([i.tag == '{http://jabber.org/protocol/pubsub}item' for i in element]):
             self.disp(
-                _(u"You are not using list of pubsub items, we can't import this file"),
+                _("You are not using list of pubsub items, we can't import this file"),
                 error=True)
             self.host.quit(C.EXIT_DATA_ERROR)
 
@@ -374,28 +371,28 @@
                 self.args.service,
                 self.args.node,
                 items,
-                u"",
+                "",
                 self.profile,
                 callback=partial(self.psItemsSendCb),
                 errback=partial(
                     self.errback,
-                    msg=_(u"can't send item: {}"),
+                    msg=_("can't send item: {}"),
                     exit_code=C.EXIT_BRIDGE_ERRBACK,
                 ),
             )
         else:
-            self.disp(_(u"Items are imported without using admin mode, publisher can't "
-                        u"be changed"))
+            self.disp(_("Items are imported without using admin mode, publisher can't "
+                        "be changed"))
             self.host.bridge.psItemsSend(
                 self.args.service,
                 self.args.node,
                 items,
-                u"",
+                "",
                 self.profile,
                 callback=partial(self.psItemsSendCb),
                 errback=partial(
                     self.errback,
-                    msg=_(u"can't send item: {}"),
+                    msg=_("can't send item: {}"),
                     exit_code=C.EXIT_BRIDGE_ERRBACK,
                 ),
             )
@@ -410,7 +407,7 @@
             use_output=C.OUTPUT_DICT,
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"retrieve node affiliations (for node owner)"),
+            help=_("retrieve node affiliations (for node owner)"),
         )
         self.need_loop = True
 
@@ -423,7 +420,7 @@
 
     def psNodeAffiliationsGetEb(self, failure_):
         self.disp(
-            u"can't get node affiliations: {reason}".format(reason=failure_), error=True
+            "can't get node affiliations: {reason}".format(reason=failure_), error=True
         )
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
@@ -446,7 +443,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"set affiliations (for node owner)"),
+            help=_("set affiliations (for node owner)"),
         )
         self.need_loop = True
 
@@ -459,19 +456,18 @@
             dest="affiliations",
             metavar=("JID", "AFFILIATION"),
             required=True,
-            type=base.unicode_decoder,
             action="append",
             nargs=2,
-            help=_(u"entity/affiliation couple(s)"),
+            help=_("entity/affiliation couple(s)"),
         )
 
     def psNodeAffiliationsSetCb(self):
-        self.disp(_(u"affiliations have been set"), 1)
+        self.disp(_("affiliations have been set"), 1)
         self.host.quit()
 
     def psNodeAffiliationsSetEb(self, failure_):
         self.disp(
-            u"can't set node affiliations: {reason}".format(reason=failure_), error=True
+            "can't set node affiliations: {reason}".format(reason=failure_), error=True
         )
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
@@ -495,7 +491,7 @@
             host,
             "affiliations",
             use_profile=False,
-            help=_(u"set or retrieve node affiliations"),
+            help=_("set or retrieve node affiliations"),
         )
 
 
@@ -508,7 +504,7 @@
             use_output=C.OUTPUT_DICT,
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"retrieve node subscriptions (for node owner)"),
+            help=_("retrieve node subscriptions (for node owner)"),
         )
         self.need_loop = True
 
@@ -521,7 +517,7 @@
 
     def psNodeSubscriptionsGetEb(self, failure_):
         self.disp(
-            u"can't get node subscriptions: {reason}".format(reason=failure_), error=True
+            "can't get node subscriptions: {reason}".format(reason=failure_), error=True
         )
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
@@ -552,8 +548,8 @@
                 subscription = "subscribed"
             if subscription not in ALLOWED_SUBSCRIPTIONS_OWNER:
                 parser.error(
-                    _(u"subscription must be one of {}").format(
-                        u", ".join(ALLOWED_SUBSCRIPTIONS_OWNER)
+                    _("subscription must be one of {}").format(
+                        ", ".join(ALLOWED_SUBSCRIPTIONS_OWNER)
                     )
                 )
             dest_dict[jid_s] = subscription
@@ -568,7 +564,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"set/modify subscriptions (for node owner)"),
+            help=_("set/modify subscriptions (for node owner)"),
         )
         self.need_loop = True
 
@@ -583,18 +579,17 @@
             nargs="+",
             metavar=("JID [SUSBSCRIPTION]"),
             required=True,
-            type=base.unicode_decoder,
             action=StoreSubscriptionAction,
-            help=_(u"entity/subscription couple(s)"),
+            help=_("entity/subscription couple(s)"),
         )
 
     def psNodeSubscriptionsSetCb(self):
-        self.disp(_(u"subscriptions have been set"), 1)
+        self.disp(_("subscriptions have been set"), 1)
         self.host.quit()
 
     def psNodeSubscriptionsSetEb(self, failure_):
         self.disp(
-            u"can't set node subscriptions: {reason}".format(reason=failure_), error=True
+            "can't set node subscriptions: {reason}".format(reason=failure_), error=True
         )
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
@@ -617,7 +612,7 @@
             host,
             "subscriptions",
             use_profile=False,
-            help=_(u"get or modify node subscriptions"),
+            help=_("get or modify node subscriptions"),
         )
 
 
@@ -630,15 +625,15 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"set/replace a schema"),
+            help=_("set/replace a schema"),
         )
         self.need_loop = True
 
     def add_parser_options(self):
-        self.parser.add_argument("schema", help=_(u"schema to set (must be XML)"))
+        self.parser.add_argument("schema", help=_("schema to set (must be XML)"))
 
     def psSchemaSetCb(self):
-        self.disp(_(u"schema has been set"), 1)
+        self.disp(_("schema has been set"), 1)
         self.host.quit()
 
     def start(self):
@@ -650,7 +645,7 @@
             callback=self.psSchemaSetCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't set schema: {}"),
+                msg=_("can't set schema: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -668,7 +663,7 @@
             pubsub_flags={C.NODE},
             use_draft=True,
             use_verbose=True,
-            help=_(u"edit a schema"),
+            help=_("edit a schema"),
         )
         common.BaseEdit.__init__(self, self.host, PUBSUB_SCHEMA_TMP_DIR)
         self.need_loop = True
@@ -677,7 +672,7 @@
         pass
 
     def psSchemaSetCb(self):
-        self.disp(_(u"schema has been set"), 1)
+        self.disp(_("schema has been set"), 1)
         self.host.quit()
 
     def publish(self, schema):
@@ -689,7 +684,7 @@
             callback=self.psSchemaSetCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't set schema: {}"),
+                msg=_("can't set schema: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -698,8 +693,8 @@
         try:
             from lxml import etree
         except ImportError:
-            self.disp(u'lxml module must be installed to use edit, please install it '
-                      u'with "pip install lxml"',
+            self.disp('lxml module must be installed to use edit, please install it '
+                      'with "pip install lxml"',
                 error=True,
             )
             self.host.quit(1)
@@ -722,7 +717,7 @@
             callback=self.psSchemaGetCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't edit schema: {}"),
+                msg=_("can't edit schema: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -738,7 +733,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"get schema"),
+            help=_("get schema"),
         )
         self.need_loop = True
 
@@ -747,7 +742,7 @@
 
     def psSchemaGetCb(self, schema):
         if not schema:
-            self.disp(_(u"no schema found"), 1)
+            self.disp(_("no schema found"), 1)
             self.host.quit(1)
         self.output(schema)
         self.host.quit()
@@ -760,7 +755,7 @@
             callback=self.psSchemaGetCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't get schema: {}"),
+                msg=_("can't get schema: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -771,7 +766,7 @@
 
     def __init__(self, host):
         super(NodeSchema, self).__init__(
-            host, "schema", use_profile=False, help=_(u"data schema manipulation")
+            host, "schema", use_profile=False, help=_("data schema manipulation")
         )
 
 
@@ -802,24 +797,23 @@
             "set",
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"publish a new item or update an existing one"),
+            help=_("publish a new item or update an existing one"),
         )
         self.need_loop = True
 
     def add_parser_options(self):
         self.parser.add_argument(
             "item",
-            type=base.unicode_decoder,
             nargs="?",
-            default=u"",
-            help=_(u"id, URL of the item to update, keyword, or nothing for new item"),
+            default="",
+            help=_("id, URL of the item to update, keyword, or nothing for new item"),
         )
 
     def psItemsSendCb(self, published_id):
         if published_id:
-            self.disp(u"Item published at {pub_id}".format(pub_id=published_id))
+            self.disp("Item published at {pub_id}".format(pub_id=published_id))
         else:
-            self.disp(u"Item published")
+            self.disp("Item published")
         self.host.quit(C.EXIT_OK)
 
     def start(self):
@@ -837,7 +831,7 @@
             callback=self.psItemsSendCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't send item: {}"),
+                msg=_("can't send item: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -852,7 +846,7 @@
             use_output=C.OUTPUT_LIST_XML,
             use_pubsub=True,
             pubsub_flags={C.NODE, C.MULTI_ITEMS},
-            help=_(u"get pubsub item(s)"),
+            help=_("get pubsub item(s)"),
         )
         self.need_loop = True
 
@@ -860,9 +854,8 @@
         self.parser.add_argument(
             "-S",
             "--sub-id",
-            type=base.unicode_decoder,
-            default=u"",
-            help=_(u"subscription id"),
+            default="",
+            help=_("subscription id"),
         )
         #  TODO: a key(s) argument to select keys to display
         # TODO: add MAM filters
@@ -872,7 +865,7 @@
         self.host.quit(C.EXIT_OK)
 
     def psItemsGetEb(self, failure_):
-        self.disp(u"can't get pubsub items: {reason}".format(reason=failure_), error=True)
+        self.disp("can't get pubsub items: {reason}".format(reason=failure_), error=True)
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
     def start(self):
@@ -897,30 +890,30 @@
             "delete",
             use_pubsub=True,
             pubsub_flags={C.NODE, C.ITEM, C.SINGLE_ITEM},
-            help=_(u"delete an item"),
+            help=_("delete an item"),
         )
         self.need_loop = True
 
     def add_parser_options(self):
         self.parser.add_argument(
-            "-f", "--force", action="store_true", help=_(u"delete without confirmation")
+            "-f", "--force", action="store_true", help=_("delete without confirmation")
         )
         self.parser.add_argument(
-            "-N", "--notify", action="store_true", help=_(u"notify deletion")
+            "-N", "--notify", action="store_true", help=_("notify deletion")
         )
 
     def psItemsDeleteCb(self):
-        self.disp(_(u"item {item_id} has been deleted").format(item_id=self.args.item))
+        self.disp(_("item {item_id} has been deleted").format(item_id=self.args.item))
         self.host.quit(C.EXIT_OK)
 
     def start(self):
         if not self.args.item:
-            self.parser.error(_(u"You need to specify an item to delete"))
+            self.parser.error(_("You need to specify an item to delete"))
         if not self.args.force:
-            message = _(u"Are you sure to delete item {item_id} ?").format(
+            message = _("Are you sure to delete item {item_id} ?").format(
                 item_id=self.args.item
             )
-            self.host.confirmOrQuit(message, _(u"item deletion cancelled"))
+            self.host.confirmOrQuit(message, _("item deletion cancelled"))
         self.host.bridge.psRetractItem(
             self.args.service,
             self.args.node,
@@ -930,7 +923,7 @@
             callback=self.psItemsDeleteCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't delete item: {}"),
+                msg=_("can't delete item: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -946,7 +939,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE, C.SINGLE_ITEM},
             use_draft=True,
-            help=_(u"edit an existing or new pubsub item"),
+            help=_("edit an existing or new pubsub item"),
         )
         common.BaseEdit.__init__(self, self.host, PUBSUB_TMP_DIR)
 
@@ -967,16 +960,16 @@
             self.profile,
         )
         if published_id:
-            self.disp(u"Item published at {pub_id}".format(pub_id=published_id))
+            self.disp("Item published at {pub_id}".format(pub_id=published_id))
         else:
-            self.disp(u"Item published")
+            self.disp("Item published")
 
     def getItemData(self, service, node, item):
         try:
             from lxml import etree
         except ImportError:
-            self.disp(u'lxml module must be installed to use edit, please install it '
-                      u'with "pip install lxml"',
+            self.disp('lxml module must be installed to use edit, please install it '
+                      'with "pip install lxml"',
                 error=True,
             )
             self.host.quit(1)
@@ -990,8 +983,8 @@
         try:
             payload = item_elt[0]
         except IndexError:
-            self.disp(_(u"Item has not payload"), 1)
-            return u""
+            self.disp(_("Item has not payload"), 1)
+            return ""
         return etree.tostring(payload, encoding="unicode", pretty_print=True), item_id
 
     def start(self):
@@ -1010,7 +1003,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"subscribe to a node"),
+            help=_("subscribe to a node"),
         )
         self.need_loop = True
 
@@ -1018,9 +1011,9 @@
         pass
 
     def psSubscribeCb(self, sub_id):
-        self.disp(_(u"subscription done"), 1)
+        self.disp(_("subscription done"), 1)
         if sub_id:
-            self.disp(_(u"subscription id: {sub_id}").format(sub_id=sub_id))
+            self.disp(_("subscription id: {sub_id}").format(sub_id=sub_id))
         self.host.quit()
 
     def start(self):
@@ -1032,7 +1025,7 @@
             callback=self.psSubscribeCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't subscribe to node: {}"),
+                msg=_("can't subscribe to node: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -1049,7 +1042,7 @@
             use_pubsub=True,
             pubsub_flags={C.NODE},
             use_verbose=True,
-            help=_(u"unsubscribe from a node"),
+            help=_("unsubscribe from a node"),
         )
         self.need_loop = True
 
@@ -1057,7 +1050,7 @@
         pass
 
     def psUnsubscribeCb(self):
-        self.disp(_(u"subscription removed"), 1)
+        self.disp(_("subscription removed"), 1)
         self.host.quit()
 
     def start(self):
@@ -1068,7 +1061,7 @@
             callback=self.psUnsubscribeCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't unsubscribe from node: {}"),
+                msg=_("can't unsubscribe from node: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -1082,7 +1075,7 @@
             "subscriptions",
             use_output=C.OUTPUT_LIST_DICT,
             use_pubsub=True,
-            help=_(u"retrieve all subscriptions on a service"),
+            help=_("retrieve all subscriptions on a service"),
         )
         self.need_loop = True
 
@@ -1101,7 +1094,7 @@
             callback=self.psSubscriptionsGetCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't retrieve subscriptions: {}"),
+                msg=_("can't retrieve subscriptions: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -1115,7 +1108,7 @@
             "affiliations",
             use_output=C.OUTPUT_DICT,
             use_pubsub=True,
-            help=_(u"retrieve all affiliations on a service"),
+            help=_("retrieve all affiliations on a service"),
         )
         self.need_loop = True
 
@@ -1128,7 +1121,7 @@
 
     def psAffiliationsGetEb(self, failure_):
         self.disp(
-            u"can't get node affiliations: {reason}".format(reason=failure_), error=True
+            "can't get node affiliations: {reason}".format(reason=failure_), error=True
         )
         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
 
@@ -1150,7 +1143,7 @@
     """
 
     RE_FLAGS = re.MULTILINE | re.UNICODE
-    EXEC_ACTIONS = (u"exec", u"external")
+    EXEC_ACTIONS = ("exec", "external")
 
     def __init__(self, host):
         # FIXME: C.NO_MAX is not needed here, and this can be globally removed from consts
@@ -1164,7 +1157,7 @@
             use_pubsub=True,
             pubsub_flags={C.MULTI_ITEMS, C.NO_MAX},
             use_verbose=True,
-            help=_(u"search items corresponding to filters"),
+            help=_("search items corresponding to filters"),
         )
         self.need_loop = True
 
@@ -1178,7 +1171,6 @@
         return self._etree
 
     def filter_opt(self, value, type_):
-        value = base.unicode_decoder(value)
         return (type_, value)
 
     def filter_flag(self, value, type_):
@@ -1191,16 +1183,16 @@
             "--max-depth",
             type=int,
             default=0,
-            help=_(u"maximum depth of recursion (will search linked nodes if > 0, "
-                   u"DEFAULT: 0)"),
+            help=_("maximum depth of recursion (will search linked nodes if > 0, "
+                   "DEFAULT: 0)"),
         )
         self.parser.add_argument(
             "-M",
             "--node-max",
             type=int,
             default=30,
-            help=_(u"maximum number of items to get per node ({} to get all items, "
-                   u"DEFAULT: 30)".format( C.NO_LIMIT)),
+            help=_("maximum number of items to get per node ({} to get all items, "
+                   "DEFAULT: 30)".format( C.NO_LIMIT)),
         )
         self.parser.add_argument(
             "-N",
@@ -1209,17 +1201,17 @@
             nargs=2,
             default=[],
             metavar="NAME NAMESPACE",
-            help=_(u"namespace to use for xpath"),
+            help=_("namespace to use for xpath"),
         )
 
         # filters
-        filter_text = partial(self.filter_opt, type_=u"text")
-        filter_re = partial(self.filter_opt, type_=u"regex")
-        filter_xpath = partial(self.filter_opt, type_=u"xpath")
-        filter_python = partial(self.filter_opt, type_=u"python")
+        filter_text = partial(self.filter_opt, type_="text")
+        filter_re = partial(self.filter_opt, type_="regex")
+        filter_xpath = partial(self.filter_opt, type_="xpath")
+        filter_python = partial(self.filter_opt, type_="python")
         filters = self.parser.add_argument_group(
-            _(u"filters"),
-            _(u"only items corresponding to following filters will be kept"),
+            _("filters"),
+            _("only items corresponding to following filters will be kept"),
         )
         filters.add_argument(
             "-t",
@@ -1228,7 +1220,7 @@
             dest="filters",
             type=filter_text,
             metavar="TEXT",
-            help=_(u"full text filter, item must contain this string (XML included)"),
+            help=_("full text filter, item must contain this string (XML included)"),
         )
         filters.add_argument(
             "-r",
@@ -1237,7 +1229,7 @@
             dest="filters",
             type=filter_re,
             metavar="EXPRESSION",
-            help=_(u"like --text but using a regular expression"),
+            help=_("like --text but using a regular expression"),
         )
         filters.add_argument(
             "-x",
@@ -1246,7 +1238,7 @@
             dest="filters",
             type=filter_xpath,
             metavar="XPATH",
-            help=_(u"filter items which has elements matching this xpath"),
+            help=_("filter items which has elements matching this xpath"),
         )
         filters.add_argument(
             "-P",
@@ -1255,20 +1247,20 @@
             dest="filters",
             type=filter_python,
             metavar="PYTHON_CODE",
-            help=_(u'Python expression which much return a bool (True to keep item, '
-                   u'False to reject it). "item" is raw text item, "item_xml" is '
-                   u'lxml\'s etree.Element'
+            help=_('Python expression which much return a bool (True to keep item, '
+                   'False to reject it). "item" is raw text item, "item_xml" is '
+                   'lxml\'s etree.Element'
             ),
         )
 
         # filters flags
-        flag_case = partial(self.filter_flag, type_=u"ignore-case")
-        flag_invert = partial(self.filter_flag, type_=u"invert")
-        flag_dotall = partial(self.filter_flag, type_=u"dotall")
-        flag_matching = partial(self.filter_flag, type_=u"only-matching")
+        flag_case = partial(self.filter_flag, type_="ignore-case")
+        flag_invert = partial(self.filter_flag, type_="invert")
+        flag_dotall = partial(self.filter_flag, type_="dotall")
+        flag_matching = partial(self.filter_flag, type_="only-matching")
         flags = self.parser.add_argument_group(
-            _(u"filters flags"),
-            _(u"filters modifiers (change behaviour of following filters)"),
+            _("filters flags"),
+            _("filters modifiers (change behaviour of following filters)"),
         )
         flags.add_argument(
             "-C",
@@ -1279,7 +1271,7 @@
             const=("ignore-case", True),
             nargs="?",
             metavar="BOOLEAN",
-            help=_(u"(don't) ignore case in following filters (DEFAULT: case sensitive)"),
+            help=_("(don't) ignore case in following filters (DEFAULT: case sensitive)"),
         )
         flags.add_argument(
             "-I",
@@ -1290,7 +1282,7 @@
             const=("invert", True),
             nargs="?",
             metavar="BOOLEAN",
-            help=_(u"(don't) invert effect of following filters (DEFAULT: don't invert)"),
+            help=_("(don't) invert effect of following filters (DEFAULT: don't invert)"),
         )
         flags.add_argument(
             "-A",
@@ -1301,7 +1293,7 @@
             const=("dotall", True),
             nargs="?",
             metavar="BOOLEAN",
-            help=_(u"(don't) use DOTALL option for regex (DEFAULT: don't use)"),
+            help=_("(don't) use DOTALL option for regex (DEFAULT: don't use)"),
         )
         flags.add_argument(
             "-k",
@@ -1312,7 +1304,7 @@
             const=("only-matching", True),
             nargs="?",
             metavar="BOOLEAN",
-            help=_(u"keep only the matching part of the item"),
+            help=_("keep only the matching part of the item"),
         )
 
         # action
@@ -1321,13 +1313,13 @@
             default="print",
             nargs="?",
             choices=("print", "exec", "external"),
-            help=_(u"action to do on found items (DEFAULT: print)"),
+            help=_("action to do on found items (DEFAULT: print)"),
         )
         self.parser.add_argument("command", nargs=argparse.REMAINDER)
 
     def psItemsGetEb(self, failure_, service, node):
         self.disp(
-            u"can't get pubsub items at {service} (node: {node}): {reason}".format(
+            "can't get pubsub items at {service} (node: {node}): {reason}".format(
                 service=service, node=node, reason=failure_
             ),
             error=True,
@@ -1357,15 +1349,15 @@
             this list will be filled while xmpp: URIs are discovered
         """
         url = match.group(0)
-        if url.startswith(u"xmpp"):
+        if url.startswith("xmpp"):
             try:
                 url_data = uri.parseXMPPUri(url)
             except ValueError:
                 return
-            if url_data[u"type"] == u"pubsub":
-                found_node = {u"service": url_data[u"path"], u"node": url_data[u"node"]}
-                if u"item" in url_data:
-                    found_node[u"item"] = url_data[u"item"]
+            if url_data["type"] == "pubsub":
+                found_node = {"service": url_data["path"], "node": url_data["node"]}
+                if "item" in url_data:
+                    found_node["item"] = url_data["item"]
                 found_nodes.append(found_node)
 
     def getSubNodes(self, item, depth):
@@ -1376,9 +1368,9 @@
         for data in found_nodes:
             self.getItems(
                 depth + 1,
-                data[u"service"],
-                data[u"node"],
-                [data[u"item"]] if u"item" in data else [],
+                data["service"],
+                data["node"],
+                [data["item"]] if "item" in data else [],
             )
 
     def parseXml(self, item):
@@ -1386,8 +1378,8 @@
             return self.etree.fromstring(item)
         except self.etree.XMLSyntaxError:
             self.disp(
-                _(u"item doesn't looks like XML, you have probably used --only-matching "
-                  u"somewhere before and we have no more XML"),
+                _("item doesn't looks like XML, you have probably used --only-matching "
+                  "somewhere before and we have no more XML"),
                 error=True,
             )
             self.host.quit(C.EXIT_BAD_ARG)
@@ -1410,7 +1402,7 @@
 
             ## filters
 
-            if type_ == u"text":
+            if type_ == "text":
                 if ignore_case:
                     if value.lower() not in item.lower():
                         keep = False
@@ -1422,12 +1414,12 @@
                     # so we raise an error
                     self.host.disp(
                         _(
-                            u"--only-matching used with fixed --text string, are you sure?"
+                            "--only-matching used with fixed --text string, are you sure?"
                         ),
                         error=True,
                     )
                     self.host.quit(C.EXIT_BAD_ARG)
-            elif type_ == u"regex":
+            elif type_ == "regex":
                 flags = self.RE_FLAGS
                 if ignore_case:
                     flags |= re.IGNORECASE
@@ -1438,14 +1430,14 @@
                 if keep and only_matching:
                     item = match.group()
                     item_xml = None
-            elif type_ == u"xpath":
+            elif type_ == "xpath":
                 if item_xml is None:
                     item_xml = self.parseXml(item)
                 try:
                     elts = item_xml.xpath(value, namespaces=self.args.namespace)
                 except self.etree.XPathEvalError as e:
                     self.disp(
-                        _(u"can't use xpath: {reason}").format(reason=e), error=True
+                        _("can't use xpath: {reason}").format(reason=e), error=True
                     )
                     self.host.quit(C.EXIT_BAD_ARG)
                 keep = bool(elts)
@@ -1455,33 +1447,33 @@
                         item = self.etree.tostring(item_xml, encoding="unicode")
                     except TypeError:
                         # we have a string only, not an element
-                        item = unicode(item_xml)
+                        item = str(item_xml)
                         item_xml = None
-            elif type_ == u"python":
+            elif type_ == "python":
                 if item_xml is None:
                     item_xml = self.parseXml(item)
-                cmd_ns = {u"item": item, u"item_xml": item_xml}
+                cmd_ns = {"item": item, "item_xml": item_xml}
                 try:
                     keep = eval(value, cmd_ns)
                 except SyntaxError as e:
-                    self.disp(unicode(e), error=True)
+                    self.disp(str(e), error=True)
                     self.host.quit(C.EXIT_BAD_ARG)
 
             ## flags
 
-            elif type_ == u"ignore-case":
+            elif type_ == "ignore-case":
                 ignore_case = value
-            elif type_ == u"invert":
+            elif type_ == "invert":
                 invert = value
                 #  we need to continue, else loop would end here
                 continue
-            elif type_ == u"dotall":
+            elif type_ == "dotall":
                 dotall = value
-            elif type_ == u"only-matching":
+            elif type_ == "only-matching":
                 only_matching = value
             else:
                 raise exceptions.InternalError(
-                    _(u"unknown filter type {type}").format(type=type_)
+                    _("unknown filter type {type}").format(type=type_)
                 )
 
             if invert:
@@ -1497,7 +1489,7 @@
         @param item(unicode): accepted item
         """
         action = self.args.action
-        if action == u"print" or self.host.verbosity > 0:
+        if action == "print" or self.host.verbosity > 0:
             try:
                 self.output(item)
             except self.etree.XMLSyntaxError:
@@ -1506,10 +1498,10 @@
                 self.disp(item)
         if action in self.EXEC_ACTIONS:
             item_elt = self.parseXml(item)
-            if action == u"exec":
+            if action == "exec":
                 use = {
-                    "service": metadata[u"service"],
-                    "node": metadata[u"node"],
+                    "service": metadata["service"],
+                    "node": metadata["node"],
                     "item": item_elt.get("id"),
                     "profile": self.profile,
                 }
@@ -1523,12 +1515,12 @@
                 cmd_args = self.args.command
 
             self.disp(
-                u"COMMAND: {command}".format(
-                    command=u" ".join([arg_tools.escape(a) for a in cmd_args])
+                "COMMAND: {command}".format(
+                    command=" ".join([arg_tools.escape(a) for a in cmd_args])
                 ),
                 2,
             )
-            if action == u"exec":
+            if action == "exec":
                 ret = subprocess.call(cmd_args)
             else:
                 p = subprocess.Popen(cmd_args, stdin=subprocess.PIPE)
@@ -1538,7 +1530,7 @@
                 self.disp(
                     A.color(
                         C.A_FAILURE,
-                        _(u"executed command failed with exit code {code}").format(
+                        _("executed command failed with exit code {code}").format(
                             code=ret
                         ),
                     )
@@ -1573,16 +1565,16 @@
         if self.args.command:
             if self.args.action not in self.EXEC_ACTIONS:
                 self.parser.error(
-                    _(u"Command can only be used with {actions} actions").format(
-                        actions=u", ".join(self.EXEC_ACTIONS)
+                    _("Command can only be used with {actions} actions").format(
+                        actions=", ".join(self.EXEC_ACTIONS)
                     )
                 )
         else:
             if self.args.action in self.EXEC_ACTIONS:
-                self.parser.error(_(u"you need to specify a command to execute"))
+                self.parser.error(_("you need to specify a command to execute"))
         if not self.args.node:
             # TODO: handle get service affiliations when node is not set
-            self.parser.error(_(u"empty node is not handled yet"))
+            self.parser.error(_("empty node is not handled yet"))
         # to_get is increased on each get and decreased on each answer
         # when it reach 0 again, the command is finished
         self.to_get = 0
@@ -1603,7 +1595,7 @@
             "transform",
             use_pubsub=True,
             pubsub_flags={C.NODE, C.MULTI_ITEMS},
-            help=_(u"modify items of a node using an external command/script"),
+            help=_("modify items of a node using an external command/script"),
         )
         self.need_loop = True
 
@@ -1611,39 +1603,39 @@
         self.parser.add_argument(
             "--apply",
             action="store_true",
-            help=_(u"apply transformation (DEFAULT: do a dry run)"),
+            help=_("apply transformation (DEFAULT: do a dry run)"),
         )
         self.parser.add_argument(
             "--admin",
             action="store_true",
-            help=_(u"do a pubsub admin request, needed to change publisher"),
+            help=_("do a pubsub admin request, needed to change publisher"),
         )
         self.parser.add_argument(
             "-I",
             "--ignore_errors",
             action="store_true",
             help=_(
-                u"if command return a non zero exit code, ignore the item and continue"),
+                "if command return a non zero exit code, ignore the item and continue"),
         )
         self.parser.add_argument(
             "-A",
             "--all",
             action="store_true",
-            help=_(u"get all items by looping over all pages using RSM")
+            help=_("get all items by looping over all pages using RSM")
         )
         self.parser.add_argument(
             "command_path",
-            help=_(u"path to the command to use. Will be called repetitivly with an "
-                   u"item as input. Output (full item XML) will be used as new one. "
-                   u'Return "DELETE" string to delete the item, and "SKIP" to ignore it'),
+            help=_("path to the command to use. Will be called repetitivly with an "
+                   "item as input. Output (full item XML) will be used as new one. "
+                   'Return "DELETE" string to delete the item, and "SKIP" to ignore it'),
         )
 
     def psItemsSendCb(self, item_ids, metadata):
         if item_ids:
-            self.disp(_(u'items published with ids {item_ids}').format(
-                item_ids=u', '.join(item_ids)))
+            self.disp(_('items published with ids {item_ids}').format(
+                item_ids=', '.join(item_ids)))
         else:
-            self.disp(_(u'items published'))
+            self.disp(_('items published'))
         if self.args.all:
             return self.handleNextPage(metadata)
         else:
@@ -1656,30 +1648,30 @@
         @param metadata(dict): metadata as returned by psItemsGet
         """
         try:
-            last = metadata[u'rsm_last']
-            index = int(metadata[u'rsm_index'])
-            count = int(metadata[u'rsm_count'])
+            last = metadata['rsm_last']
+            index = int(metadata['rsm_index'])
+            count = int(metadata['rsm_count'])
         except KeyError:
-            self.disp(_(u"Can't retrieve all items, RSM metadata not available"),
+            self.disp(_("Can't retrieve all items, RSM metadata not available"),
                       error=True)
             self.host.quit(C.EXIT_MISSING_FEATURE)
         except ValueError as e:
-            self.disp(_(u"Can't retrieve all items, bad RSM metadata: {msg}")
+            self.disp(_("Can't retrieve all items, bad RSM metadata: {msg}")
                       .format(msg=e), error=True)
             self.host.quit(C.EXIT_ERROR)
 
         if index + self.args.rsm_max >= count:
-            self.disp(_(u'All items transformed'))
+            self.disp(_('All items transformed'))
             self.host.quit(0)
 
-        self.disp(_(u'Retrieving next page ({page_idx}/{page_total})').format(
+        self.disp(_('Retrieving next page ({page_idx}/{page_total})').format(
             page_idx = int(index/self.args.rsm_max) + 1,
             page_total = int(count/self.args.rsm_max),
             )
         )
 
         extra = self.getPubsubExtra()
-        extra[u'rsm_after'] = last
+        extra['rsm_after'] = last
         self.host.bridge.psItemsGet(
             self.args.service,
             self.args.node,
@@ -1691,7 +1683,7 @@
             callback=self.psItemsGetCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't retrieve items: {}"),
+                msg=_("can't retrieve items: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -1708,8 +1700,8 @@
                 item_id = item_elt.get('id')
                 if item_id in self.items_ids:
                     self.disp(_(
-                        u"Duplicate found on item {item_id}, we have probably handled "
-                        u"all items.").format(item_id=item_id))
+                        "Duplicate found on item {item_id}, we have probably handled "
+                        "all items.").format(item_id=item_id))
                     self.host.quit()
                 self.items_ids.append(item_id)
 
@@ -1720,13 +1712,13 @@
             except OSError as e:
                 exit_code = C.EXIT_CMD_NOT_FOUND if e.errno == 2 else C.EXIT_ERROR
                 e = str(e).decode('utf-8', errors="ignore")
-                self.disp(u"Can't execute the command: {msg}".format(msg=e), error=True)
+                self.disp("Can't execute the command: {msg}".format(msg=e), error=True)
                 self.host.quit(exit_code)
             cmd_std_out, cmd_std_err = p.communicate(item.encode("utf-8"))
             ret = p.wait()
             if ret != 0:
-                self.disp(u"The command returned a non zero status while parsing the "
-                          u"following item:\n\n{item}".format(item=item), error=True)
+                self.disp("The command returned a non zero status while parsing the "
+                          "following item:\n\n{item}".format(item=item), error=True)
                 if self.args.ignore_errors:
                     continue
                 else:
@@ -1738,7 +1730,7 @@
             if cmd_std_out == "DELETE":
                 item_elt, __ = xml_tools.etreeParse(self, item)
                 item_id = item_elt.get('id')
-                self.disp(_(u"Deleting item {item_id}").format(item_id=item_id))
+                self.disp(_("Deleting item {item_id}").format(item_id=item_id))
                 if self.args.apply:
                     # FIXME: we don't wait for item to be retracted which can cause
                     #        trouble in case of error just before the end of the command
@@ -1753,7 +1745,7 @@
                         self.profile,
                         errback=partial(
                             self.errback,
-                            msg=_(u"can't delete item [%s]: {}" % item_id),
+                            msg=_("can't delete item [%s]: {}" % item_id),
                             exit_code=C.EXIT_BRIDGE_ERRBACK,
                         ),
                     )
@@ -1761,19 +1753,19 @@
             elif cmd_std_out == "SKIP":
                 item_elt, __ = xml_tools.etreeParse(self, item)
                 item_id = item_elt.get('id')
-                self.disp(_(u"Skipping item {item_id}").format(item_id=item_id))
+                self.disp(_("Skipping item {item_id}").format(item_id=item_id))
                 continue
             element, etree = xml_tools.etreeParse(self, cmd_std_out)
 
             # at this point command has been run and we have a etree.Element object
             if element.tag not in ("item", "{http://jabber.org/protocol/pubsub}item"):
-                self.disp(u"your script must return a whole item, this is not:\n{xml}"
+                self.disp("your script must return a whole item, this is not:\n{xml}"
                     .format(xml=etree.tostring(element, encoding="unicode")), error=True)
                 self.host.quit(C.EXIT_DATA_ERROR)
 
             if not self.args.apply:
                 # we have a dry run, we just display filtered items
-                serialised = etree.tostring(element, encoding=u'unicode',
+                serialised = etree.tostring(element, encoding='unicode',
                                             pretty_print=True)
                 self.disp(serialised)
             else:
@@ -1790,12 +1782,12 @@
                     self.args.service,
                     self.args.node,
                     new_items,
-                    u"",
+                    "",
                     self.profile,
                     callback=partial(self.psItemsSendCb, metadata=metadata),
                     errback=partial(
                         self.errback,
-                        msg=_(u"can't send item: {}"),
+                        msg=_("can't send item: {}"),
                         exit_code=C.EXIT_BRIDGE_ERRBACK,
                     ),
                 )
@@ -1804,12 +1796,12 @@
                     self.args.service,
                     self.args.node,
                     new_items,
-                    u"",
+                    "",
                     self.profile,
                     callback=partial(self.psItemsSendCb, metadata=metadata),
                     errback=partial(
                         self.errback,
-                        msg=_(u"can't send item: {}"),
+                        msg=_("can't send item: {}"),
                         exit_code=C.EXIT_BRIDGE_ERRBACK,
                     ),
                 )
@@ -1820,11 +1812,11 @@
             self.items_ids = []
             self.disp(A.color(
                 A.FG_RED, A.BOLD,
-                u'/!\\ "--all" should be used with "--order-by creation" /!\\\n',
+                '/!\\ "--all" should be used with "--order-by creation" /!\\\n',
                 A.RESET,
-                u"We'll update items, so order may change during transformation,\n"
-                u"we'll try to mitigate that by stopping on first duplicate,\n"
-                u"but this method is not safe, and some items may be missed.\n---\n"))
+                "We'll update items, so order may change during transformation,\n"
+                "we'll try to mitigate that by stopping on first duplicate,\n"
+                "but this method is not safe, and some items may be missed.\n---\n"))
         else:
             self.check_duplicates = False
         self.host.bridge.psItemsGet(
@@ -1838,7 +1830,7 @@
             callback=self.psItemsGetCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't retrieve items: {}"),
+                msg=_("can't retrieve items: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -1853,7 +1845,7 @@
             use_profile=False,
             use_pubsub=True,
             pubsub_flags={C.NODE, C.SINGLE_ITEM},
-            help=_(u"build URI"),
+            help=_("build URI"),
         )
         self.need_loop = True
 
@@ -1861,9 +1853,8 @@
         self.parser.add_argument(
             "-p",
             "--profile",
-            type=base.unicode_decoder,
             default=C.PROF_KEY_DEFAULT,
-            help=_(u"profile (used when no server is specified)"),
+            help=_("profile (used when no server is specified)"),
         )
 
     def display_uri(self, jid_):
@@ -1877,19 +1868,19 @@
                 key = "path"
             if value:
                 uri_args[key] = value
-        self.disp(uri.buildXMPPUri(u"pubsub", **uri_args))
+        self.disp(uri.buildXMPPUri("pubsub", **uri_args))
         self.host.quit()
 
     def start(self):
         if not self.args.service:
             self.host.bridge.asyncGetParamA(
-                u"JabberID",
-                u"Connection",
+                "JabberID",
+                "Connection",
                 profile_key=self.args.profile,
                 callback=self.display_uri,
                 errback=partial(
                     self.errback,
-                    msg=_(u"can't retrieve jid: {}"),
+                    msg=_("can't retrieve jid: {}"),
                     exit_code=C.EXIT_BRIDGE_ERRBACK,
                 ),
             )
@@ -1905,7 +1896,7 @@
             "create",
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"create a Pubsub hook"),
+            help=_("create a Pubsub hook"),
         )
         self.need_loop = True
 
@@ -1913,29 +1904,28 @@
         self.parser.add_argument(
             "-t",
             "--type",
-            default=u"python",
+            default="python",
             choices=("python", "python_file", "python_code"),
-            help=_(u"hook type"),
+            help=_("hook type"),
         )
         self.parser.add_argument(
             "-P",
             "--persistent",
             action="store_true",
-            help=_(u"make hook persistent across restarts"),
+            help=_("make hook persistent across restarts"),
         )
         self.parser.add_argument(
             "hook_arg",
-            type=base.unicode_decoder,
-            help=_(u"argument of the hook (depend of the type)"),
+            help=_("argument of the hook (depend of the type)"),
         )
 
     @staticmethod
     def checkArgs(self):
-        if self.args.type == u"python_file":
+        if self.args.type == "python_file":
             self.args.hook_arg = os.path.abspath(self.args.hook_arg)
             if not os.path.isfile(self.args.hook_arg):
                 self.parser.error(
-                    _(u"{path} is not a file").format(path=self.args.hook_arg)
+                    _("{path} is not a file").format(path=self.args.hook_arg)
                 )
 
     def start(self):
@@ -1950,7 +1940,7 @@
             callback=self.host.quit,
             errback=partial(
                 self.errback,
-                msg=_(u"can't create hook: {}"),
+                msg=_("can't create hook: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -1964,7 +1954,7 @@
             "delete",
             use_pubsub=True,
             pubsub_flags={C.NODE},
-            help=_(u"delete a Pubsub hook"),
+            help=_("delete a Pubsub hook"),
         )
         self.need_loop = True
 
@@ -1972,24 +1962,23 @@
         self.parser.add_argument(
             "-t",
             "--type",
-            default=u"",
+            default="",
             choices=("", "python", "python_file", "python_code"),
-            help=_(u"hook type to remove, empty to remove all (DEFAULT: remove all)"),
+            help=_("hook type to remove, empty to remove all (DEFAULT: remove all)"),
         )
         self.parser.add_argument(
             "-a",
             "--arg",
             dest="hook_arg",
-            type=base.unicode_decoder,
-            default=u"",
+            default="",
             help=_(
-                u"argument of the hook to remove, empty to remove all (DEFAULT: remove all)"
+                "argument of the hook to remove, empty to remove all (DEFAULT: remove all)"
             ),
         )
 
     def psHookRemoveCb(self, nb_deleted):
         self.disp(
-            _(u"{nb_deleted} hook(s) have been deleted").format(nb_deleted=nb_deleted)
+            _("{nb_deleted} hook(s) have been deleted").format(nb_deleted=nb_deleted)
         )
         self.host.quit()
 
@@ -2004,7 +1993,7 @@
             callback=self.psHookRemoveCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't delete hook: {}"),
+                msg=_("can't delete hook: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )
@@ -2017,7 +2006,7 @@
             host,
             "list",
             use_output=C.OUTPUT_LIST_DICT,
-            help=_(u"list hooks of a profile"),
+            help=_("list hooks of a profile"),
         )
         self.need_loop = True
 
@@ -2026,7 +2015,7 @@
 
     def psHookListCb(self, data):
         if not data:
-            self.disp(_(u"No hook found."))
+            self.disp(_("No hook found."))
         self.output(data)
         self.host.quit()
 
@@ -2036,7 +2025,7 @@
             callback=self.psHookListCb,
             errback=partial(
                 self.errback,
-                msg=_(u"can't list hooks: {}"),
+                msg=_("can't list hooks: {}"),
                 exit_code=C.EXIT_BRIDGE_ERRBACK,
             ),
         )