diff sat_frontends/jp/cmd_ticket.py @ 3040:fee60f17ebac

jp: jp asyncio port: /!\ this commit is huge. Jp is temporarily not working with `dbus` bridge /!\ This patch implements the port of jp to asyncio, so it is now correctly using the bridge asynchronously, and it can be used with bridges like `pb`. This also simplify the code, notably for things which were previously implemented with many callbacks (like pagination with RSM). During the process, some behaviours have been modified/fixed, in jp and backends, check diff for details.
author Goffi <goffi@goffi.org>
date Wed, 25 Sep 2019 08:56:41 +0200
parents ab2696e34d29
children 9d0df638c8b4
line wrap: on
line diff
--- a/sat_frontends/jp/cmd_ticket.py	Wed Sep 25 08:53:38 2019 +0200
+++ b/sat_frontends/jp/cmd_ticket.py	Wed Sep 25 08:56:41 2019 +0200
@@ -22,7 +22,6 @@
 from sat.core.i18n import _
 from sat_frontends.jp import common
 from sat_frontends.jp.constants import Const as C
-from functools import partial
 import json
 import os
 
@@ -44,37 +43,31 @@
             use_output=C.OUTPUT_LIST_XMLUI,
             help=_("get tickets"),
         )
-        self.need_loop = True
 
     def add_parser_options(self):
         pass
 
-    def ticketsGetCb(self, tickets_data):
-        self.output(tickets_data[0])
-        self.host.quit(C.EXIT_OK)
-
-    def getTickets(self):
-        self.host.bridge.ticketsGet(
-            self.args.service,
-            self.args.node,
-            self.args.max,
-            self.args.items,
-            "",
-            self.getPubsubExtra(),
-            self.profile,
-            callback=self.ticketsGetCb,
-            errback=partial(
-                self.errback,
-                msg=_("can't get tickets: {}"),
-                exit_code=C.EXIT_BRIDGE_ERRBACK,
-            ),
-        )
-
-    def start(self):
-        common.URIFinder(self, os.getcwd(), "tickets", self.getTickets, meta_map={})
+    async def start(self):
+        await common.fill_well_known_uri(self, os.getcwd(), "tickets", meta_map={})
+        try:
+            tickets_data = await self.host.bridge.ticketsGet(
+                self.args.service,
+                self.args.node,
+                self.args.max,
+                self.args.items,
+                "",
+                self.getPubsubExtra(),
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't get tickets: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            await self.output(tickets_data[0])
+            self.host.quit(C.EXIT_OK)
 
 
-class Import(base.CommandAnswering):
+class Import(base.CommandBase):
     # TODO: factorize with blog/import
 
     def __init__(self, host):
@@ -82,9 +75,9 @@
             host,
             "import",
             use_progress=True,
+            use_verbose=True,
             help=_("import tickets from external software/dataset"),
         )
-        self.need_loop = True
 
     def add_parser_options(self):
         self.parser.add_argument(
@@ -109,7 +102,8 @@
             default=[],
             metavar=("IMPORTED_FIELD", "DEST_FIELD"),
             help=_(
-                "specified field in import data will be put in dest field (default: use same field name, or ignore if it doesn't exist)"
+                "specified field in import data will be put in dest field (default: use "
+                "same field name, or ignore if it doesn't exist)"
             ),
         )
         self.parser.add_argument(
@@ -125,97 +119,92 @@
             default="",
             metavar="PUBSUB_NODE",
             help=_(
-                "PubSub node where the items must be uploaded (default: tickets' defaults)"
+                "PubSub node where the items must be uploaded (default: tickets' "
+                "defaults)"
             ),
         )
         self.parser.add_argument(
             "location",
             nargs="?",
             help=_(
-                "importer data location (see importer description), nothing to show importer description"
+                "importer data location (see importer description), nothing to show "
+                "importer description"
             ),
         )
 
-    def onProgressStarted(self, metadata):
+    async def onProgressStarted(self, metadata):
         self.disp(_("Tickets upload started"), 2)
 
-    def onProgressFinished(self, metadata):
+    async def onProgressFinished(self, metadata):
         self.disp(_("Tickets uploaded successfully"), 2)
 
-    def onProgressError(self, error_msg):
-        self.disp(_("Error while uploading tickets: {}").format(error_msg), error=True)
+    async def onProgressError(self, error_msg):
+        self.disp(_(f"Error while uploading tickets: {error_msg}"), error=True)
 
-    def error(self, failure):
-        self.disp(
-            _("Error while trying to upload tickets: {reason}").format(reason=failure),
-            error=True,
-        )
-        self.host.quit(1)
-
-    def start(self):
+    async def start(self):
         if self.args.location is None:
+            # no location, the list of importer or description is requested
             for name in ("option", "service", "node"):
                 if getattr(self.args, name):
                     self.parser.error(
-                        _(
-                            "{name} argument can't be used without location argument"
-                        ).format(name=name)
-                    )
+                        _(f"{name} argument can't be used without location argument"))
             if self.args.importer is None:
                 self.disp(
                     "\n".join(
                         [
-                            "{}: {}".format(name, desc)
-                            for name, desc in self.host.bridge.ticketsImportList()
+                            f"{name}: {desc}"
+                            for name, desc in await self.host.bridge.ticketsImportList()
                         ]
                     )
                 )
             else:
                 try:
-                    short_desc, long_desc = self.host.bridge.ticketsImportDesc(
+                    short_desc, long_desc = await self.host.bridge.ticketsImportDesc(
                         self.args.importer
                     )
                 except Exception as e:
-                    msg = [l for l in str(e).split("\n") if l][
-                        -1
-                    ]  # we only keep the last line
-                    self.disp(msg)
-                    self.host.quit(1)
+                    self.disp(f"can't get importer description: {e}", error=True)
+                    self.host.quit(C.EXIT_BRIDGE_ERRBACK)
                 else:
-                    self.disp(
-                        "{name}: {short_desc}\n\n{long_desc}".format(
-                            name=self.args.importer,
-                            short_desc=short_desc,
-                            long_desc=long_desc,
-                        )
-                    )
+                    self.disp(f"{name}: {short_desc}\n\n{long_desc}")
             self.host.quit()
         else:
             # we have a location, an import is requested
+
+            if self.args.progress:
+                # we use a custom progress bar template as we want a counter
+                self.pbar_template = [
+                    _("Progress: "), ["Percentage"], " ", ["Bar"], " ",
+                    ["Counter"], " ", ["ETA"]
+                ]
+
             options = {key: value for key, value in self.args.option}
             fields_map = dict(self.args.map)
             if fields_map:
                 if FIELDS_MAP in options:
                     self.parser.error(
-                        _(
-                            "fields_map must be specified either preencoded in --option or using --map, but not both at the same time"
-                        )
+                        _("fields_map must be specified either preencoded in --option or "
+                          "using --map, but not both at the same time")
                     )
                 options[FIELDS_MAP] = json.dumps(fields_map)
 
-            def gotId(id_):
-                self.progress_id = id_
-
-            self.host.bridge.ticketsImport(
-                self.args.importer,
-                self.args.location,
-                options,
-                self.args.service,
-                self.args.node,
-                self.profile,
-                callback=gotId,
-                errback=self.error,
-            )
+            try:
+                progress_id = await self.host.bridge.ticketsImport(
+                    self.args.importer,
+                    self.args.location,
+                    options,
+                    self.args.service,
+                    self.args.node,
+                    self.profile,
+                )
+            except Exception as e:
+                self.disp(
+                    _(f"Error while trying to import tickets: {e}"),
+                    error=True,
+                )
+                self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+            else:
+                await self.set_progress_id(progress_id)
 
 
 class Ticket(base.CommandBase):