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.
This commit is contained in:
Goffi 2021-06-14 18:35:12 +02:00
commit 7adbf3ead8
22 changed files with 823 additions and 601 deletions

View file

@ -972,8 +972,12 @@ class Params(object):
if not self.checkSecurityLimit(node[1], security_limit):
msg = _(
f"{profile!r} is trying to set parameter {name!r} in category "
f"{category!r} without authorization!!!")
"{profile!r} is trying to set parameter {name!r} in category "
"{category!r} without authorization!!!").format(
profile=repr(profile),
name=repr(name),
category=repr(category)
)
log.warning(msg)
raise exceptions.PermissionError(msg)
@ -986,8 +990,11 @@ class Params(object):
int(value)
except ValueError:
log.warning(_(
f"Trying to set parameter {name!r} in category {category!r} with"
f"an non-integer value"
"Trying to set parameter {name} in category {category} with"
"an non-integer value"
).format(
name=repr(name),
category=repr(category)
))
return defer.succeed(None)
if node[1].hasAttribute("constraint"):

View file

@ -64,7 +64,7 @@ class ImportPlugin(object):
@param name(unicode): import handler name
"""
assert name == name.lower().strip()
log.info(_(f"initializing {name} import handler"))
log.info(_("initializing {name} import handler").format(name=name))
import_handler.name = name
import_handler.register = partial(self.register, import_handler)
import_handler.unregister = partial(self.unregister, import_handler)
@ -155,7 +155,7 @@ class ImportPlugin(object):
pass
except ValueError:
raise exceptions.DataError(
_(f"invalid json option: {option}")
_("invalid json option: {option}").format(option=option)
)
pubsub_service = jid.JID(pubsub_service) if pubsub_service else None
return self.doImport(

View file

@ -708,7 +708,8 @@ class XEP_0329(object):
)
else:
log.warning(
_(f"unexpected element, ignoring: {elt.toXml()}")
_("unexpected element, ignoring: {elt}")
.format(elt=elt.toXml())
)
continue
files.append(file_data)

View file

@ -76,7 +76,7 @@ class CommandProtocol(protocol.ProcessProtocol):
def processEnded(self, reason):
data = b''.join(self.data)
if (reason.value.exitCode == 0):
log.debug(_(f'{self.command_name!r} command succeed'))
log.debug(f'{self.command_name!r} command succeed')
# we don't use "replace" on purpose, we want an exception if decoding
# is not working properly
self._deferred.callback(data)

View file

@ -153,8 +153,10 @@ class LiberviaCli:
background = self.guess_background()
if background not in ('dark', 'light'):
raise exceptions.ConfigError(_(
f'Invalid value set for "background" ({background!r}), please check '
f'your settings in libervia.conf'))
'Invalid value set for "background" ({background}), please check '
'your settings in libervia.conf').format(
background=repr(background)
))
if background == 'light':
C.A_HEADER = A.FG_MAGENTA
C.A_SUBHEADER = A.BOLD + A.FG_RED
@ -449,7 +451,8 @@ class LiberviaCli:
if default:
if type_ in self.default_output:
self.disp(
_(f'there is already a default output for {type_}, ignoring new one')
_('there is already a default output for {type}, ignoring new one')
.format(type=type_)
)
else:
self.default_output[type_] = name
@ -493,7 +496,8 @@ class LiberviaCli:
self.import_plugin_module(module, type_)
except ImportError as e:
self.disp(
_(f"Can't import {module_path} plugin, ignoring it: {e}"),
_("Can't import {module_path} plugin, ignoring it: {e}")
.format(module_path=module_path, e=e),
error=True)
except exceptions.CancelError:
continue
@ -512,7 +516,10 @@ class LiberviaCli:
try:
class_names = getattr(module, '__{}__'.format(type_))
except AttributeError:
log.disp(_(f"Invalid plugin module [{type_}] {module}"), error=True)
log.disp(
_("Invalid plugin module [{type}] {module}")
.format(type=type_, module=module),
error=True)
raise ImportError
else:
for class_name in class_names:
@ -601,7 +608,9 @@ class LiberviaCli:
if not item_last:
self.args.item = uri_item
else:
self.parser.error(_(f'XMPP URL is not a pubsub one: {url}'))
self.parser.error(
_('XMPP URL is not a pubsub one: {url}').format(url=url)
)
flags = self.args._cmd._pubsub_flags
# we check required arguments here instead of using add_arguments' required option
# because the required argument can be set in URL
@ -647,13 +656,15 @@ class LiberviaCli:
await self.bridge.bridgeConnect()
except Exception as e:
if isinstance(e, exceptions.BridgeExceptionNoService):
print((_("Can't connect to SàT backend, are you sure it's launched ?")))
print(_("Can't connect to SàT backend, are you sure it's launched ?"))
self.quit(C.EXIT_BACKEND_NOT_FOUND, raise_exc=False)
elif isinstance(e, exceptions.BridgeInitError):
print((_("Can't init bridge")))
print(_("Can't init bridge"))
self.quit(C.EXIT_BRIDGE_ERROR, raise_exc=False)
else:
print((_(f"Error while initialising bridge: {e}")))
print(
_("Error while initialising bridge: {e}").format(e=e)
)
self.quit(C.EXIT_BRIDGE_ERROR, raise_exc=False)
return
self.version = await self.bridge.getVersion()
@ -844,7 +855,10 @@ class LiberviaCli:
self.profile = await self.bridge.profileNameGet(self.args.profile)
if not self.profile:
log.error(_(f"The profile [{self.args.profile}] doesn't exist"))
log.error(
_("The profile [{profile}] doesn't exist")
.format(profile=self.args.profile)
)
self.quit(C.EXIT_ERROR)
try:
@ -861,9 +875,11 @@ class LiberviaCli:
elif not await self.bridge.profileIsSessionStarted(self.profile):
if not self.args.connect:
self.disp(_(
f"Session for [{self.profile}] is not started, please start it "
f"before using jp, or use either --start-session or --connect "
f"option"), error=True)
"Session for [{profile}] is not started, please start it "
"before using jp, or use either --start-session or --connect "
"option"
.format(profile=self.profile)
), error=True)
self.quit(1)
elif not getattr(self.args, "connect", False):
return
@ -882,8 +898,10 @@ class LiberviaCli:
else:
if not await self.bridge.isConnected(self.profile):
log.error(
_(f"Profile [{self.profile}] is not connected, please connect it "
f"before using jp, or use --connect option"))
_("Profile [{profile}] is not connected, please connect it "
"before using jp, or use --connect option")
.format(profile=self.profile)
)
self.quit(1)
async def get_full_jid(self, param_jid):
@ -1158,7 +1176,7 @@ class CommandBase(object):
@param error_msg(unicode): error message as sent by bridge.progressError
"""
self.disp(_(f"Error while doing operation: {e}"), error=True)
self.disp(_("Error while doing operation: {e}").format(e=e), error=True)
def disp(self, msg, verbosity=0, error=False, end='\n'):
return self.host.disp(msg, verbosity, error, end)

View file

@ -73,7 +73,9 @@ class AccountCreate(base.CommandBase):
"--port",
type=int,
default=0,
help=_(f"server port (default: {C.XMPP_C2S_PORT})"),
help=_("server port (default: {port})").format(
port=C.XMPP_C2S_PORT
),
)
async def start(self):
@ -124,8 +126,12 @@ class AccountCreate(base.CommandBase):
self.host.quit(C.EXIT_CONFLICT)
else:
self.disp(
_(f"Can't create profile {self.args.profile} to associate with jid "
f"{self.args.jid}: {e}"),
_("Can't create profile {profile} to associate with jid "
"{jid}: {e}").format(
profile=self.args.profile,
jid=self.args.jid,
e=e
),
error=True,
)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)

View file

@ -97,7 +97,8 @@ class Remote(base.CommandBase):
for method in methods:
path, iface, command = method
self.disp(
_(f"Command found: (path:{path}, iface: {iface}) [{command}]"),
_("Command found: (path:{path}, iface: {iface}) [{command}]")
.format(path=path, iface=iface, command=command),
1,
)
self.host.quit()

View file

@ -113,7 +113,7 @@ class Set(base.CommandBase):
async def start(self):
path = self.args.image_path
if not os.path.exists(path):
self.disp(_(f"file {path!r} doesn't exist!"), error=True)
self.disp(_("file {path} doesn't exist!").format(path=repr(path)), error=True)
self.host.quit(C.EXIT_BAD_ARG)
path = os.path.abspath(path)
try:

View file

@ -100,7 +100,7 @@ async def guessSyntaxFromPath(host, sat_conf, path):
if k and ext == v:
return k
# if not found, we use current syntax
# if not found, we use current syntax
return await host.bridge.getParamA("Syntax", "Composition", "value", host.profile)
@ -125,15 +125,17 @@ class BlogPublishCommon(object):
self.current_syntax = self.args.syntax = syntax
except Exception as e:
if e.classname == "NotFound":
self.parser.error(_(f"unknown syntax requested ({self.args.syntax})"))
self.parser.error(
_("unknown syntax requested ({syntax})").format(
syntax=self.args.syntax
)
)
else:
raise e
return self.args.syntax
def add_parser_options(self):
self.parser.add_argument(
"-T", "--title", help=_("title of the item")
)
self.parser.add_argument("-T", "--title", help=_("title of the item"))
self.parser.add_argument(
"-t",
"--tag",
@ -148,13 +150,22 @@ class BlogPublishCommon(object):
comments_group = self.parser.add_mutually_exclusive_group()
comments_group.add_argument(
"-C", "--comments", action="store_const", const=True, dest="comments",
help=_("enable comments (default: comments not enabled except if they "
"already exist)")
"-C",
"--comments",
action="store_const",
const=True,
dest="comments",
help=_(
"enable comments (default: comments not enabled except if they "
"already exist)"
),
)
comments_group.add_argument(
"--no-comments", action="store_const", const=False, dest="comments",
help=_("disable comments (will remove comments node if it exist)")
"--no-comments",
action="store_const",
const=False,
dest="comments",
help=_("disable comments (will remove comments node if it exist)"),
)
self.parser.add_argument(
@ -182,7 +193,7 @@ class BlogPublishCommon(object):
if self.args.comments is not None:
mb_data["allow_comments"] = self.args.comments
if self.args.tag:
mb_data['tags'] = self.args.tag
mb_data["tags"] = self.args.tag
if self.args.title is not None:
mb_data["title"] = self.args.title
if self.args.language is not None:
@ -222,9 +233,7 @@ class Set(base.CommandBase, BlogPublishCommon):
self.profile,
)
except Exception as e:
self.disp(
f"can't send item: {e}", error=True
)
self.disp(f"can't send item: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp("Item published")
@ -261,12 +270,12 @@ class Get(base.CommandBase):
def template_data_mapping(self, data):
items, blog_items = data
blog_items['items'] = items
blog_items["items"] = items
return {"blog_items": blog_items}
def format_comments(self, item, keys):
lines = []
for data in item.get('comments', []):
for data in item.get("comments", []):
lines.append(data["uri"])
for k in ("node", "service"):
if OUTPUT_OPT_NO_HEADER in self.args.output_opts:
@ -277,7 +286,7 @@ class Get(base.CommandBase):
return "\n".join(lines)
def format_tags(self, item, keys):
tags = item.pop('tags', [])
tags = item.pop("tags", [])
return ", ".join(tags)
def format_updated(self, item, keys):
@ -359,7 +368,7 @@ class Get(base.CommandBase):
if isinstance(value, bool):
value = str(value).lower()
self.disp(header + value)
# we want a separation line after each item but the last one
# we want a separation line after each item but the last one
if idx < len(items) - 1:
print("")
@ -393,7 +402,7 @@ class Get(base.CommandBase):
else:
author = published = updated = None
if verbosity > 1:
tags = item.pop('tags', [])
tags = item.pop("tags", [])
else:
tags = None
content = item.get("content")
@ -428,14 +437,14 @@ class Get(base.CommandBase):
self.args.max,
self.args.items,
self.getPubsubExtra(),
self.profile
self.profile,
)
)
except Exception as e:
self.disp(f"can't get blog items: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
items = mb_data.pop('items')
items = mb_data.pop("items")
await self.output((items, mb_data))
self.host.quit(C.EXIT_OK)
@ -483,7 +492,8 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
# we first construct metadata from edited item ones and CLI argumments
# or re-use the existing one if it exists
meta_file_path = content_file_path.with_name(
content_file_path.stem + common.METADATA_SUFF)
content_file_path.stem + common.METADATA_SUFF
)
if meta_file_path.exists():
self.disp("Metadata file already exists, we re-use it")
try:
@ -499,20 +509,20 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
else:
mb_data = {} if mb_data is None else mb_data.copy()
# in all cases, we want to remove unwanted keys
# in all cases, we want to remove unwanted keys
for key in KEY_TO_REMOVE_METADATA:
try:
del mb_data[key]
except KeyError:
pass
# and override metadata with command-line arguments
# and override metadata with command-line arguments
self.setMbDataFromArgs(mb_data)
if self.args.no_publish:
mb_data["publish"] = False
# then we create the file and write metadata there, as JSON dict
# XXX: if we port jp one day on Windows, O_BINARY may need to be added here
# then we create the file and write metadata there, as JSON dict
# XXX: if we port jp one day on Windows, O_BINARY may need to be added here
with os.fdopen(
os.open(meta_file_path, os.O_RDWR | os.O_CREAT | os.O_TRUNC, 0o600), "w+b"
) as f:
@ -556,7 +566,7 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
)
)
# we launch editor
# we launch editor
coroutines.append(
self.runEditor(
"blog_editor_args",
@ -590,11 +600,9 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
items = [item] if item else []
mb_data = data_format.deserialise(
await self.host.bridge.mbGet(
service, node, 1, items, {}, self.profile
)
await self.host.bridge.mbGet(service, node, 1, items, {}, self.profile)
)
item = mb_data['items'][0]
item = mb_data["items"][0]
try:
content = item["content_xhtml"]
@ -612,8 +620,8 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
if content and self.current_syntax == SYNTAX_XHTML:
content = content.strip()
if not content.startswith('<div>'):
content = '<div>' + content + '</div>'
if not content.startswith("<div>"):
content = "<div>" + content + "</div>"
try:
from lxml import etree
except ImportError:
@ -630,15 +638,20 @@ class Edit(base.CommandBase, BlogPublishCommon, common.BaseEdit):
SYNTAX_EXT.update(config.getConfig(self.sat_conf, "jp", CONF_SYNTAX_EXT, {}))
self.current_syntax = await self.get_current_syntax()
(self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path,
content_file_obj, mb_data,) = await self.getItemPath()
(
self.pubsub_service,
self.pubsub_node,
self.pubsub_item,
content_file_path,
content_file_obj,
mb_data,
) = await self.getItemPath()
await self.edit(content_file_path, content_file_obj, mb_data=mb_data)
self.host.quit()
class Rename(base.CommandBase):
def __init__(self, host):
base.CommandBase.__init__(
self,
@ -650,10 +663,7 @@ class Rename(base.CommandBase):
)
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:
@ -665,14 +675,13 @@ class Rename(base.CommandBase):
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")
self.host.quit(C.EXIT_OK)
class Preview(base.CommandBase, common.BaseEdit):
# TODO: need to be rewritten with template output
@ -735,9 +744,9 @@ class Preview(base.CommandBase, common.BaseEdit):
xhtml = (
f'<html xmlns="http://www.w3.org/1999/xhtml">'
f'<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />'
f'</head>'
f'<body>{content}</body>'
f'</html>'
f"</head>"
f"<body>{content}</body>"
f"</html>"
)
with open(self.preview_file_path, "wb") as f:
@ -791,18 +800,19 @@ class Preview(base.CommandBase, common.BaseEdit):
else:
update_cb = self.updatePreviewExt
# which file do we need to edit?
# which file do we need to edit?
if self.args.file == "current":
self.content_file_path = self.getCurrentFile(self.profile)
else:
try:
self.content_file_path = Path(self.args.file).resolve(strict=True)
except FileNotFoundError:
self.disp(_(f'File "{self.args.file}" doesn\'t exist!'))
self.disp(_('File "{file}" doesn\'t exist!').format(file=self.args.file))
self.host.quit(C.EXIT_NOT_FOUND)
self.syntax = await guessSyntaxFromPath(
self.host, sat_conf, self.content_file_path)
self.host, sat_conf, self.content_file_path
)
# at this point the syntax is converted, we can display the preview
preview_file = tempfile.NamedTemporaryFile(suffix=".xhtml", delete=False)
@ -825,10 +835,10 @@ class Preview(base.CommandBase, common.BaseEdit):
watcher_kwargs = {
# Watcher don't accept Path so we convert to string
"path": str(self.content_file_path),
"alias": 'content_file',
"alias": "content_file",
"flags": aionotify.Flags.CLOSE_WRITE
| aionotify.Flags.DELETE_SELF
| aionotify.Flags.MOVE_SELF,
| aionotify.Flags.DELETE_SELF
| aionotify.Flags.MOVE_SELF,
}
watcher.watch(**watcher_kwargs)
@ -839,14 +849,15 @@ class Preview(base.CommandBase, common.BaseEdit):
while True:
event = await watcher.get_event()
self.disp("Content updated", 1)
if event.flags & (aionotify.Flags.DELETE_SELF
| aionotify.Flags.MOVE_SELF):
if event.flags & (
aionotify.Flags.DELETE_SELF | aionotify.Flags.MOVE_SELF
):
self.disp(
"DELETE/MOVE event catched, changing the watch",
2,
)
try:
watcher.unwatch('content_file')
watcher.unwatch("content_file")
except IOError as e:
self.disp(
f"Can't remove the watch: {e}",
@ -869,7 +880,7 @@ class Preview(base.CommandBase, common.BaseEdit):
finally:
os.unlink(self.preview_file_path)
try:
watcher.unwatch('content_file')
watcher.unwatch("content_file")
except IOError as e:
self.disp(
f"Can't remove the watch: {e}",
@ -893,9 +904,7 @@ class Import(base.CommandBase):
nargs="?",
help=_("importer name, nothing to display importers list"),
)
self.parser.add_argument(
"--host", help=_("original blog host")
)
self.parser.add_argument("--host", help=_("original blog host"))
self.parser.add_argument(
"--no-images-upload",
action="store_true",
@ -954,13 +963,16 @@ class Import(base.CommandBase):
)
self.disp(
_(
f"\nTo redirect old URLs to new ones, put the following lines in your"
f" sat.conf file, in [libervia] section:\n\n{conf}"
)
"\nTo redirect old URLs to new ones, put the following lines in your"
" sat.conf file, in [libervia] section:\n\n{conf}"
).format(conf=conf)
)
async def onProgressError(self, error_msg):
self.disp(_(f"Error while uploading blog: {error_msg}"), error=True)
self.disp(
_("Error while uploading blog: {error_msg}").format(error_msg=error_msg),
error=True,
)
async def start(self):
if self.args.location is None:
@ -968,8 +980,8 @@ class Import(base.CommandBase):
if getattr(self.args, name):
self.parser.error(
_(
f"{name} argument can't be used without location argument"
)
"{name} argument can't be used without location argument"
).format(name=name)
)
if self.args.importer is None:
self.disp(
@ -1022,13 +1034,14 @@ class Import(base.CommandBase):
)
except Exception as e:
self.disp(
_(f"Error while trying to import a blog: {e}"),
_("Error while trying to import a blog: {e}").format(e=e),
error=True,
)
self.host.quit(1)
await self.set_progress_id(progress_id)
class Blog(base.CommandBase):
subcommands = (Set, Get, Edit, Rename, Preview, Import)

View file

@ -23,25 +23,41 @@ from sat_frontends.jp.constants import Const as C
__commands__ = ["Bookmarks"]
STORAGE_LOCATIONS = ('local', 'private', 'pubsub')
TYPES = ('muc', 'url')
STORAGE_LOCATIONS = ("local", "private", "pubsub")
TYPES = ("muc", "url")
class BookmarksCommon(base.CommandBase):
"""Class used to group common options of bookmarks subcommands"""
def add_parser_options(self, location_default='all'):
self.parser.add_argument('-l', '--location', type=str, choices=(location_default,) + STORAGE_LOCATIONS, default=location_default, help=_("storage location (default: %(default)s)"))
self.parser.add_argument('-t', '--type', type=str, choices=TYPES, default=TYPES[0], help=_("bookmarks type (default: %(default)s)"))
def add_parser_options(self, location_default="all"):
self.parser.add_argument(
"-l",
"--location",
type=str,
choices=(location_default,) + STORAGE_LOCATIONS,
default=location_default,
help=_("storage location (default: %(default)s)"),
)
self.parser.add_argument(
"-t",
"--type",
type=str,
choices=TYPES,
default=TYPES[0],
help=_("bookmarks type (default: %(default)s)"),
)
class BookmarksList(BookmarksCommon):
def __init__(self, host):
super(BookmarksList, self).__init__(host, 'list', help=_('list bookmarks'))
super(BookmarksList, self).__init__(host, "list", help=_("list bookmarks"))
async def start(self):
try:
data = await self.host.bridge.bookmarksList(
self.args.type, self.args.location, self.host.profile)
self.args.type, self.args.location, self.host.profile
)
except Exception as e:
self.disp(f"can't get bookmarks list: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
@ -54,32 +70,40 @@ class BookmarksList(BookmarksCommon):
loc_mess.append(f"{location}:")
book_mess = []
for book_link, book_data in list(data[location].items()):
name = book_data.get('name')
autojoin = book_data.get('autojoin', 'false') == 'true'
nick = book_data.get('nick')
book_mess.append("\t%s[%s%s]%s" % ((name+' ') if name else '',
book_link,
' (%s)' % nick if nick else '',
' (*)' if autojoin else ''))
loc_mess.append('\n'.join(book_mess))
mess.append('\n'.join(loc_mess))
name = book_data.get("name")
autojoin = book_data.get("autojoin", "false") == "true"
nick = book_data.get("nick")
book_mess.append(
"\t%s[%s%s]%s"
% (
(name + " ") if name else "",
book_link,
" (%s)" % nick if nick else "",
" (*)" if autojoin else "",
)
)
loc_mess.append("\n".join(book_mess))
mess.append("\n".join(loc_mess))
print('\n\n'.join(mess))
print("\n\n".join(mess))
self.host.quit()
class BookmarksRemove(BookmarksCommon):
def __init__(self, host):
super(BookmarksRemove, self).__init__(host, 'remove', help=_('remove a bookmark'))
super(BookmarksRemove, self).__init__(host, "remove", help=_("remove a bookmark"))
def add_parser_options(self):
super(BookmarksRemove, self).add_parser_options()
self.parser.add_argument(
'bookmark', help=_('jid (for muc bookmark) or url of to remove'))
"bookmark", help=_("jid (for muc bookmark) or url of to remove")
)
self.parser.add_argument(
"-f", "--force", action="store_true",
help=_("delete bookmark without confirmation"),)
"-f",
"--force",
action="store_true",
help=_("delete bookmark without confirmation"),
)
async def start(self):
if not self.args.force:
@ -87,50 +111,58 @@ class BookmarksRemove(BookmarksCommon):
try:
await self.host.bridge.bookmarksRemove(
self.args.type, self.args.bookmark, self.args.location, self.host.profile)
self.args.type, self.args.bookmark, self.args.location, self.host.profile
)
except Exception as e:
self.disp(_(f"can't delete bookmark: {e}"), error=True)
self.disp(_("can't delete bookmark: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(_('bookmark deleted'))
self.disp(_("bookmark deleted"))
self.host.quit()
class BookmarksAdd(BookmarksCommon):
def __init__(self, host):
super(BookmarksAdd, self).__init__(host, 'add', help=_('add a bookmark'))
super(BookmarksAdd, self).__init__(host, "add", help=_("add a bookmark"))
def add_parser_options(self):
super(BookmarksAdd, self).add_parser_options(location_default='auto')
super(BookmarksAdd, self).add_parser_options(location_default="auto")
self.parser.add_argument(
'bookmark', help=_('jid (for muc bookmark) or url of to remove'))
self.parser.add_argument('-n', '--name', help=_("bookmark name"))
muc_group = self.parser.add_argument_group(_('MUC specific options'))
muc_group.add_argument('-N', '--nick', help=_('nickname'))
"bookmark", help=_("jid (for muc bookmark) or url of to remove")
)
self.parser.add_argument("-n", "--name", help=_("bookmark name"))
muc_group = self.parser.add_argument_group(_("MUC specific options"))
muc_group.add_argument("-N", "--nick", help=_("nickname"))
muc_group.add_argument(
'-a', '--autojoin', action='store_true',
help=_('join room on profile connection'))
"-a",
"--autojoin",
action="store_true",
help=_("join room on profile connection"),
)
async def start(self):
if self.args.type == 'url' and (self.args.autojoin or self.args.nick is not None):
if self.args.type == "url" and (self.args.autojoin or self.args.nick is not None):
self.parser.error(_("You can't use --autojoin or --nick with --type url"))
data = {}
if self.args.autojoin:
data['autojoin'] = 'true'
data["autojoin"] = "true"
if self.args.nick is not None:
data['nick'] = self.args.nick
data["nick"] = self.args.nick
if self.args.name is not None:
data['name'] = self.args.name
data["name"] = self.args.name
try:
await self.host.bridge.bookmarksAdd(
self.args.type, self.args.bookmark, data, self.args.location,
self.host.profile)
self.args.type,
self.args.bookmark,
data,
self.args.location,
self.host.profile,
)
except Exception as e:
self.disp(f"can't add bookmark: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(_('bookmark successfully added'))
self.disp(_("bookmark successfully added"))
self.host.quit()
@ -138,4 +170,6 @@ class Bookmarks(base.CommandBase):
subcommands = (BookmarksList, BookmarksRemove, BookmarksAdd)
def __init__(self, host):
super(Bookmarks, self).__init__(host, 'bookmarks', use_profile=False, help=_('manage bookmarks'))
super(Bookmarks, self).__init__(
host, "bookmarks", use_profile=False, help=_("manage bookmarks")
)

View file

@ -53,20 +53,19 @@ class Method(base.CommandBase, BridgeCommon):
self.parser.add_argument(
"method", type=str, help=_("name of the method to execute")
)
self.parser.add_argument(
"arg", nargs="*", help=_("argument of the method")
)
self.parser.add_argument("arg", nargs="*", help=_("argument of the method"))
async def start(self):
method = getattr(self.host.bridge, self.args.method)
import inspect
argspec = inspect.getargspec(method)
kwargs = {}
if 'profile_key' in argspec.args:
kwargs['profile_key'] = self.profile
elif 'profile' in argspec.args:
kwargs['profile'] = self.profile
if "profile_key" in argspec.args:
kwargs["profile_key"] = self.profile
elif "profile" in argspec.args:
kwargs["profile"] = self.profile
args = self.evalArgs()
@ -76,7 +75,12 @@ class Method(base.CommandBase, BridgeCommon):
**kwargs,
)
except Exception as e:
self.disp(_(f"Error while executing {self.args.method}: {e}"), error=True)
self.disp(
_("Error while executing {method}: {e}").format(
method=self.args.method, e=e
),
error=True,
)
self.host.quit(C.EXIT_ERROR)
else:
if ret is not None:
@ -92,12 +96,8 @@ class Signal(base.CommandBase, BridgeCommon):
BridgeCommon.__init__(self)
def add_parser_options(self):
self.parser.add_argument(
"signal", type=str, help=_("name of the signal to send")
)
self.parser.add_argument(
"arg", nargs="*", help=_("argument of the signal")
)
self.parser.add_argument("signal", type=str, help=_("name of the signal to send"))
self.parser.add_argument("arg", nargs="*", help=_("argument of the signal"))
async def start(self):
args = self.evalArgs()
@ -105,9 +105,11 @@ class Signal(base.CommandBase, BridgeCommon):
# XXX: we use self.args.profile and not self.profile
# because we want the raw profile_key (so plugin handle C.PROF_KEY_NONE)
try:
await self.host.bridge.debugFakeSignal(self.args.signal, json_args, self.args.profile)
await self.host.bridge.debugFakeSignal(
self.args.signal, json_args, self.args.profile
)
except Exception as e:
self.disp(_(f"Can't send fake signal: {e}"), error=True)
self.disp(_("Can't send fake signal: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_ERROR)
else:
self.host.quit()
@ -198,18 +200,17 @@ class Theme(base.CommandBase):
async def start(self):
for attr in dir(C):
if not attr.startswith('A_'):
if not attr.startswith("A_"):
continue
color = getattr(C, attr)
if attr == 'A_LEVEL_COLORS':
if attr == "A_LEVEL_COLORS":
# This constant contains multiple colors
self.disp('LEVEL COLORS: ', end=' ')
self.disp("LEVEL COLORS: ", end=" ")
for idx, c in enumerate(color):
last = idx == len(color)-1
end = '\n' if last else ' '
last = idx == len(color) - 1
end = "\n" if last else " "
self.disp(
c + f'LEVEL_{idx}' + A.RESET + (', ' if not last else ''),
end=end
c + f"LEVEL_{idx}" + A.RESET + (", " if not last else ""), end=end
)
else:
text = attr[2:]

View file

@ -107,9 +107,7 @@ class EventBase(object):
default="",
help=_("ID of the PubSub Item"),
)
self.parser.add_argument(
"-d", "--date", type=str, help=_("date of the event")
)
self.parser.add_argument("-d", "--date", type=str, help=_("date of the event"))
self.parser.add_argument(
"-f",
"--field",
@ -169,7 +167,7 @@ class Create(EventBase, base.CommandBase):
self.disp(f"can't create event: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(_(f"Event created successfuly on node {node}"))
self.disp(_("Event created successfuly on node {node}").format(node=node))
self.host.quit()
@ -350,9 +348,7 @@ class InviteesList(base.CommandBase):
table = common.Table.fromListDict(
self.host,
data,
("nick",)
+ (("jid",) if self.host.verbosity else ())
+ ("attend", "guests"),
("nick",) + (("jid",) if self.host.verbosity else ()) + ("attend", "guests"),
headers=None,
filters={
"nick": A.color(C.A_HEADER, "{}" if show_table else "{} "),
@ -402,9 +398,7 @@ class InviteesList(base.CommandBase):
)
)
self.disp(
A.color(
C.A_SUBHEADER, _("total: "), A.RESET, str(guests + guests_maybe)
)
A.color(C.A_SUBHEADER, _("total: "), A.RESET, str(guests + guests_maybe))
)
if attendees_missing:
self.disp("")
@ -453,7 +447,7 @@ class InviteesList(base.CommandBase):
self.disp(f"can't get event data: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
# we fill nicknames and keep only requested people
# we fill nicknames and keep only requested people
if self.args.no_rsvp:
for jid_ in event_data:
@ -462,21 +456,23 @@ class InviteesList(base.CommandBase):
try:
del prefilled[jid_]
except KeyError:
self.disp(A.color(
C.A_WARNING,
f"We got a RSVP from somebody who was not in invitees "
f"list: {jid_}"
self.disp(
A.color(
C.A_WARNING,
f"We got a RSVP from somebody who was not in invitees "
f"list: {jid_}",
),
error=True)
error=True,
)
else:
# we replace empty dicts for existing people with R.S.V.P. data
prefilled.update(event_data)
# we get nicknames for everybody, make it easier for organisers
# we get nicknames for everybody, make it easier for organisers
for jid_, data in prefilled.items():
id_data = await self.host.bridge.identityGet(jid_, [], True, self.profile)
id_data = data_format.deserialise(id_data)
data["nick"] = id_data['nicknames'][0]
data["nick"] = id_data["nicknames"][0]
await self.output(prefilled)
self.host.quit()

View file

@ -54,9 +54,7 @@ class Send(base.CommandBase):
self.parser.add_argument(
"files", type=str, nargs="+", metavar="file", help=_("a list of file")
)
self.parser.add_argument(
"jid", help=_("the destination jid")
)
self.parser.add_argument("jid", help=_("the destination jid"))
self.parser.add_argument(
"-b", "--bz2", action="store_true", help=_("make a bzip2 tarball")
)
@ -101,19 +99,21 @@ class Send(base.CommandBase):
await self.set_progress_id(data["progress"])
except KeyError:
# TODO: if 'xmlui' key is present, manage xmlui message display
self.disp(
_("Can't send file to {jid}".format(jid=self.args.jid)), error=True
)
self.disp(_("Can't send file to {jid}".format(jid=self.args.jid)), error=True)
self.host.quit(2)
async def start(self):
for file_ in self.args.files:
if not os.path.exists(file_):
self.disp(_(f"file {file_!r} doesn't exist!"), error=True)
self.disp(
_("file {file_} doesn't exist!").format(file_=repr(file_)), error=True
)
self.host.quit(C.EXIT_BAD_ARG)
if not self.args.bz2 and os.path.isdir(file_):
self.disp(
_(f"{file_!r} is a dir! Please send files inside or use compression")
_(
"{file_} is a dir! Please send files inside or use compression"
).format(file_=repr(file_))
)
self.host.quit(C.EXIT_BAD_ARG)
@ -188,9 +188,7 @@ class Request(base.CommandBase):
return self.args.name or self.args.hash or "output"
def add_parser_options(self):
self.parser.add_argument(
"jid", help=_("the destination jid")
)
self.parser.add_argument("jid", help=_("the destination jid"))
self.parser.add_argument(
"-D",
"--dest",
@ -258,7 +256,8 @@ class Request(base.CommandBase):
if os.path.exists(path) and not self.args.force:
message = _("File {path} already exists! Do you want to overwrite?").format(
path = path)
path=path
)
await self.host.confirmOrQuit(message, _("file request cancelled"))
self.full_dest_jid = await self.host.get_full_jid(self.args.jid)
@ -278,7 +277,7 @@ class Request(base.CommandBase):
self.profile,
)
except Exception as e:
self.disp(msg=_(f"can't request file: {e}"), error=True)
self.disp(msg=_("can't request file: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
await self.set_progress_id(progress_id)
@ -334,15 +333,16 @@ class Receive(base.CommandAnswering):
self.disp(_("File received successfully"), 2)
if metadata.get("hash_verified", False):
try:
self.disp(_(
f"hash checked: {metadata['hash_algo']}:{metadata['hash']}"), 1)
self.disp(
_("hash checked: {metadata['hash_algo']}:{metadata['hash']}"), 1
)
except KeyError:
self.disp(_("hash is checked but hash value is missing", 1), error=True)
else:
self.disp(_("hash can't be verified"), 1)
async def onProgressError(self, e):
self.disp(_(f"Error while receiving file: {e}"), error=True)
self.disp(_("Error while receiving file: {e}").format(e=e), error=True)
def getXmluiId(self, action_data):
# FIXME: we temporarily use ElementTree, but a real XMLUI managing module
@ -413,8 +413,12 @@ class Receive(base.CommandAnswering):
try:
from_jid = jid.JID(action_data["meta_from_jid"])
except ValueError:
self.disp(_('invalid "from_jid" value received, ignoring: {value}').format(
value=from_jid), error=True)
self.disp(
_('invalid "from_jid" value received, ignoring: {value}').format(
value=from_jid
),
error=True,
)
return
except KeyError:
self.disp(_('ignoring action without "from_jid" value'), error=True)
@ -448,18 +452,23 @@ class Receive(base.CommandAnswering):
class Get(base.CommandBase):
def __init__(self, host):
super(Get, self).__init__(
host, "get", use_progress=True, use_verbose=True,
help=_("download a file from URI")
host,
"get",
use_progress=True,
use_verbose=True,
help=_("download a file from URI"),
)
def add_parser_options(self):
self.parser.add_argument(
'-o', '--dest-file', type=str, default='',
help=_("destination file (DEFAULT: filename from URL)")
)
"-o",
"--dest-file",
type=str,
default="",
help=_("destination file (DEFAULT: filename from URL)"),
)
self.parser.add_argument(
"-f",
"--force",
@ -482,8 +491,8 @@ class Get(base.CommandBase):
try:
await self.set_progress_id(data["progress"])
except KeyError:
if 'xmlui' in data:
ui = xmlui_manager.create(self.host, data['xmlui'])
if "xmlui" in data:
ui = xmlui_manager.create(self.host, data["xmlui"])
await ui.show()
else:
self.disp(_("Can't download file"), error=True)
@ -499,7 +508,8 @@ class Get(base.CommandBase):
dest_file = Path(dest_file).expanduser().resolve()
if dest_file.exists() and not self.args.force:
message = _("File {path} already exists! Do you want to overwrite?").format(
path = dest_file)
path=dest_file
)
await self.host.confirmOrQuit(message, _("file download cancelled"))
options = {}
@ -569,8 +579,8 @@ class Upload(base.CommandBase):
try:
await self.set_progress_id(data["progress"])
except KeyError:
if 'xmlui' in data:
ui = xmlui_manager.create(self.host, data['xmlui'])
if "xmlui" in data:
ui = xmlui_manager.create(self.host, data["xmlui"])
await ui.show()
else:
self.disp(_("Can't upload file"), error=True)
@ -579,10 +589,12 @@ class Upload(base.CommandBase):
async def start(self):
file_ = self.args.file
if not os.path.exists(file_):
self.disp(_(f"file {file_!r} doesn't exist !"), error=True)
self.disp(
_("file {file_} doesn't exist !").format(file_=repr(file_)), error=True
)
self.host.quit(C.EXIT_BAD_ARG)
if os.path.isdir(file_):
self.disp(_(f"{file_!r} is a dir! Can't upload a dir"))
self.disp(_("{file_} is a dir! Can't upload a dir").format(file_=repr(file_)))
self.host.quit(C.EXIT_BAD_ARG)
if self.args.jid is None:
@ -613,7 +625,6 @@ class Upload(base.CommandBase):
class ShareAffiliationsSet(base.CommandBase):
def __init__(self, host):
super(ShareAffiliationsSet, self).__init__(
host,
@ -720,7 +731,6 @@ class ShareAffiliations(base.CommandBase):
class ShareConfigurationSet(base.CommandBase):
def __init__(self, host):
super(ShareConfigurationSet, self).__init__(
host,
@ -822,8 +832,10 @@ class ShareConfiguration(base.CommandBase):
def __init__(self, host):
super(ShareConfiguration, self).__init__(
host, "configuration", use_profile=False,
help=_("file sharing node configuration")
host,
"configuration",
use_profile=False,
help=_("file sharing node configuration"),
)
@ -962,7 +974,11 @@ class SharePath(base.CommandBase):
self.disp(f"can't share path: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(_(f'{self.path} shared under the name "{name}"'))
self.disp(
_('{path} shared under the name "{name}"').format(
path=self.path, name=name
)
)
self.host.quit()
@ -1015,10 +1031,10 @@ class ShareInvite(base.CommandBase):
self.path = os.path.normpath(self.args.path) if self.args.path else ""
extra = {}
if self.args.thumbnail is not None:
if not self.args.thumbnail.startswith('http'):
if not self.args.thumbnail.startswith("http"):
self.parser.error(_("only http(s) links are allowed with --thumbnail"))
else:
extra['thumb_url'] = self.args.thumbnail
extra["thumb_url"] = self.args.thumbnail
try:
await self.host.bridge.FISInvite(
self.args.jid,
@ -1034,15 +1050,18 @@ class ShareInvite(base.CommandBase):
self.disp(f"can't send invitation: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(
_(f'invitation sent to {self.args.jid}')
)
self.disp(_("invitation sent to {jid}").format(jid=self.args.jid))
self.host.quit()
class Share(base.CommandBase):
subcommands = (
ShareList, SharePath, ShareInvite, ShareAffiliations, ShareConfiguration)
ShareList,
SharePath,
ShareInvite,
ShareAffiliations,
ShareConfiguration,
)
def __init__(self, host):
super(Share, self).__init__(

View file

@ -28,35 +28,47 @@ __commands__ = ["Info"]
class Disco(base.CommandBase):
def __init__(self, host):
extra_outputs = {'default': self.default_output}
extra_outputs = {"default": self.default_output}
super(Disco, self).__init__(
host, 'disco', use_output='complex', extra_outputs=extra_outputs,
help=_('service discovery'))
host,
"disco",
use_output="complex",
extra_outputs=extra_outputs,
help=_("service discovery"),
)
def add_parser_options(self):
self.parser.add_argument("jid", help=_("entity to discover"))
self.parser.add_argument(
"-t", "--type", type=str, choices=('infos', 'items', 'both'), default='both',
help=_("type of data to discover"))
self.parser.add_argument("-n", "--node", default='', help=_("node to use"))
"-t",
"--type",
type=str,
choices=("infos", "items", "both"),
default="both",
help=_("type of data to discover"),
)
self.parser.add_argument("-n", "--node", default="", help=_("node to use"))
self.parser.add_argument(
"-C", "--no-cache", dest='use_cache', action="store_false",
help=_("ignore cache"))
"-C",
"--no-cache",
dest="use_cache",
action="store_false",
help=_("ignore cache"),
)
def default_output(self, data):
features = data.get('features', [])
identities = data.get('identities', [])
extensions = data.get('extensions', {})
items = data.get('items', [])
features = data.get("features", [])
identities = data.get("identities", [])
extensions = data.get("extensions", {})
items = data.get("items", [])
identities_table = common.Table(self.host,
identities,
headers=(_('category'),
_('type'),
_('name')),
use_buffer=True)
identities_table = common.Table(
self.host,
identities,
headers=(_("category"), _("type"), _("name")),
use_buffer=True,
)
extensions_tpl = []
extensions_types = list(extensions.keys())
@ -69,30 +81,35 @@ class Disco(base.CommandBase):
data_keys = list(data.keys())
data_keys.sort()
for key in data_keys:
field_lines.append(A.color('\t', C.A_SUBHEADER, key, A.RESET, ': ',
data[key]))
field_lines.append(
A.color("\t", C.A_SUBHEADER, key, A.RESET, ": ", data[key])
)
if len(values) == 1:
field_lines.append(A.color('\t', C.A_SUBHEADER, "value", A.RESET,
': ', values[0] or (A.BOLD + "UNSET")))
field_lines.append(
A.color(
"\t",
C.A_SUBHEADER,
"value",
A.RESET,
": ",
values[0] or (A.BOLD + "UNSET"),
)
)
elif len(values) > 1:
field_lines.append(A.color('\t', C.A_SUBHEADER, "values", A.RESET,
': '))
field_lines.append(
A.color("\t", C.A_SUBHEADER, "values", A.RESET, ": ")
)
for value in values:
field_lines.append(A.color('\t - ', A.BOLD, value))
fields.append('\n'.join(field_lines))
extensions_tpl.append('{type_}\n{fields}'.format(
type_=type_,
fields='\n\n'.join(fields)))
field_lines.append(A.color("\t - ", A.BOLD, value))
fields.append("\n".join(field_lines))
extensions_tpl.append(
"{type_}\n{fields}".format(type_=type_, fields="\n\n".join(fields))
)
items_table = common.Table(
self.host,
items,
headers=(
_('entity'),
_('node'),
_('name')),
use_buffer=True)
self.host, items, headers=(_("entity"), _("node"), _("name")), use_buffer=True
)
template = []
if features:
@ -104,16 +121,18 @@ class Disco(base.CommandBase):
if items:
template.append(A.color(C.A_HEADER, _("Items")) + "\n\n{items}")
print("\n\n".join(template).format(
features = '\n'.join(features),
identities = identities_table.display().string,
extensions = '\n'.join(extensions_tpl),
items = items_table.display().string,
))
print(
"\n\n".join(template).format(
features="\n".join(features),
identities=identities_table.display().string,
extensions="\n".join(extensions_tpl),
items=items_table.display().string,
)
)
async def start(self):
infos_requested = self.args.type in ('infos', 'both')
items_requested = self.args.type in ('items', 'both')
infos_requested = self.args.type in ("infos", "both")
items_requested = self.args.type in ("items", "both")
jids = await self.host.check_jids([self.args.jid])
jid = jids[0]
@ -126,13 +145,13 @@ class Disco(base.CommandBase):
jid,
node=self.args.node,
use_cache=self.args.use_cache,
profile_key=self.host.profile
profile_key=self.host.profile,
)
except Exception as e:
self.disp(_(f"error while doing discovery: {e}"), error=True)
self.disp(_("error while doing discovery: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
# items
# items
if not items_requested:
items = None
else:
@ -141,35 +160,34 @@ class Disco(base.CommandBase):
jid,
node=self.args.node,
use_cache=self.args.use_cache,
profile_key=self.host.profile
profile_key=self.host.profile,
)
except Exception as e:
self.disp(_(f"error while doing discovery: {e}"), error=True)
self.disp(_("error while doing discovery: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
# output
# output
data = {}
if infos_requested:
features, identities, extensions = infos
features.sort()
identities.sort(key=lambda identity: identity[2])
data.update({
'features': features,
'identities': identities,
'extensions': extensions})
data.update(
{"features": features, "identities": identities, "extensions": extensions}
)
if items_requested:
items.sort(key=lambda item: item[2])
data['items'] = items
data["items"] = items
await self.output(data)
self.host.quit()
class Version(base.CommandBase):
class Version(base.CommandBase):
def __init__(self, host):
super(Version, self).__init__(host, 'version', help=_('software version'))
super(Version, self).__init__(host, "version", help=_("software version"))
def add_parser_options(self):
self.parser.add_argument("jid", type=str, help=_("Entity to request"))
@ -180,45 +198,49 @@ class Version(base.CommandBase):
try:
data = await self.host.bridge.getSoftwareVersion(jid, self.host.profile)
except Exception as e:
self.disp(_(f"error while trying to get version: {e}"), error=True)
self.disp(_("error while trying to get version: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
infos = []
name, version, os = data
if name:
infos.append(_(f"Software name: {name}"))
infos.append(_("Software name: {name}").format(name=name))
if version:
infos.append(_(f"Software version: {version}"))
infos.append(_("Software version: {version}").format(version=version))
if os:
infos.append(_(f"Operating System: {os}"))
infos.append(_("Operating System: {os}").format(os=os))
print("\n".join(infos))
self.host.quit()
class Session(base.CommandBase):
def __init__(self, host):
extra_outputs = {'default': self.default_output}
extra_outputs = {"default": self.default_output}
super(Session, self).__init__(
host, 'session', use_output='dict', extra_outputs=extra_outputs,
help=_('running session'))
host,
"session",
use_output="dict",
extra_outputs=extra_outputs,
help=_("running session"),
)
def add_parser_options(self):
pass
async def default_output(self, data):
started = data['started']
data['started'] = '{short} (UTC, {relative})'.format(
started = data["started"]
data["started"] = "{short} (UTC, {relative})".format(
short=date_utils.date_fmt(started),
relative=date_utils.date_fmt(started, 'relative'))
await self.host.output(C.OUTPUT_DICT, 'simple', {}, data)
relative=date_utils.date_fmt(started, "relative"),
)
await self.host.output(C.OUTPUT_DICT, "simple", {}, data)
async def start(self):
try:
data = await self.host.bridge.sessionInfosGet(self.host.profile)
except Exception as e:
self.disp(_(f'Error getting session infos: {e}'), error=True)
self.disp(_("Error getting session infos: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
await self.output(data)
@ -226,22 +248,23 @@ class Session(base.CommandBase):
class Devices(base.CommandBase):
def __init__(self, host):
super(Devices, self).__init__(
host, 'devices', use_output=C.OUTPUT_LIST_DICT,
help=_('devices of an entity'))
host, "devices", use_output=C.OUTPUT_LIST_DICT, help=_("devices of an entity")
)
def add_parser_options(self):
self.parser.add_argument(
"jid", type=str, nargs='?', default='', help=_("Entity to request"))
"jid", type=str, nargs="?", default="", help=_("Entity to request")
)
async def start(self):
try:
data = await self.host.bridge.devicesInfosGet(
self.args.jid, self.host.profile)
self.args.jid, self.host.profile
)
except Exception as e:
self.disp(_(f'Error getting devices infos: {e}'), error=True)
self.disp(_("Error getting devices infos: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
data = data_format.deserialise(data, type_check=list)
@ -254,5 +277,8 @@ class Info(base.CommandBase):
def __init__(self, host):
super(Info, self).__init__(
host, 'info', use_profile=False,
help=_('Get various pieces of information on entities'))
host,
"info",
use_profile=False,
help=_("Get various pieces of information on entities"),
)

View file

@ -162,9 +162,7 @@ class Get(base.CommandBase):
)
def add_parser_options(self):
self.parser.add_argument(
"id", help=_("invitation UUID")
)
self.parser.add_argument("id", help=_("invitation UUID"))
self.parser.add_argument(
"-j",
"--with-jid",
@ -184,7 +182,7 @@ class Get(base.CommandBase):
self.args.id,
)
except Exception as e:
self.disp(msg=_(f"can't get invitation data: {e}"), error=True)
self.disp(msg=_("can't get invitation data: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
if not self.args.with_jid:
@ -197,7 +195,7 @@ class Get(base.CommandBase):
profile,
)
except Exception as e:
self.disp(msg=_(f"can't start session: {e}"), error=True)
self.disp(msg=_("can't start session: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
try:
@ -207,7 +205,7 @@ class Get(base.CommandBase):
profile_key=profile,
)
except Exception as e:
self.disp(msg=_(f"can't retrieve jid: {e}"), error=True)
self.disp(msg=_("can't retrieve jid: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
await self.output_data(invitation_data, jid_)
@ -224,9 +222,7 @@ class Delete(base.CommandBase):
)
def add_parser_options(self):
self.parser.add_argument(
"id", help=_("invitation UUID")
)
self.parser.add_argument("id", help=_("invitation UUID"))
async def start(self):
try:
@ -234,7 +230,7 @@ class Delete(base.CommandBase):
self.args.id,
)
except Exception as e:
self.disp(msg=_(f"can't delete guest account: {e}"), error=True)
self.disp(msg=_("can't delete guest account: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
self.host.quit()
@ -290,9 +286,7 @@ class Modify(base.CommandBase):
default="",
help="profile doing the invitation (default: don't associate profile",
)
self.parser.add_argument(
"id", help=_("invitation UUID")
)
self.parser.add_argument("id", help=_("invitation UUID"))
async def start(self):
extra = dict(self.args.extra)
@ -302,7 +296,9 @@ class Modify(base.CommandBase):
continue
if arg_name in extra:
self.parser.error(
_(f"you can't set {arg_name} in both optional argument and extra")
_(
"you can't set {arg_name} in both optional argument and extra"
).format(arg_name=arg_name)
)
extra[arg_name] = value
try:
@ -312,9 +308,7 @@ class Modify(base.CommandBase):
self.args.replace,
)
except Exception as e:
self.disp(
f"can't modify invitation: {e}", error=True
)
self.disp(f"can't modify invitation: {e}", error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(_("invitations have been modified successfuly"))

View file

@ -61,7 +61,7 @@ class Get(base.CommandBase):
self.getPubsubExtra(),
self.profile,
),
type_check=list
type_check=list,
)
except Exception as e:
self.disp(f"can't get lists: {e}", error=True)
@ -72,7 +72,6 @@ class Get(base.CommandBase):
class Set(base.CommandBase):
def __init__(self, host):
base.CommandBase.__init__(
self,
@ -128,10 +127,10 @@ class Set(base.CommandBase):
self.args.service,
self.args.node,
values,
'',
"",
self.args.item,
data_format.serialise(extra),
self.profile
self.profile,
)
except Exception as e:
self.disp(f"can't set list item: {e}", error=True)
@ -142,7 +141,6 @@ class Set(base.CommandBase):
class Delete(base.CommandBase):
def __init__(self, host):
base.CommandBase.__init__(
self,
@ -183,10 +181,10 @@ class Delete(base.CommandBase):
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)
@ -262,7 +260,10 @@ class Import(base.CommandBase):
self.disp(_("Tickets uploaded successfully"), 2)
async def onProgressError(self, error_msg):
self.disp(_(f"Error while uploading tickets: {error_msg}"), error=True)
self.disp(
_("Error while uploading tickets: {error_msg}").format(error_msg=error_msg),
error=True,
)
async def start(self):
if self.args.location is None:
@ -270,7 +271,10 @@ class Import(base.CommandBase):
for name in ("option", "service", "node"):
if getattr(self.args, name):
self.parser.error(
_(f"{name} argument can't be used without location argument"))
_(
"{name} argument can't be used without location argument"
).format(name=name)
)
if self.args.importer is None:
self.disp(
"\n".join(
@ -297,8 +301,14 @@ class Import(base.CommandBase):
if self.args.progress:
# we use a custom progress bar template as we want a counter
self.pbar_template = [
_("Progress: "), ["Percentage"], " ", ["Bar"], " ",
["Counter"], " ", ["ETA"]
_("Progress: "),
["Percentage"],
" ",
["Bar"],
" ",
["Counter"],
" ",
["ETA"],
]
options = {key: value for key, value in self.args.option}
@ -306,8 +316,10 @@ class Import(base.CommandBase):
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)
@ -322,7 +334,7 @@ class Import(base.CommandBase):
)
except Exception as e:
self.disp(
_(f"Error while trying to import tickets: {e}"),
_("Error while trying to import tickets: {e}").format(e=e),
error=True,
)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)

View file

@ -30,7 +30,6 @@ __commands__ = ["MergeRequest"]
class Set(base.CommandBase):
def __init__(self, host):
base.CommandBase.__init__(
self,
@ -74,11 +73,12 @@ class Set(base.CommandBase):
await common.fill_well_known_uri(self, self.repository, "merge requests")
if not self.args.force:
message = _(
f"You are going to publish your changes to service "
f"[{self.args.service}], are you sure ?"
)
"You are going to publish your changes to service "
"[{service}], are you sure ?"
).format(service=self.args.service)
await self.host.confirmOrQuit(
message, _("merge request publication cancelled"))
message, _("merge request publication cancelled")
)
extra = {"update": True} if self.args.item else {}
values = {}
@ -101,7 +101,11 @@ class Set(base.CommandBase):
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
if published_id:
self.disp(_(f"Merge request published at {published_id}"))
self.disp(
_("Merge request published at {published_id}").format(
published_id=published_id
)
)
else:
self.disp(_("Merge request published"))
@ -125,8 +129,7 @@ class Get(base.CommandBase):
pass
async def start(self):
await common.fill_well_known_uri(
self, os.getcwd(), "merge requests", meta_map={})
await common.fill_well_known_uri(self, os.getcwd(), "merge requests", meta_map={})
extra = {}
try:
requests_data = data_format.deserialise(
@ -148,7 +151,7 @@ class Get(base.CommandBase):
whitelist = None
else:
whitelist = {"id", "title", "body"}
for request_xmlui in requests_data['items']:
for request_xmlui in requests_data["items"]:
xmlui = xmlui_manager.create(self.host, request_xmlui, whitelist=whitelist)
await xmlui.show(values_only=True)
self.disp("")
@ -179,7 +182,8 @@ class Import(base.CommandBase):
async def start(self):
self.repository = os.path.expanduser(os.path.abspath(self.args.repository))
await common.fill_well_known_uri(
self, self.repository, "merge requests", meta_map={})
self, self.repository, "merge requests", meta_map={}
)
extra = {}
try:
await self.host.bridge.mergeRequestsImport(

View file

@ -22,23 +22,31 @@
from . import base
from sat.core.i18n import _
from .constants import Const as C
__commands__ = ["Param"]
class Get(base.CommandBase):
def __init__(self, host):
super(Get, self).__init__(
host, 'get', need_connect=False, help=_('get a parameter value'))
host, "get", need_connect=False, help=_("get a parameter value")
)
def add_parser_options(self):
self.parser.add_argument(
"category", nargs='?', help=_("category of the parameter"))
self.parser.add_argument("name", nargs='?', help=_("name of the parameter"))
"category", nargs="?", help=_("category of the parameter")
)
self.parser.add_argument("name", nargs="?", help=_("name of the parameter"))
self.parser.add_argument(
"-a", "--attribute", type=str, default="value",
help=_("name of the attribute to get"))
"-a",
"--attribute",
type=str,
default="value",
help=_("name of the attribute to get"),
)
self.parser.add_argument(
"--security-limit", type=int, default=-1, help=_("security limit"))
"--security-limit", type=int, default=-1, help=_("security limit")
)
async def start(self):
if self.args.category is None:
@ -47,9 +55,12 @@ class Get(base.CommandBase):
elif self.args.name is None:
try:
values_dict = await self.host.bridge.asyncGetParamsValuesFromCategory(
self.args.category, self.args.security_limit, "", "", self.profile)
self.args.category, self.args.security_limit, "", "", self.profile
)
except Exception as e:
self.disp(_(f"can't find requested parameters: {e}"), error=True)
self.disp(
_("can't find requested parameters: {e}").format(e=e), error=True
)
self.host.quit(C.EXIT_NOT_FOUND)
else:
for name, value in values_dict.items():
@ -57,10 +68,16 @@ class Get(base.CommandBase):
else:
try:
value = await self.host.bridge.asyncGetParamA(
self.args.name, self.args.category, self.args.attribute,
self.args.security_limit, self.profile)
self.args.name,
self.args.category,
self.args.attribute,
self.args.security_limit,
self.profile,
)
except Exception as e:
self.disp(_(f"can't find requested parameter: {e}"), error=True)
self.disp(
_("can't find requested parameter: {e}").format(e=e), error=True
)
self.host.quit(C.EXIT_NOT_FOUND)
else:
print(value)
@ -69,21 +86,29 @@ class Get(base.CommandBase):
class Set(base.CommandBase):
def __init__(self, host):
super(Set, self).__init__(host, 'set', need_connect=False, help=_('set a parameter value'))
super(Set, self).__init__(
host, "set", need_connect=False, help=_("set a parameter value")
)
def add_parser_options(self):
self.parser.add_argument("category", help=_("category of the parameter"))
self.parser.add_argument("name", help=_("name of the parameter"))
self.parser.add_argument("value", help=_("name of the parameter"))
self.parser.add_argument("--security-limit", type=int, default=-1, help=_("security limit"))
self.parser.add_argument(
"--security-limit", type=int, default=-1, help=_("security limit")
)
async def start(self):
try:
await self.host.bridge.setParam(
self.args.name, self.args.value, self.args.category,
self.args.security_limit, self.profile)
self.args.name,
self.args.value,
self.args.category,
self.args.security_limit,
self.profile,
)
except Exception as e:
self.disp(_(f"can't set requested parameter: {e}"), error=True)
self.disp(_("can't set requested parameter: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.host.quit()
@ -94,8 +119,11 @@ class SaveTemplate(base.CommandBase):
def __init__(self, host):
super(SaveTemplate, self).__init__(
host, 'save', use_profile=False,
help=_('save parameters template to xml file'))
host,
"save",
use_profile=False,
help=_("save parameters template to xml file"),
)
def add_parser_options(self):
self.parser.add_argument("filename", type=str, help=_("output file"))
@ -105,10 +133,14 @@ class SaveTemplate(base.CommandBase):
try:
await self.host.bridge.saveParamsTemplate(self.args.filename)
except Exception as e:
self.disp(_(f"can't save parameters to file: {e}"), error=True)
self.disp(_("can't save parameters to file: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(_(f"parameters saved to file {self.args.filename}"))
self.disp(
_("parameters saved to file {filename}").format(
filename=self.args.filename
)
)
self.host.quit()
@ -117,8 +149,11 @@ class LoadTemplate(base.CommandBase):
def __init__(self, host):
super(LoadTemplate, self).__init__(
host, 'load', use_profile=False,
help=_('load parameters template from xml file'))
host,
"load",
use_profile=False,
help=_("load parameters template from xml file"),
)
def add_parser_options(self):
self.parser.add_argument("filename", type=str, help=_("input file"))
@ -128,10 +163,14 @@ class LoadTemplate(base.CommandBase):
try:
self.host.bridge.loadParamsTemplate(self.args.filename)
except Exception as e:
self.disp(_(f"can't load parameters from file: {e}"), error=True)
self.disp(_("can't load parameters from file: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
self.disp(_(f"parameters loaded from file {self.args.filename}"))
self.disp(
_("parameters loaded from file {filename}").format(
filename=self.args.filename
)
)
self.host.quit()
@ -139,4 +178,6 @@ class Param(base.CommandBase):
subcommands = (Get, Set, SaveTemplate, LoadTemplate)
def __init__(self, host):
super(Param, self).__init__(host, 'param', use_profile=False, help=_('Save/load parameters template'))
super(Param, self).__init__(
host, "param", use_profile=False, help=_("Save/load parameters template")
)

View file

@ -25,14 +25,11 @@ __commands__ = ["Ping"]
class Ping(base.CommandBase):
def __init__(self, host):
super(Ping, self).__init__(host, 'ping', help=_('ping XMPP entity'))
super(Ping, self).__init__(host, "ping", help=_("ping XMPP entity"))
def add_parser_options(self):
self.parser.add_argument(
"jid", help=_("jid to ping")
)
self.parser.add_argument("jid", help=_("jid to ping"))
self.parser.add_argument(
"-d", "--delay-only", action="store_true", help=_("output delay only (in s)")
)
@ -41,9 +38,9 @@ class Ping(base.CommandBase):
try:
pong_time = await self.host.bridge.ping(self.args.jid, self.profile)
except Exception as e:
self.disp(msg=_(f"can't do the ping: {e}"), error=True)
self.disp(msg=_("can't do the ping: {e}").format(e=e), error=True)
self.host.quit(C.EXIT_BRIDGE_ERRBACK)
else:
msg = pong_time if self.args.delay_only else f"PONG ({pong_time} s)"
msg = pong_time if self.args.delay_only else f"PONG ({pong_time} s)"
self.disp(msg)
self.host.quit()

View file

@ -82,10 +82,10 @@ class NodeInfo(base.CommandBase):
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 @@ class NodeCreate(base.CommandBase):
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 NodeCreate(base.CommandBase):
class NodePurge(base.CommandBase):
def __init__(self, host):
super(NodePurge, self).__init__(
host,
@ -189,12 +188,14 @@ class NodePurge(base.CommandBase):
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 @@ class NodePurge(base.CommandBase):
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 @@ class NodeDelete(base.CommandBase):
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 @@ class NodeDelete(base.CommandBase):
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 NodeSet(base.CommandBase):
class NodeImport(base.CommandBase):
def __init__(self, host):
super(NodeImport, self).__init__(
host,
@ -326,16 +329,20 @@ class NodeImport(base.CommandBase):
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 @@ class NodeImport(base.CommandBase):
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 @@ class NodeImport(base.CommandBase):
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 @@ class NodeImport(base.CommandBase):
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 @@ class NodeSchemaEdit(base.CommandBase, common.BaseEdit):
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 @@ class NodeSchemaEdit(base.CommandBase, common.BaseEdit):
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 @@ class NodeSchemaEdit(base.CommandBase, common.BaseEdit):
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 @@ class NodeSchemaGet(base.CommandBase):
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 @@ class Set(base.CommandBase):
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 @@ class Set(base.CommandBase):
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 @@ class Get(base.CommandBase):
)
)
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 @@ class Get(base.CommandBase):
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 @@ class Delete(base.CommandBase):
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 @@ class Edit(base.CommandBase, common.BaseEdit):
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 @@ class Edit(base.CommandBase, common.BaseEdit):
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 @@ class Edit(base.CommandBase, common.BaseEdit):
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 @@ class Rename(base.CommandBase):
)
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 @@ class Rename(base.CommandBase):
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 @@ class Subscribe(base.CommandBase):
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 @@ class Unsubscribe(base.CommandBase):
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 @@ class Subscriptions(base.CommandBase):
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 @@ class Affiliations(base.CommandBase):
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 @@ class Search(base.CommandBase):
"--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 @@ class Search(base.CommandBase):
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 @@ class Search(base.CommandBase):
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 @@ class Search(base.CommandBase):
# 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 @@ class Search(base.CommandBase):
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 @@ class Search(base.CommandBase):
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 @@ class Search(base.CommandBase):
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 @@ class Search(base.CommandBase):
@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 @@ class Search(base.CommandBase):
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 @@ class Search(base.CommandBase):
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 @@ class Transform(base.CommandBase):
"--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 @@ class Transform(base.CommandBase):
@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 @@ class Transform(base.CommandBase):
)
)
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 @@ class Transform(base.CommandBase):
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 @@ class Transform(base.CommandBase):
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 @@ class Transform(base.CommandBase):
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 @@ class Uri(base.CommandBase):
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 @@ class HookDelete(base.CommandBase):
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()

View file

@ -143,12 +143,11 @@ class BaseEdit(object):
raise OSError("path must link to a regular file")
if path.parent != getTmpDir(self.sat_conf, self.cat_dir):
self.disp(
f"File {path} is not in SàT temporary hierarchy, we do not remove "
f"it",
f"File {path} is not in SàT temporary hierarchy, we do not remove " f"it",
2,
)
return
# we have 2 files per draft with use_metadata, so we double max
# we have 2 files per draft with use_metadata, so we double max
unlink_max = SECURE_UNLINK_MAX * 2 if self.use_metadata else SECURE_UNLINK_MAX
backup_dir = getTmpDir(self.sat_conf, self.cat_dir, SECURE_UNLINK_DIR)
if not os.path.exists(backup_dir):
@ -157,9 +156,7 @@ class BaseEdit(object):
backup_path = os.path.join(backup_dir, filename)
# we move file to backup dir
self.host.disp(
"Backuping file {src} to {dst}".format(
src=path, dst=backup_path
),
"Backuping file {src} to {dst}".format(src=path, dst=backup_path),
1,
)
os.rename(path, backup_path)
@ -171,8 +168,14 @@ class BaseEdit(object):
self.host.disp("Purging backup file {}".format(path), 2)
os.unlink(path)
async def runEditor(self, editor_args_opt, content_file_path, content_file_obj,
meta_file_path=None, meta_ori=None):
async def runEditor(
self,
editor_args_opt,
content_file_path,
content_file_obj,
meta_file_path=None,
meta_ori=None,
):
"""Run editor to edit content and metadata
@param editor_args_opt(unicode): option in [jp] section in configuration for
@ -188,7 +191,7 @@ class BaseEdit(object):
assert meta_file_path is None
assert meta_ori is None
# we calculate hashes to check for modifications
# we calculate hashes to check for modifications
import hashlib
content_file_obj.seek(0)
@ -217,9 +220,10 @@ class BaseEdit(object):
if not args:
args = [content_file_path]
# actual editing
# actual editing
editor_process = await asyncio.create_subprocess_exec(
editor, *[str(a) for a in args])
editor, *[str(a) for a in args]
)
editor_exit = await editor_process.wait()
# edition will now be checked, and data will be sent if it was a success
@ -243,7 +247,7 @@ class BaseEdit(object):
)
self.host.quit(C.EXIT_NOT_FOUND)
# metadata
# metadata
if self.use_metadata:
try:
with meta_file_path.open("rb") as f:
@ -268,8 +272,8 @@ class BaseEdit(object):
if self.use_metadata and not metadata.get("publish", True):
self.disp(
f'Publication blocked by "publish" key in metadata, cancelling '
f'edition.\n\ntemporary file path:\t{content_file_path}\nmetadata '
f'file path:\t{meta_file_path}',
f"edition.\n\ntemporary file path:\t{content_file_path}\nmetadata "
f"file path:\t{meta_file_path}",
error=True,
)
self.host.quit()
@ -289,7 +293,7 @@ class BaseEdit(object):
os.unlink(meta_file_path)
self.host.quit()
# time to re-check the hash
# time to re-check the hash
elif tmp_ori_hash == hashlib.sha1(content).digest() and (
not self.use_metadata or meta_ori == metadata
):
@ -354,9 +358,7 @@ class BaseEdit(object):
)
return os.fdopen(fd, "w+b"), Path(path)
except OSError as e:
self.disp(
f"Can't create temporary file: {e}", error=True
)
self.disp(f"Can't create temporary file: {e}", error=True)
self.host.quit(1)
def getCurrentFile(self, profile):
@ -371,7 +373,7 @@ class BaseEdit(object):
tmp_dir = getTmpDir(self.sat_conf, self.cat_dir, profile)
available = [
p
for p in tmp_dir.glob(f'{self.cat_dir}_*')
for p in tmp_dir.glob(f"{self.cat_dir}_*")
if not p.match(f"*{METADATA_SUFF}")
]
if not available:
@ -436,9 +438,9 @@ class BaseEdit(object):
else:
self.disp(
_(
f'item "{item}" not found, we create a new item with'
f'this id'
),
'item "{item}" not found, we create a new item with'
"this id"
).format(item=item),
2,
)
content_file_obj.seek(0)
@ -453,9 +455,7 @@ class BaseEdit(object):
content_file_obj.write("\n*****\n")
content_file_obj.write(content.encode("utf-8"))
content_file_obj.seek(0)
self.disp(
_(f'item "{item}" found, we edit it'), 2
)
self.disp(_('item "{item}" found, we edit it').format(item=item), 2)
else:
self.disp("Editing a new item", 2)
if self.use_metadata:
@ -498,7 +498,7 @@ class Table(object):
size = None
if headers:
# we use a namedtuple to make the value easily accessible from filters
headers_safe = [re.sub(r'[^a-zA-Z_]', '_', h) for h in headers]
headers_safe = [re.sub(r"[^a-zA-Z_]", "_", h) for h in headers]
row_cls = namedtuple("RowData", headers_safe)
else:
row_cls = tuple
@ -516,8 +516,8 @@ class Table(object):
col_value = filter_(value, row_cls(*row_data_list))
except TypeError:
col_value = filter_(value)
# we count size without ANSI code as they will change length of the
# string when it's mostly style/color changes.
# we count size without ANSI code as they will change length of the
# string when it's mostly style/color changes.
col_size = len(regex.ansiRemove(col_value))
else:
col_value = str(value)
@ -562,7 +562,8 @@ class Table(object):
@classmethod
def fromListDict(
cls, host, data, keys=None, headers=None, filters=None, defaults=None):
cls, host, data, keys=None, headers=None, filters=None, defaults=None
):
"""Create a table from a list of dictionaries
each dictionary is a row of the table, keys being columns names.
@ -694,13 +695,13 @@ class Table(object):
bottom_sep = col_sep_size * bottom
if not show_borders:
left = right = head_line_left = head_line_right = ""
# top border
# top border
if show_borders:
self._disp(
top_left + top_sep.join([top * size for size in sizes]) + top_right
)
# headers
# headers
if show_header and self.headers is not None:
self._disp(
left
@ -714,7 +715,7 @@ class Table(object):
+ head_line_right
)
# content
# content
if columns_alignment == "left":
alignment = lambda idx, s: ansi_ljust(s, sizes[idx])
elif columns_alignment == "center":
@ -740,7 +741,7 @@ class Table(object):
+ bottom_sep.join([bottom * size for size in sizes])
+ bottom_right
)
#  we return self so string can be used after display (table.display().string)
#  we return self so string can be used after display (table.display().string)
return self
def display_blank(self, **kwargs):
@ -781,8 +782,10 @@ async def fill_well_known_uri(command, path, key, meta_map=None):
uri_data = uris_data[key]
except KeyError:
host.disp(
_(f"No {key} URI specified for this project, please specify service and "
f"node"),
_(
"No {key} URI specified for this project, please specify service and "
"node"
).format(key=key),
error=True,
)
host.quit(C.EXIT_NOT_FOUND)
@ -790,7 +793,7 @@ async def fill_well_known_uri(command, path, key, meta_map=None):
uri = uri_data["uri"]
# set extra metadata if they are specified
for data_key in ['labels']:
for data_key in ["labels"]:
new_values_json = uri_data.get(data_key)
if uri_data is not None:
if meta_map is None:
@ -803,7 +806,7 @@ async def fill_well_known_uri(command, path, key, meta_map=None):
try:
values = getattr(args, data_key)
except AttributeError:
raise exceptions.InternalError(f'there is no {data_key!r} arguments')
raise exceptions.InternalError(f"there is no {data_key!r} arguments")
else:
if values is None:
values = []
@ -815,5 +818,5 @@ async def fill_well_known_uri(command, path, key, meta_map=None):
args.service = parsed_uri["path"]
args.node = parsed_uri["node"]
except KeyError:
host.disp(_(f"Invalid URI found: {uri}"), error=True)
host.disp(_("Invalid URI found: {uri}").format(uri=uri), error=True)
host.quit(C.EXIT_DATA_ERROR)

View file

@ -174,12 +174,11 @@ class OptionsWidget(Widget):
class EmptyWidget(xmlui_base.EmptyWidget, Widget):
def __init__(self, xmlui_parent):
Widget.__init__(self, xmlui_parent)
async def show(self):
self.host.disp('')
self.host.disp("")
class TextWidget(xmlui_base.TextWidget, ValueWidget):
@ -199,7 +198,7 @@ class LabelWidget(xmlui_base.LabelWidget, ValueWidget):
except AttributeError:
return None
async def show(self, end='\n', ansi=""):
async def show(self, end="\n", ansi=""):
"""show label
@param end(str): same as for [JP.disp]
@ -211,6 +210,7 @@ class LabelWidget(xmlui_base.LabelWidget, ValueWidget):
class JidWidget(xmlui_base.JidWidget, TextWidget):
type = "jid"
class StringWidget(xmlui_base.StringWidget, InputWidget):
type = "string"
@ -221,7 +221,7 @@ class StringWidget(xmlui_base.StringWidget, InputWidget):
elems = []
self.verboseName(elems)
if self.value:
elems.append(_(f"(enter: {self.value})"))
elems.append(_("(enter: {value})").format(value=self.value))
elems.extend([C.A_HEADER, "> "])
value = await self.host.ainput(A.color(*elems))
if value:
@ -244,21 +244,24 @@ class TextBoxWidget(xmlui_base.TextWidget, StringWidget):
self.disp(self.value)
else:
if self.value:
self.disp(A.color(C.A_HEADER, "↓ current value ↓\n", A.FG_CYAN, self.value,
""))
self.disp(
A.color(C.A_HEADER, "↓ current value ↓\n", A.FG_CYAN, self.value, "")
)
values = []
while True:
try:
if not values:
line = await self.host.ainput(A.color(C.A_HEADER, "[Ctrl-D to finish]> "))
line = await self.host.ainput(
A.color(C.A_HEADER, "[Ctrl-D to finish]> ")
)
else:
line = await self.host.ainput()
values.append(line)
except EOFError:
break
break
self.value = '\n'.join(values).rstrip()
self.value = "\n".join(values).rstrip()
class XHTMLBoxWidget(xmlui_base.XHTMLBoxWidget, StringWidget):
@ -269,7 +272,8 @@ class XHTMLBoxWidget(xmlui_base.XHTMLBoxWidget, StringWidget):
# this only for now to make it simpler, it must be refactored
# to use async when jp will be fully async (expected for 0.8)
self.value = await self.host.bridge.syntaxConvert(
self.value, C.SYNTAX_XHTML, "markdown", False, self.host.profile)
self.value, C.SYNTAX_XHTML, "markdown", False, self.host.profile
)
await super(XHTMLBoxWidget, self).show()
@ -285,7 +289,7 @@ class ListWidget(xmlui_base.ListWidget, OptionsWidget):
if not self.options:
return
# list display
# list display
self.verboseName()
for idx, (value, label) in enumerate(self.options):
@ -304,12 +308,15 @@ class ListWidget(xmlui_base.ListWidget, OptionsWidget):
self.value = self.options[0][0]
return
#  we ask use to choose an option
#  we ask use to choose an option
choice = None
limit_max = len(self.options) - 1
while choice is None or choice < 0 or choice > limit_max:
choice = await self.host.ainput(
A.color(C.A_HEADER, _(f"your choice (0-{limit_max}): "))
A.color(
C.A_HEADER,
_("your choice (0-{limit_max}): ").format(limit_max=limit_max),
)
)
try:
choice = int(choice)
@ -328,12 +335,14 @@ class BoolWidget(xmlui_base.BoolWidget, InputWidget):
if self.read_only or self.root.read_only:
self.disp(disp_true if self.value else disp_false)
else:
self.disp(A.color(C.A_HEADER, "0: ",
disp_false, A.RESET,
" *" if not self.value else ""))
self.disp(A.color(C.A_HEADER, "1: ",
disp_true, A.RESET,
" *" if self.value else ""))
self.disp(
A.color(
C.A_HEADER, "0: ", disp_false, A.RESET, " *" if not self.value else ""
)
)
self.disp(
A.color(C.A_HEADER, "1: ", disp_true, A.RESET, " *" if self.value else "")
)
choice = None
while choice not in ("0", "1"):
elems = [C.A_HEADER, _("your choice (0,1): ")]
@ -345,8 +354,7 @@ class BoolWidget(xmlui_base.BoolWidget, InputWidget):
def _xmluiGetValue(self):
return C.boolConst(self.value)
## Containers ##
## Containers ##
class Container(Base):
@ -383,7 +391,7 @@ class LabelContainer(xmlui_base.PairsContainer, Container):
async def show(self):
for child in self.children:
end = '\n'
end = "\n"
# we check linked widget type
# to see if we want the label on the same line or not
if child.type == "label":
@ -396,15 +404,14 @@ class LabelContainer(xmlui_base.PairsContainer, Container):
"string",
"jid_input",
):
end = ' '
end = " "
elif wid_type == "bool" and for_widget.read_only:
end = ' '
end = " "
await child.show(end=end, ansi=A.FG_CYAN)
else:
await child.show()
## Dialogs ##
## Dialogs ##
class Dialog(object):
@ -422,8 +429,8 @@ class Dialog(object):
"""
raise NotImplementedError(self.__class__)
class MessageDialog(xmlui_base.MessageDialog, Dialog):
class MessageDialog(xmlui_base.MessageDialog, Dialog):
def __init__(self, xmlui_parent, title, message, level):
Dialog.__init__(self, xmlui_parent)
xmlui_base.MessageDialog.__init__(self, xmlui_parent)
@ -437,7 +444,6 @@ class MessageDialog(xmlui_base.MessageDialog, Dialog):
class NoteDialog(xmlui_base.NoteDialog, Dialog):
def __init__(self, xmlui_parent, title, message, level):
Dialog.__init__(self, xmlui_parent)
xmlui_base.NoteDialog.__init__(self, xmlui_parent)
@ -456,12 +462,15 @@ class NoteDialog(xmlui_base.NoteDialog, Dialog):
class ConfirmDialog(xmlui_base.ConfirmDialog, Dialog):
def __init__(self, xmlui_parent, title, message, level, buttons_set):
Dialog.__init__(self, xmlui_parent)
xmlui_base.ConfirmDialog.__init__(self, xmlui_parent)
self.title, self.message, self.level, self.buttons_set = (
title, message, level, buttons_set)
title,
message,
level,
buttons_set,
)
async def show(self):
# TODO: handle buttons_set and level
@ -469,16 +478,15 @@ class ConfirmDialog(xmlui_base.ConfirmDialog, Dialog):
if self.title:
self.disp(A.color(C.A_HEADER, self.title))
input_ = None
while input_ not in ('y', 'n'):
while input_ not in ("y", "n"):
input_ = await self.host.ainput(f"{self.message} (y/n)? ")
input_ = input_.lower()
if input_ == 'y':
if input_ == "y":
self._xmluiValidated()
else:
self._xmluiCancelled()
## Factory ##
## Factory ##
class WidgetFactory(object):
@ -496,8 +504,17 @@ class XMLUIPanel(xmlui_base.AIOXMLUIPanel):
workflow = None
_submit_cb = None
def __init__(self, host, parsed_dom, title=None, flags=None, callback=None,
ignore=None, whitelist=None, profile=None):
def __init__(
self,
host,
parsed_dom,
title=None,
flags=None,
callback=None,
ignore=None,
whitelist=None,
profile=None,
):
xmlui_base.XMLUIPanel.__init__(
self,
host,
@ -588,7 +605,7 @@ class XMLUIPanel(xmlui_base.AIOXMLUIPanel):
await xmlui.show()
if xmlui.submit_id:
await xmlui.onFormSubmitted()
# TODO: handle data other than XMLUI
# TODO: handle data other than XMLUI
if not XMLUIPanel._actions:
if self._submit_cb is None:
self.host.quit()
@ -622,6 +639,7 @@ class XMLUIDialog(xmlui_base.XMLUIDialog):
pass
create = partial(xmlui_base.create, class_map={
xmlui_base.CLASS_PANEL: XMLUIPanel,
xmlui_base.CLASS_DIALOG: XMLUIDialog})
create = partial(
xmlui_base.create,
class_map={xmlui_base.CLASS_PANEL: XMLUIPanel, xmlui_base.CLASS_DIALOG: XMLUIDialog},
)