Mercurial > libervia-backend
comparison 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 |
comparison
equal
deleted
inserted
replaced
3039:a1bc34f90fa5 | 3040:fee60f17ebac |
---|---|
20 | 20 |
21 from . import base | 21 from . import base |
22 from sat.core.i18n import _ | 22 from sat.core.i18n import _ |
23 from sat_frontends.jp import common | 23 from sat_frontends.jp import common |
24 from sat_frontends.jp.constants import Const as C | 24 from sat_frontends.jp.constants import Const as C |
25 from functools import partial | |
26 import json | 25 import json |
27 import os | 26 import os |
28 | 27 |
29 __commands__ = ["Ticket"] | 28 __commands__ = ["Ticket"] |
30 | 29 |
42 pubsub_flags={C.MULTI_ITEMS}, | 41 pubsub_flags={C.MULTI_ITEMS}, |
43 pubsub_defaults={"service": _("auto"), "node": _("auto")}, | 42 pubsub_defaults={"service": _("auto"), "node": _("auto")}, |
44 use_output=C.OUTPUT_LIST_XMLUI, | 43 use_output=C.OUTPUT_LIST_XMLUI, |
45 help=_("get tickets"), | 44 help=_("get tickets"), |
46 ) | 45 ) |
47 self.need_loop = True | |
48 | 46 |
49 def add_parser_options(self): | 47 def add_parser_options(self): |
50 pass | 48 pass |
51 | 49 |
52 def ticketsGetCb(self, tickets_data): | 50 async def start(self): |
53 self.output(tickets_data[0]) | 51 await common.fill_well_known_uri(self, os.getcwd(), "tickets", meta_map={}) |
54 self.host.quit(C.EXIT_OK) | 52 try: |
55 | 53 tickets_data = await self.host.bridge.ticketsGet( |
56 def getTickets(self): | 54 self.args.service, |
57 self.host.bridge.ticketsGet( | 55 self.args.node, |
58 self.args.service, | 56 self.args.max, |
59 self.args.node, | 57 self.args.items, |
60 self.args.max, | 58 "", |
61 self.args.items, | 59 self.getPubsubExtra(), |
62 "", | 60 self.profile, |
63 self.getPubsubExtra(), | 61 ) |
64 self.profile, | 62 except Exception as e: |
65 callback=self.ticketsGetCb, | 63 self.disp(f"can't get tickets: {e}", error=True) |
66 errback=partial( | 64 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
67 self.errback, | 65 else: |
68 msg=_("can't get tickets: {}"), | 66 await self.output(tickets_data[0]) |
69 exit_code=C.EXIT_BRIDGE_ERRBACK, | 67 self.host.quit(C.EXIT_OK) |
70 ), | 68 |
71 ) | 69 |
72 | 70 class Import(base.CommandBase): |
73 def start(self): | |
74 common.URIFinder(self, os.getcwd(), "tickets", self.getTickets, meta_map={}) | |
75 | |
76 | |
77 class Import(base.CommandAnswering): | |
78 # TODO: factorize with blog/import | 71 # TODO: factorize with blog/import |
79 | 72 |
80 def __init__(self, host): | 73 def __init__(self, host): |
81 super(Import, self).__init__( | 74 super(Import, self).__init__( |
82 host, | 75 host, |
83 "import", | 76 "import", |
84 use_progress=True, | 77 use_progress=True, |
78 use_verbose=True, | |
85 help=_("import tickets from external software/dataset"), | 79 help=_("import tickets from external software/dataset"), |
86 ) | 80 ) |
87 self.need_loop = True | |
88 | 81 |
89 def add_parser_options(self): | 82 def add_parser_options(self): |
90 self.parser.add_argument( | 83 self.parser.add_argument( |
91 "importer", | 84 "importer", |
92 nargs="?", | 85 nargs="?", |
107 action="append", | 100 action="append", |
108 nargs=2, | 101 nargs=2, |
109 default=[], | 102 default=[], |
110 metavar=("IMPORTED_FIELD", "DEST_FIELD"), | 103 metavar=("IMPORTED_FIELD", "DEST_FIELD"), |
111 help=_( | 104 help=_( |
112 "specified field in import data will be put in dest field (default: use same field name, or ignore if it doesn't exist)" | 105 "specified field in import data will be put in dest field (default: use " |
106 "same field name, or ignore if it doesn't exist)" | |
113 ), | 107 ), |
114 ) | 108 ) |
115 self.parser.add_argument( | 109 self.parser.add_argument( |
116 "-s", | 110 "-s", |
117 "--service", | 111 "--service", |
123 "-n", | 117 "-n", |
124 "--node", | 118 "--node", |
125 default="", | 119 default="", |
126 metavar="PUBSUB_NODE", | 120 metavar="PUBSUB_NODE", |
127 help=_( | 121 help=_( |
128 "PubSub node where the items must be uploaded (default: tickets' defaults)" | 122 "PubSub node where the items must be uploaded (default: tickets' " |
123 "defaults)" | |
129 ), | 124 ), |
130 ) | 125 ) |
131 self.parser.add_argument( | 126 self.parser.add_argument( |
132 "location", | 127 "location", |
133 nargs="?", | 128 nargs="?", |
134 help=_( | 129 help=_( |
135 "importer data location (see importer description), nothing to show importer description" | 130 "importer data location (see importer description), nothing to show " |
131 "importer description" | |
136 ), | 132 ), |
137 ) | 133 ) |
138 | 134 |
139 def onProgressStarted(self, metadata): | 135 async def onProgressStarted(self, metadata): |
140 self.disp(_("Tickets upload started"), 2) | 136 self.disp(_("Tickets upload started"), 2) |
141 | 137 |
142 def onProgressFinished(self, metadata): | 138 async def onProgressFinished(self, metadata): |
143 self.disp(_("Tickets uploaded successfully"), 2) | 139 self.disp(_("Tickets uploaded successfully"), 2) |
144 | 140 |
145 def onProgressError(self, error_msg): | 141 async def onProgressError(self, error_msg): |
146 self.disp(_("Error while uploading tickets: {}").format(error_msg), error=True) | 142 self.disp(_(f"Error while uploading tickets: {error_msg}"), error=True) |
147 | 143 |
148 def error(self, failure): | 144 async def start(self): |
149 self.disp( | |
150 _("Error while trying to upload tickets: {reason}").format(reason=failure), | |
151 error=True, | |
152 ) | |
153 self.host.quit(1) | |
154 | |
155 def start(self): | |
156 if self.args.location is None: | 145 if self.args.location is None: |
146 # no location, the list of importer or description is requested | |
157 for name in ("option", "service", "node"): | 147 for name in ("option", "service", "node"): |
158 if getattr(self.args, name): | 148 if getattr(self.args, name): |
159 self.parser.error( | 149 self.parser.error( |
160 _( | 150 _(f"{name} argument can't be used without location argument")) |
161 "{name} argument can't be used without location argument" | |
162 ).format(name=name) | |
163 ) | |
164 if self.args.importer is None: | 151 if self.args.importer is None: |
165 self.disp( | 152 self.disp( |
166 "\n".join( | 153 "\n".join( |
167 [ | 154 [ |
168 "{}: {}".format(name, desc) | 155 f"{name}: {desc}" |
169 for name, desc in self.host.bridge.ticketsImportList() | 156 for name, desc in await self.host.bridge.ticketsImportList() |
170 ] | 157 ] |
171 ) | 158 ) |
172 ) | 159 ) |
173 else: | 160 else: |
174 try: | 161 try: |
175 short_desc, long_desc = self.host.bridge.ticketsImportDesc( | 162 short_desc, long_desc = await self.host.bridge.ticketsImportDesc( |
176 self.args.importer | 163 self.args.importer |
177 ) | 164 ) |
178 except Exception as e: | 165 except Exception as e: |
179 msg = [l for l in str(e).split("\n") if l][ | 166 self.disp(f"can't get importer description: {e}", error=True) |
180 -1 | 167 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
181 ] # we only keep the last line | |
182 self.disp(msg) | |
183 self.host.quit(1) | |
184 else: | 168 else: |
185 self.disp( | 169 self.disp(f"{name}: {short_desc}\n\n{long_desc}") |
186 "{name}: {short_desc}\n\n{long_desc}".format( | |
187 name=self.args.importer, | |
188 short_desc=short_desc, | |
189 long_desc=long_desc, | |
190 ) | |
191 ) | |
192 self.host.quit() | 170 self.host.quit() |
193 else: | 171 else: |
194 # we have a location, an import is requested | 172 # we have a location, an import is requested |
173 | |
174 if self.args.progress: | |
175 # we use a custom progress bar template as we want a counter | |
176 self.pbar_template = [ | |
177 _("Progress: "), ["Percentage"], " ", ["Bar"], " ", | |
178 ["Counter"], " ", ["ETA"] | |
179 ] | |
180 | |
195 options = {key: value for key, value in self.args.option} | 181 options = {key: value for key, value in self.args.option} |
196 fields_map = dict(self.args.map) | 182 fields_map = dict(self.args.map) |
197 if fields_map: | 183 if fields_map: |
198 if FIELDS_MAP in options: | 184 if FIELDS_MAP in options: |
199 self.parser.error( | 185 self.parser.error( |
200 _( | 186 _("fields_map must be specified either preencoded in --option or " |
201 "fields_map must be specified either preencoded in --option or using --map, but not both at the same time" | 187 "using --map, but not both at the same time") |
202 ) | |
203 ) | 188 ) |
204 options[FIELDS_MAP] = json.dumps(fields_map) | 189 options[FIELDS_MAP] = json.dumps(fields_map) |
205 | 190 |
206 def gotId(id_): | 191 try: |
207 self.progress_id = id_ | 192 progress_id = await self.host.bridge.ticketsImport( |
208 | 193 self.args.importer, |
209 self.host.bridge.ticketsImport( | 194 self.args.location, |
210 self.args.importer, | 195 options, |
211 self.args.location, | 196 self.args.service, |
212 options, | 197 self.args.node, |
213 self.args.service, | 198 self.profile, |
214 self.args.node, | 199 ) |
215 self.profile, | 200 except Exception as e: |
216 callback=gotId, | 201 self.disp( |
217 errback=self.error, | 202 _(f"Error while trying to import tickets: {e}"), |
218 ) | 203 error=True, |
204 ) | |
205 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | |
206 else: | |
207 await self.set_progress_id(progress_id) | |
219 | 208 |
220 | 209 |
221 class Ticket(base.CommandBase): | 210 class Ticket(base.CommandBase): |
222 subcommands = (Get, Import) | 211 subcommands = (Get, Import) |
223 | 212 |