diff sat_frontends/jp/cmd_pubsub.py @ 3568:04283582966f

core, frontends: fix invalid translatable strings. Some f-strings where used in translatable text, this has been fixed by using explicit `format()` call (using a script based on `tokenize`). As tokenize messes with spaces, a reformating tool (`black`) has been applied to some files afterwards.
author Goffi <goffi@goffi.org>
date Mon, 14 Jun 2021 18:35:12 +0200
parents 62f490eff51c
children 5f65f4e9f8cb
line wrap: on
line diff
--- a/sat_frontends/jp/cmd_pubsub.py	Mon Jun 14 12:19:21 2021 +0200
+++ b/sat_frontends/jp/cmd_pubsub.py	Mon Jun 14 18:35:12 2021 +0200
@@ -82,10 +82,10 @@
                 self.profile,
             )
         except BridgeException as e:
-            if e.condition == 'item-not-found':
+            if e.condition == "item-not-found":
                 self.disp(
                     f"The node {self.args.node} doesn't exist on {self.args.service}",
-                    error=True
+                    error=True,
                 )
                 self.host.quit(C.EXIT_NOT_FOUND)
             else:
@@ -155,7 +155,7 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(msg=_(f"can't create node: {e}"), error=True)
+            self.disp(msg=_("can't create node: {e}").format(e=e), error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             if self.host.verbosity:
@@ -167,7 +167,6 @@
 
 
 class NodePurge(base.CommandBase):
-
     def __init__(self, host):
         super(NodePurge, self).__init__(
             host,
@@ -189,12 +188,14 @@
         if not self.args.force:
             if not self.args.service:
                 message = _(
-                    f"Are you sure to purge PEP node [{self.args.node}]? This will "
-                    f"delete ALL items from it!")
+                    "Are you sure to purge PEP node [{node}]? This will "
+                    "delete ALL items from it!"
+                ).format(node=self.args.node)
             else:
                 message = _(
-                    f"Are you sure to delete node [{self.args.node}] on service "
-                    f"[{self.args.service}]? This will delete ALL items from it!")
+                    "Are you sure to delete node [{node}] on service "
+                    "[{service}]? This will delete ALL items from it!"
+                ).format(node=self.args.node, service=self.args.service)
             await self.host.confirmOrQuit(message, _("node purge cancelled"))
 
         try:
@@ -204,10 +205,10 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(msg=_(f"can't purge node: {e}"), error=True)
+            self.disp(msg=_("can't purge node: {e}").format(e=e), error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
-            self.disp(_(f"node [{self.args.node}] purged successfully"))
+            self.disp(_("node [{node}] purged successfully").format(node=self.args.node))
             self.host.quit()
 
 
@@ -233,10 +234,13 @@
     async def start(self):
         if not self.args.force:
             if not self.args.service:
-                message = _(f"Are you sure to delete PEP node [{self.args.node}] ?")
+                message = _("Are you sure to delete PEP node [{node}] ?").format(
+                    node=self.args.node
+                )
             else:
-                message = _(f"Are you sure to delete node [{self.args.node}] on "
-                            f"service [{self.args.service}]?")
+                message = _(
+                    "Are you sure to delete node [{node}] on " "service [{service}]?"
+                ).format(node=self.args.node, service=self.args.service)
             await self.host.confirmOrQuit(message, _("node deletion cancelled"))
 
         try:
@@ -249,7 +253,7 @@
             self.disp(f"can't delete node: {e}", error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
-            self.disp(_(f"node [{self.args.node}] deleted successfully"))
+            self.disp(_("node [{node}] deleted successfully").format(node=self.args.node))
             self.host.quit()
 
 
@@ -307,7 +311,6 @@
 
 
 class NodeImport(base.CommandBase):
-
     def __init__(self, host):
         super(NodeImport, self).__init__(
             host,
@@ -326,16 +329,20 @@
         self.parser.add_argument(
             "import_file",
             type=argparse.FileType(),
-            help=_("path to the XML file with data to import. The file must contain "
-                   "whole XML of each item to import."),
+            help=_(
+                "path to the XML file with data to import. The file must contain "
+                "whole XML of each item to import."
+            ),
         )
 
     async def start(self):
         try:
-            element, etree = xml_tools.etreeParse(self, self.args.import_file,
-                                                  reraise=True)
+            element, etree = xml_tools.etreeParse(
+                self, self.args.import_file, reraise=True
+            )
         except Exception as e:
             from lxml.etree import XMLSyntaxError
+
             if isinstance(e, XMLSyntaxError) and e.code == 5:
                 # we have extra content, this probaby means that item are not wrapped
                 # so we wrap them here and try again
@@ -343,14 +350,15 @@
                 xml_buf = "<import>" + self.args.import_file.read() + "</import>"
                 element, etree = xml_tools.etreeParse(self, xml_buf)
 
-        # we reverse element as we expect to have most recently published element first
-        # TODO: make this more explicit and add an option
+                # we reverse element as we expect to have most recently published element first
+                # TODO: make this more explicit and add an option
         element[:] = reversed(element)
 
-        if not all([i.tag == '{http://jabber.org/protocol/pubsub}item' for i in element]):
+        if not all([i.tag == "{http://jabber.org/protocol/pubsub}item" for i in element]):
             self.disp(
                 _("You are not using list of pubsub items, we can't import this file"),
-                error=True)
+                error=True,
+            )
             self.host.quit(C.EXIT_DATA_ERROR)
             return
 
@@ -358,8 +366,12 @@
         if self.args.admin:
             method = self.host.bridge.psAdminItemsSend
         else:
-            self.disp(_("Items are imported without using admin mode, publisher can't "
-                        "be changed"))
+            self.disp(
+                _(
+                    "Items are imported without using admin mode, publisher can't "
+                    "be changed"
+                )
+            )
             method = self.host.bridge.psItemsSend
 
         try:
@@ -375,10 +387,13 @@
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             if items_ids:
-                self.disp(_('items published with id(s) {items_ids}').format(
-                    items_ids=', '.join(items_ids)))
+                self.disp(
+                    _("items published with id(s) {items_ids}").format(
+                        items_ids=", ".join(items_ids)
+                    )
+                )
             else:
-                self.disp(_('items published'))
+                self.disp(_("items published"))
             self.host.quit()
 
 
@@ -645,8 +660,9 @@
         try:
             from lxml import etree
         except ImportError:
-            self.disp('lxml module must be installed to use edit, please install it '
-                      '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)
@@ -659,7 +675,9 @@
                 etree.tostring(schema_elt, encoding="utf-8", pretty_print=True)
             )
             content_file_obj.seek(0)
-        await self.runEditor("pubsub_schema_editor_args", content_file_path, content_file_obj)
+        await self.runEditor(
+            "pubsub_schema_editor_args", content_file_path, content_file_obj
+        )
 
     async def start(self):
         try:
@@ -669,7 +687,7 @@
                 self.profile,
             )
         except BridgeException as e:
-            if e.condition == 'item-not-found' or e.classname=="NotFound":
+            if e.condition == "item-not-found" or e.classname == "NotFound":
                 schema = ""
             else:
                 self.disp(f"can't edit schema: {e}", error=True)
@@ -702,7 +720,7 @@
                 self.profile,
             )
         except BridgeException as e:
-            if e.condition == 'item-not-found' or e.classname=="NotFound":
+            if e.condition == "item-not-found" or e.classname == "NotFound":
                 schema = None
             else:
                 self.disp(f"can't get schema: {e}", error=True)
@@ -772,7 +790,7 @@
         extra = {}
         publish_options = NodeCreate.get_config_options(self.args)
         if publish_options:
-            extra['publish_options'] = publish_options
+            extra["publish_options"] = publish_options
 
         try:
             published_id = await self.host.bridge.psItemSend(
@@ -784,12 +802,12 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(_(f"can't send item: {e}"), error=True)
+            self.disp(_("can't send item: {e}").format(e=e), error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             if published_id:
                 if self.args.quiet:
-                    self.disp(published_id, end='')
+                    self.disp(published_id, end="")
                 else:
                     self.disp(f"Item published at {published_id}")
             else:
@@ -833,10 +851,10 @@
                 )
             )
         except BridgeException as e:
-            if e.condition == 'item-not-found' or e.classname=="NotFound":
+            if e.condition == "item-not-found" or e.classname == "NotFound":
                 self.disp(
                     f"The node {self.args.node} doesn't exist on {self.args.service}",
-                    error=True
+                    error=True,
                 )
                 self.host.quit(C.EXIT_NOT_FOUND)
             else:
@@ -846,7 +864,7 @@
             self.disp(f"Internal error: {e}", error=True)
             self.host.quit(C.EXIT_INTERNAL_ERROR)
         else:
-            await self.output(ps_result['items'])
+            await self.output(ps_result["items"])
             self.host.quit(C.EXIT_OK)
 
 
@@ -886,10 +904,10 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(_(f"can't delete item: {e}"), error=True)
+            self.disp(_("can't delete item: {e}").format(e=e), error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
-            self.disp(_(f"item {self.args.item} has been deleted"))
+            self.disp(_("item {item} has been deleted").format(item=self.args.item))
             self.host.quit(C.EXIT_OK)
 
 
@@ -928,8 +946,9 @@
         try:
             from lxml import etree
         except ImportError:
-            self.disp('lxml module must be installed to use edit, please install it '
-                      '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)
@@ -939,7 +958,7 @@
                 service, node, 1, items, "", {}, self.profile
             )
         )
-        item_raw = ps_result['items'][0]
+        item_raw = ps_result["items"][0]
         parser = etree.XMLParser(remove_blank_text=True, recover=True)
         item_elt = etree.fromstring(item_raw, parser)
         item_id = item_elt.get("id")
@@ -951,17 +970,18 @@
         return etree.tostring(payload, encoding="unicode", pretty_print=True), item_id
 
     async def start(self):
-        (self.pubsub_service,
-         self.pubsub_node,
-         self.pubsub_item,
-         content_file_path,
-         content_file_obj) = await self.getItemPath()
+        (
+            self.pubsub_service,
+            self.pubsub_node,
+            self.pubsub_item,
+            content_file_path,
+            content_file_obj,
+        ) = await self.getItemPath()
         await self.runEditor("pubsub_editor_args", content_file_path, content_file_obj)
         self.host.quit()
 
 
 class Rename(base.CommandBase):
-
     def __init__(self, host):
         base.CommandBase.__init__(
             self,
@@ -973,10 +993,7 @@
         )
 
     def add_parser_options(self):
-        self.parser.add_argument(
-            "new_id",
-            help=_("new item id to use")
-        )
+        self.parser.add_argument("new_id", help=_("new item id to use"))
 
     async def start(self):
         try:
@@ -988,9 +1005,7 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(
-                f"can't rename item: {e}", error=True
-            )
+            self.disp(f"can't rename item: {e}", error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             self.disp("Item renamed")
@@ -1021,7 +1036,7 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(_(f"can't subscribe to node: {e}"), error=True)
+            self.disp(_("can't subscribe to node: {e}").format(e=e), error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             self.disp(_("subscription done"), 1)
@@ -1055,7 +1070,7 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(_(f"can't unsubscribe from node: {e}"), error=True)
+            self.disp(_("can't unsubscribe from node: {e}").format(e=e), error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             self.disp(_("subscription removed"), 1)
@@ -1084,7 +1099,7 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(_(f"can't retrieve subscriptions: {e}"), error=True)
+            self.disp(_("can't retrieve subscriptions: {e}").format(e=e), error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             await self.output(subscriptions)
@@ -1113,9 +1128,7 @@
                 self.profile,
             )
         except Exception as e:
-            self.disp(
-                f"can't get node affiliations: {e}", error=True
-            )
+            self.disp(f"can't get node affiliations: {e}", error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             await self.output(affiliations)
@@ -1169,16 +1182,20 @@
             "--max-depth",
             type=int,
             default=0,
-            help=_("maximum depth of recursion (will search linked nodes if > 0, "
-                   "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=_("maximum number of items to get per node ({} to get all items, "
-                   "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",
@@ -1233,9 +1250,10 @@
             dest="filters",
             type=filter_python,
             metavar="PYTHON_CODE",
-            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'
+            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"
             ),
         )
 
@@ -1362,8 +1380,10 @@
             return self.etree.fromstring(item)
         except self.etree.XMLSyntaxError:
             self.disp(
-                _("item doesn't looks like XML, you have probably used --only-matching "
-                  "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)
@@ -1397,9 +1417,7 @@
                     # doesn't really make sens to keep a fixed string
                     # so we raise an error
                     self.host.disp(
-                        _(
-                            "--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)
@@ -1420,9 +1438,7 @@
                 try:
                     elts = item_xml.xpath(value, namespaces=self.args.namespace)
                 except self.etree.XPathEvalError as e:
-                    self.disp(
-                        _("can't use xpath: {reason}").format(reason=e), error=True
-                    )
+                    self.disp(_("can't use xpath: {reason}").format(reason=e), error=True)
                     self.host.quit(C.EXIT_BAD_ARG)
                 keep = bool(elts)
                 if keep and only_matching:
@@ -1436,18 +1452,14 @@
             elif type_ == "python":
                 if item_xml is None:
                     item_xml = self.parseXml(item)
-                cmd_ns = {
-                    "etree": self.etree,
-                    "item": item,
-                    "item_xml": item_xml
-                    }
+                cmd_ns = {"etree": self.etree, "item": item, "item_xml": item_xml}
                 try:
                     keep = eval(value, cmd_ns)
                 except SyntaxError as e:
                     self.disp(str(e), error=True)
                     self.host.quit(C.EXIT_BAD_ARG)
 
-            ## flags
+                    ## flags
 
             elif type_ == "ignore-case":
                 ignore_case = value
@@ -1512,15 +1524,14 @@
                 p = await asyncio.create_subprocess_exec(*cmd_args)
                 ret = await p.wait()
             else:
-                p = await asyncio.create_subprocess_exec(*cmd_args,
-                                                         stdin=subprocess.PIPE)
+                p = await asyncio.create_subprocess_exec(*cmd_args, stdin=subprocess.PIPE)
                 await p.communicate(item.encode(sys.getfilesystemencoding()))
                 ret = p.returncode
             if ret != 0:
                 self.disp(
                     A.color(
                         C.A_FAILURE,
-                        _(f"executed command failed with exit code {ret}"),
+                        _("executed command failed with exit code {ret}").format(ret=ret),
                     )
                 )
 
@@ -1533,7 +1544,7 @@
         @param depth(int): current depth level
             0 for first node, 1 for first children, and so on
         """
-        for item in ps_result['items']:
+        for item in ps_result["items"]:
             if depth < self.args.max_depth:
                 await self.getSubNodes(item, depth)
             keep, item = self.filter(item)
@@ -1541,7 +1552,7 @@
                 continue
             await self.doItemAction(item, ps_result)
 
-        #  we check if we got all getItems results
+            #  we check if we got all getItems results
         self.to_get -= 1
         if self.to_get == 0:
             # yes, we can quit
@@ -1562,8 +1573,8 @@
         if not self.args.node:
             # TODO: handle get service affiliations when node is not set
             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
+            # 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
         self._etree = None
         if self.args.filters is None:
@@ -1601,27 +1612,33 @@
             "--ignore-errors",
             action="store_true",
             help=_(
-                "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=_("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=_("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'),
+            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'
+            ),
         )
 
     async def psItemsSendCb(self, item_ids, metadata):
         if item_ids:
-            self.disp(_('items published with ids {item_ids}').format(
-                item_ids=', '.join(item_ids)))
+            self.disp(
+                _("items published with ids {item_ids}").format(
+                    item_ids=", ".join(item_ids)
+                )
+            )
         else:
-            self.disp(_('items published'))
+            self.disp(_("items published"))
         if self.args.all:
             return await self.handleNextPage(metadata)
         else:
@@ -1634,30 +1651,34 @@
         @param metadata(dict): metadata as returned by psItemsGet
         """
         try:
-            last = metadata['rsm']['last']
-            index = int(metadata['rsm']['index'])
-            count = int(metadata['rsm']['count'])
+            last = metadata["rsm"]["last"]
+            index = int(metadata["rsm"]["index"])
+            count = int(metadata["rsm"]["count"])
         except KeyError:
-            self.disp(_("Can't retrieve all items, RSM metadata not available"),
-                      error=True)
+            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(_("Can't retrieve all items, bad RSM metadata: {msg}")
-                      .format(msg=e), error=True)
+            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(_('All items transformed'))
+            self.disp(_("All items transformed"))
             self.host.quit(0)
 
-        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),
+        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['rsm_after'] = last
+        extra["rsm_after"] = last
         try:
             ps_result = await data_format.deserialise(
                 self.host.bridge.psItemsGet(
@@ -1671,36 +1692,36 @@
                 )
             )
         except Exception as e:
-            self.disp(
-                f"can't retrieve items: {e}", error=True
-            )
+            self.disp(f"can't retrieve items: {e}", error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
             await self.psItemsGetCb(ps_result)
 
     async def psItemsGetCb(self, ps_result):
-        encoding = 'utf-8'
+        encoding = "utf-8"
         new_items = []
 
-        for item in ps_result['items']:
+        for item in ps_result["items"]:
             if self.check_duplicates:
                 # this is used when we are not ordering by creation
                 # to avoid infinite loop
                 item_elt, __ = xml_tools.etreeParse(self, item)
-                item_id = item_elt.get('id')
+                item_id = item_elt.get("id")
                 if item_id in self.items_ids:
-                    self.disp(_(
-                        "Duplicate found on item {item_id}, we have probably handled "
-                        "all items.").format(item_id=item_id))
+                    self.disp(
+                        _(
+                            "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)
 
-            # we launch the command to filter the item
+                # we launch the command to filter the item
             try:
                 p = await asyncio.create_subprocess_exec(
-                    self.args.command_path,
-                    stdin=subprocess.PIPE,
-                    stdout=subprocess.PIPE)
+                    self.args.command_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE
+                )
             except OSError as e:
                 exit_code = C.EXIT_CMD_NOT_FOUND if e.errno == 2 else C.EXIT_ERROR
                 self.disp(f"Can't execute the command: {e}", error=True)
@@ -1709,20 +1730,23 @@
             cmd_std_out, cmd_std_err = await p.communicate(item.encode(encoding))
             ret = p.returncode
             if ret != 0:
-                self.disp(f"The command returned a non zero status while parsing the "
-                          f"following item:\n\n{item}", error=True)
+                self.disp(
+                    f"The command returned a non zero status while parsing the "
+                    f"following item:\n\n{item}",
+                    error=True,
+                )
                 if self.args.ignore_errors:
                     continue
                 else:
                     self.host.quit(C.EXIT_CMD_ERROR)
             if cmd_std_err is not None:
-                cmd_std_err = cmd_std_err.decode(encoding, errors='ignore')
+                cmd_std_err = cmd_std_err.decode(encoding, errors="ignore")
                 self.disp(cmd_std_err, error=True)
             cmd_std_out = cmd_std_out.decode(encoding).strip()
             if cmd_std_out == "DELETE":
                 item_elt, __ = xml_tools.etreeParse(self, item)
-                item_id = item_elt.get('id')
-                self.disp(_(f"Deleting item {item_id}"))
+                item_id = item_elt.get("id")
+                self.disp(_("Deleting item {item_id}").format(item_id=item_id))
                 if self.args.apply:
                     try:
                         await self.host.bridge.psItemRetract(
@@ -1733,28 +1757,31 @@
                             self.profile,
                         )
                     except Exception as e:
-                        self.disp(
-                            f"can't delete item {item_id}: {e}", error=True
-                        )
+                        self.disp(f"can't delete item {item_id}: {e}", error=True)
                         self.host.quit(C.EXIT_BRIDGE_ERRBACK)
                 continue
             elif cmd_std_out == "SKIP":
                 item_elt, __ = xml_tools.etreeParse(self, item)
-                item_id = item_elt.get('id')
+                item_id = item_elt.get("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("your script must return a whole item, this is not:\n{xml}"
-                    .format(xml=etree.tostring(element, encoding="unicode")), error=True)
+                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='unicode',
-                                            pretty_print=True)
+                serialised = etree.tostring(
+                    element, encoding="unicode", pretty_print=True
+                )
                 self.disp(serialised)
             else:
                 new_items.append(etree.tostring(element, encoding="unicode"))
@@ -1788,13 +1815,17 @@
         if self.args.all and self.args.order_by != C.ORDER_BY_CREATION:
             self.check_duplicates = True
             self.items_ids = []
-            self.disp(A.color(
-                A.FG_RED, A.BOLD,
-                '/!\\ "--all" should be used with "--order-by creation" /!\\\n',
-                A.RESET,
-                "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"))
+            self.disp(
+                A.color(
+                    A.FG_RED,
+                    A.BOLD,
+                    '/!\\ "--all" should be used with "--order-by creation" /!\\\n',
+                    A.RESET,
+                    "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
 
@@ -1855,9 +1886,7 @@
         if not self.args.service:
             try:
                 jid_ = await self.host.bridge.asyncGetParamA(
-                    "JabberID",
-                    "Connection",
-                    profile_key=self.args.profile
+                    "JabberID", "Connection", profile_key=self.args.profile
                 )
             except Exception as e:
                 self.disp(f"can't retrieve jid: {e}", error=True)
@@ -1968,7 +1997,9 @@
             self.disp(f"can't delete hook: {e}", error=True)
             self.host.quit(C.EXIT_BRIDGE_ERRBACK)
         else:
-            self.disp(_(f"{nb_deleted} hook(s) have been deleted"))
+            self.disp(
+                _("{nb_deleted} hook(s) have been deleted").format(nb_deleted=nb_deleted)
+            )
             self.host.quit()