[UI] [#1973] Improve passing extra args to UIs

Current solution for passing arguments to UI when invoking deluge
entry script is to select an UI with the --ui option and supply quoted
arguments with the --args option.

This patch cleans this up by removing both options and change to using
subparsers for valid UIs. All command line options are now parsed
directly by the child UI which is chosen by a positional argument,
i.e. the UI name.

The help text now also shows the current default UI.
This commit is contained in:
bendikro 2016-05-10 18:48:13 +02:00 committed by Calum Lind
parent d6fec88932
commit d689ad72e8
10 changed files with 436 additions and 116 deletions

View File

@ -1,16 +1,78 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import argparse
import exceptions
import StringIO
import sys
import mock
import pytest
import deluge.component as component
import deluge.ui.console
import deluge.ui.web.server
from deluge.ui import ui_entry
from deluge.ui.web.server import DelugeWeb
from . import common
from .basetest import BaseTestCase
sys_stdout = sys.stdout
class TestStdout(object):
def __init__(self, fd):
self.out = StringIO.StringIO()
self.fd = fd
for a in ["encoding"]:
setattr(self, a, getattr(sys_stdout, a))
def write(self, *data, **kwargs):
print(data, file=self.out)
def flush(self):
self.out.flush()
class DelugeEntryTestCase(BaseTestCase):
def set_up(self):
common.set_tmp_config_dir()
return component.start()
def tear_down(self):
return component.shutdown()
def test_deluge_help(self):
self.patch(sys, "argv", ["./deluge", "-h"])
config = deluge.configmanager.ConfigManager("ui.conf", ui_entry.DEFAULT_PREFS)
config.config["default_ui"] = "console"
config.save()
fd = TestStdout(sys.stdout)
self.patch(argparse._sys, "stdout", fd)
with mock.patch("deluge.ui.console.main.ConsoleUI"):
self.assertRaises(exceptions.SystemExit, ui_entry.start_ui)
self.assertTrue("usage: deluge" in fd.out.getvalue())
self.assertTrue("UI Options:" in fd.out.getvalue())
self.assertTrue("* console" in fd.out.getvalue())
def test_start_default(self):
self.patch(sys, "argv", ["./deluge"])
config = deluge.configmanager.ConfigManager("ui.conf", ui_entry.DEFAULT_PREFS)
config.config["default_ui"] = "console"
config.save()
with mock.patch("deluge.ui.console.main.ConsoleUI"):
# Just test that no exception is raised
ui_entry.start_ui()
@pytest.mark.gtkui
class UIEntryTestCase(BaseTestCase):
class GtkUIEntryTestCase(BaseTestCase):
def set_up(self):
common.set_tmp_config_dir()
@ -20,30 +82,108 @@ class UIEntryTestCase(BaseTestCase):
return component.shutdown()
def test_start_gtkui(self):
import deluge.ui.gtkui.gtkui
import sys
self.patch(sys, "argv", ['./deluge', "--ui", 'gtk'])
self.patch(sys, "argv", ["./deluge", "gtk"])
with mock.patch.object(deluge.ui.gtkui.gtkui.GtkUI, 'start', autospec=True):
from deluge.ui.gtkui import gtkui
with mock.patch.object(gtkui.GtkUI, "start", autospec=True):
ui_entry.start_ui()
def test_start_console(self):
import sys
self.patch(sys, "argv", ['./deluge', "--ui", 'console'])
with mock.patch('deluge.ui.console.main.ConsoleUI'):
ui_entry.start_ui()
class WebUIEntryTestCase(BaseTestCase):
def set_up(self):
common.set_tmp_config_dir()
return component.start()
def tear_down(self):
return component.shutdown()
def test_start_webserver(self):
import sys
from deluge.ui.web.server import DelugeWeb
self.patch(sys, "argv", ['./deluge', "--ui", 'web', '--do-not-daemonize'])
self.patch(sys, "argv", ["./deluge", "web", "--do-not-daemonize"])
class DelugeWebMock(DelugeWeb):
def __init__(self, *args, **kwargs):
kwargs["daemon"] = False
DelugeWeb.__init__(self, *args, **kwargs)
import deluge.ui.web.server
self.patch(deluge.ui.web.server, 'DelugeWeb', DelugeWebMock)
self.patch(deluge.ui.web.server, "DelugeWeb", DelugeWebMock)
ui_entry.start_ui()
class ConsoleUIBaseTestCase(object):
def __init__(self):
self.var = dict()
def set_up(self):
common.set_tmp_config_dir()
return component.start()
def tear_down(self):
return component.shutdown()
def test_start_console(self):
self.patch(sys, "argv", self.var["sys_arg_cmd"])
with mock.patch("deluge.ui.console.main.ConsoleUI"):
self.var["start_cmd"]()
def test_console_help(self):
self.patch(sys, "argv", self.var["sys_arg_cmd"] + ["-h"])
fd = TestStdout(sys.stdout)
self.patch(argparse._sys, "stdout", fd)
with mock.patch("deluge.ui.console.main.ConsoleUI"):
self.assertRaises(exceptions.SystemExit, self.var["start_cmd"])
std_output = fd.out.getvalue()
self.assertTrue(("usage: %s" % self.var["cmd_name"]) in std_output) # Check command name
self.assertTrue("Common Options:" in std_output)
self.assertTrue("Console Options:" in std_output)
self.assertTrue(r"Console commands:\n The following console commands are available:" in std_output)
self.assertTrue("The following console commands are available:" in std_output)
def test_console_command_info(self):
self.patch(sys, "argv", self.var["sys_arg_cmd"] + ["info"])
fd = TestStdout(sys.stdout)
self.patch(argparse._sys, "stdout", fd)
with mock.patch("deluge.ui.console.main.ConsoleUI"):
self.var["start_cmd"]()
def test_console_command_info_help(self):
self.patch(sys, "argv", self.var["sys_arg_cmd"] + ["info", "-h"])
fd = TestStdout(sys.stdout)
self.patch(argparse._sys, "stdout", fd)
with mock.patch("deluge.ui.console.main.ConsoleUI"):
self.assertRaises(exceptions.SystemExit, self.var["start_cmd"])
std_output = fd.out.getvalue()
self.assertTrue("usage: info" in std_output)
self.assertTrue("Show information about the torrents" in std_output)
def test_console_unrecognized_arguments(self):
self.patch(sys, "argv", ["./deluge", "--ui", "console"]) # --ui is not longer supported
fd = TestStdout(sys.stdout)
self.patch(argparse._sys, "stderr", fd)
with mock.patch("deluge.ui.console.main.ConsoleUI"):
self.assertRaises(exceptions.SystemExit, self.var["start_cmd"])
self.assertTrue("unrecognized arguments: --ui" in fd.out.getvalue())
class ConsoleUIEntryTestCase(BaseTestCase, ConsoleUIBaseTestCase):
def __init__(self, testname):
BaseTestCase.__init__(self, testname)
ConsoleUIBaseTestCase.__init__(self)
self.var["cmd_name"] = "deluge console"
self.var["start_cmd"] = ui_entry.start_ui
self.var["sys_arg_cmd"] = ["./deluge", "console"]
class ConsoleUIScriptTestCase(BaseTestCase, ConsoleUIBaseTestCase):
def __init__(self, testname):
BaseTestCase.__init__(self, testname)
ConsoleUIBaseTestCase.__init__(self)
self.var["cmd_name"] = "deluge-console"
self.var["start_cmd"] = deluge.ui.console.start
self.var["sys_arg_cmd"] = ["./deluge-console"]

View File

@ -20,6 +20,69 @@ from deluge.configmanager import get_config_dir, set_config_dir
from deluge.log import setup_logger
def find_subcommand(self, args=None):
"""Find if a subcommand has been supplied.
Args:
args (list, optional): The argument list handed to parse_args().
Returns:
int: Index of the subcommand or '-1' if none found.
"""
subcommand_found = -1
test_args = args if args else sys.argv[1:]
for x in self._subparsers._actions:
if not isinstance(x, argparse._SubParsersAction):
continue
for sp_name in x._name_parser_map.keys():
if sp_name in test_args:
subcommand_found = test_args.index(sp_name) + 1
return subcommand_found
def set_default_subparser(self, name, abort_opts=None):
"""Sets the default argparse subparser.
Args:
name (str): The name of the default subparser.
abort_opts (list): The arguments to test for in case no subcommand is found.
If any of the values are found, the default subparser will
not be inserted into sys.argv.
Returns:
list: The arguments found in sys.argv if no subcommand found, else None
"""
found_abort_opts = []
abort_opts = [] if abort_opts is None else abort_opts
test_args = sys.argv[1:]
subparser_found = self.find_subcommand(args=test_args)
for i, arg in enumerate(test_args):
if subparser_found == i:
break
if arg in abort_opts:
found_abort_opts.append(arg)
if subparser_found == -1:
if found_abort_opts:
# Found one or more of arguments in abort_opts
return found_abort_opts
# insert default in first position, this implies no
# global options without a sub_parsers specified
sys.argv.insert(1, name)
return None
argparse.ArgumentParser.find_subcommand = find_subcommand
argparse.ArgumentParser.set_default_subparser = set_default_subparser
def get_version():
version_str = "%s\n" % (common.get_version())
try:
@ -33,8 +96,7 @@ def get_version():
class DelugeTextHelpFormatter(argparse.RawDescriptionHelpFormatter):
"""Help message formatter which retains formatting of all help text.
"""
"""Help message formatter which retains formatting of all help text."""
def _split_lines(self, text, width):
"""
@ -80,9 +142,9 @@ class HelpAction(argparse._HelpAction):
def __call__(self, parser, namespace, values, option_string=None):
if hasattr(parser, "subparser"):
subparser = getattr(parser, "subparser")
# If -h on a subparser is given, the subparser will exit after help message
subparser.parse_args()
parser.print_help()
subparser.print_help()
else:
parser.print_help()
parser.exit()
@ -91,13 +153,16 @@ class BaseArgParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
if "formatter_class" not in kwargs:
kwargs["formatter_class"] = lambda prog: DelugeTextHelpFormatter(prog, max_help_position=33, width=90)
super(BaseArgParser, self).__init__(*args, add_help=False, **kwargs)
kwargs["add_help"] = kwargs.get("add_help", False)
common_help = kwargs.pop("common_help", True)
super(BaseArgParser, self).__init__(*args, **kwargs)
self.common_setup = False
self.process_arg_group = False
self.group = self.add_argument_group(_("Common Options"))
self.group.add_argument("-h", "--help", action=HelpAction,
help=_("Print this help message"))
if common_help:
self.group.add_argument("-h", "--help", action=HelpAction,
help=_("Print this help message"))
self.group.add_argument("-V", "--version", action="version", version="%(prog)s " + get_version(),
help=_("Print version information"))
self.group.add_argument("-v", action="version", version="%(prog)s " + get_version(),
@ -117,9 +182,22 @@ class BaseArgParser(argparse.ArgumentParser):
help=_("Profile %(prog)s with cProfile. Outputs to stdout "
"unless a filename is specified"))
def parse_args(self, *args):
options, remaining = super(BaseArgParser, self).parse_known_args(*args)
def parse_args(self, args=None):
"""Parse UI arguments and handle common and process group options.
Unknown arguments return an error and resulting usage text.
"""
options = super(BaseArgParser, self).parse_args(args=args)
return self._parse_args(options)
def parse_known_ui_args(self, args=None):
"""Parse UI arguments and handle common and process group options without error.
"""
options, remaining = super(BaseArgParser, self).parse_known_args(args=args)
options.remaining = remaining
return self._parse_args(options)
def _parse_args(self, options):
if not self.common_setup:
self.common_setup = True

View File

@ -32,10 +32,28 @@ class Commander(object):
print(strip_colors(line))
def do_command(self, cmd_line):
"""
Processes a command.
"""Run a console command
:param cmd: str, the command string
Args:
cmd_line (str): Console command
Returns:
Deferred: A deferred that fires when command has been executed
"""
options = self.parse_command(cmd_line)
if options:
return self.exec_command(options)
return defer.succeed(None)
def parse_command(self, cmd_line):
"""Parse a console command and process with argparse
Args:
cmd_line (str): Console command
Returns:
argparse.Namespace: The parsed command
"""
if not cmd_line:
@ -76,6 +94,7 @@ class Commander(object):
try:
options = parser.parse_args(args=args)
options.command = cmd
except TypeError as ex:
self.write("{!error!}Error parsing options: %s" % ex)
import traceback
@ -86,14 +105,28 @@ class Commander(object):
parser.print_help()
return
if not getattr(parser, "_exit", False):
try:
ret = self._commands[cmd].handle(options)
except Exception as ex:
self.write("{!error!} %s" % ex)
log.exception(ex)
import traceback
self.write("%s" % traceback.format_exc())
return defer.succeed(True)
else:
return ret
if getattr(parser, "_exit", False):
return
return options
def exec_command(self, options, *args):
"""
Execute a console command.
Args:
options (argparse.Namespace): The command to execute
Returns:
Deferred: A deferred that fires when command has been executed
"""
try:
ret = self._commands[options.command].handle(options)
except Exception as ex:
self.write("{!error!} %s" % ex)
log.exception(ex)
import traceback
self.write("%s" % traceback.format_exc())
return defer.succeed(True)
else:
return ret

View File

@ -92,7 +92,7 @@ class Command(BaseCommand):
epilog = """
You can give the first few characters of a torrent-id to identify the torrent.
Tab Completion (info *pattern*<tab>):\n
Tab Completion in interactive mode (info *pattern*<tab>):\n
| First press of <tab> will output up to 15 matches;
| hitting <tab> a second time, will print 15 more matches;
| and a third press will print all remaining matches.

View File

@ -53,7 +53,7 @@ class Console(UI):
cmd_description = """Console or command-line user interface"""
def __init__(self, *args, **kwargs):
super(Console, self).__init__("console", *args, description="Test", **kwargs)
super(Console, self).__init__(*args, **kwargs)
group = self.parser.add_argument_group(_("Console Options"), "These daemon connect options will be "
"used for commands, or if console ui autoconnect is enabled.")
@ -65,20 +65,25 @@ class Console(UI):
# To properly print help message for the console commands ( e.g. deluge-console info -h),
# we add a subparser for each command which will trigger the help/usage when given
from deluge.ui.console.main import ConsoleCommandParser # import here because (see top)
self.console_parser = ConsoleCommandParser(parents=[self.parser], add_help=False,
self.console_parser = ConsoleCommandParser(parents=[self.parser], add_help=False, prog=self.parser.prog,
description="Starts the Deluge console interface",
formatter_class=lambda prog:
DelugeTextHelpFormatter(prog, max_help_position=33, width=90))
self.parser.subparser = self.console_parser
subparsers = self.console_parser.add_subparsers(title="Console commands", help="Description", dest="commands",
self.console_parser.base_parser = self.parser
subparsers = self.console_parser.add_subparsers(title="Console commands", help="Description", dest="command",
description="The following console commands are available:",
metavar="command")
self.console_cmds = load_commands(os.path.join(UI_PATH, "commands"))
for c in sorted(self.console_cmds):
self.console_cmds[c].add_subparser(subparsers)
def start(self, args=None):
super(Console, self).start(args)
def start(self):
i = self.console_parser.find_subcommand(args=self.ui_args)
self.console_parser.subcommand = False
self.parser.subcommand = False if i == -1 else True
super(Console, self).start(self.console_parser)
from deluge.ui.console.main import ConsoleUI # import here because (see top)
def run(options):

View File

@ -24,6 +24,7 @@ from deluge.error import DelugeError
from deluge.ui.client import client
from deluge.ui.console import colors
from deluge.ui.console.colors import ConsoleColorFormatter
from deluge.ui.console.commander import Commander
from deluge.ui.console.eventlog import EventLog
from deluge.ui.console.statusbars import StatusBars
from deluge.ui.coreconfig import CoreConfig
@ -49,6 +50,58 @@ class ConsoleCommandParser(argparse.ArgumentParser):
self.epilog = epilog
return help_str
def _split_args(self, args):
command_options = []
for a in args:
if not a:
continue
if ";" in a:
cmd_lines = [arg.strip() for arg in a.split(";")]
elif " " in a:
cmd_lines = [a]
else:
continue
for cmd_line in cmd_lines:
cmds = shlex.split(cmd_line)
cmd_options = super(ConsoleCommandParser, self).parse_args(args=cmds)
cmd_options.command = cmds[0]
command_options.append(cmd_options)
return command_options
def parse_args(self, args=None):
multi_command = self._split_args(args)
# If multiple commands were passed to console
if multi_command:
# With multiple commands, normal parsing will fail, so only parse
# known arguments using the base parser, and then set
# options.parsed_cmds to the already parsed commands
options, remaining = self.base_parser.parse_known_args(args=args)
options.parsed_cmds = multi_command
else:
subcommand = False
if hasattr(self.base_parser, "subcommand"):
subcommand = getattr(self.base_parser, "subcommand")
if not subcommand:
# We must use parse_known_args to handle case when no subcommand
# is provided, because argparse does not support parsing without
# a subcommand
options, remaining = self.base_parser.parse_known_args(args=args)
# If any options remain it means they do not exist. Reparse with
# parse_args to trigger help message
if remaining:
options = self.base_parser.parse_args(args=args)
options.parsed_cmds = []
else:
options = super(ConsoleCommandParser, self).parse_args(args=args)
options.parsed_cmds = [options]
if not hasattr(options, "remaining"):
options.remaining = []
return options
class OptionParser(ConsoleCommandParser):
@ -130,6 +183,7 @@ class BaseCommand(object):
opts["usage"] = self.usage
parser = OptionParser(**opts)
parser.add_argument(self.name, metavar="")
parser.base_parser = parser
self.add_arguments(parser)
return parser
@ -167,8 +221,7 @@ class ConsoleUI(component.Component):
# Set the interactive flag to indicate where we should print the output
self.interactive = True
self._commands = cmds
if options.remaining:
if options.parsed_cmds:
self.interactive = False
if not cmds:
print("Sorry, couldn't find any commands")
@ -194,14 +247,6 @@ Please use commands from the command line, e.g.:\n
reactor.run()
def exec_args(self, options):
args = options.remaining
commands = []
if args:
cmd = " ".join([arg for arg in args])
# Multiple commands split by ";"
commands += [arg.strip() for arg in cmd.split(";")]
from deluge.ui.console.commander import Commander
commander = Commander(self._commands)
def on_connect(result):
@ -209,11 +254,14 @@ Please use commands from the command line, e.g.:\n
def on_started(result):
def do_command(result, cmd):
return commander.do_command(cmd)
def exec_command(result, cmd):
return commander.exec_command(cmd)
d = defer.succeed(None)
for command in commands:
if command in ("quit", "exit"):
for command in options.parsed_cmds:
if command.command in ("quit", "exit"):
break
d.addCallback(do_command, command)
d.addCallback(exec_command, command)
d.addCallback(do_command, "quit")
# We need to wait for the rpcs in start() to finish before processing
@ -230,17 +278,9 @@ Please use commands from the command line, e.g.:\n
commander.do_command("quit")
d = None
if not self.interactive:
if commands[0] is not None:
if commands[0].startswith("connect"):
d = commander.do_command(commands.pop(0))
if d is None:
# Error parsing command
sys.exit(0)
elif "help" in commands:
commander.do_command("help")
sys.exit(0)
if not d:
if not self.interactive and options.parsed_cmds[0].command == "connect":
d = commander.do_command(options.parsed_cmds.pop(0))
else:
log.info("connect: host=%s, port=%s, username=%s, password=%s",
options.daemon_addr, options.daemon_port, options.daemon_user, options.daemon_pass)
d = client.connect(options.daemon_addr, options.daemon_port, options.daemon_user, options.daemon_pass)

View File

@ -27,8 +27,8 @@ class Gtk(UI):
help=_("Add one or more torrent files, torrent URLs or magnet URIs"
" to a currently running Deluge GTK instance"))
def start(self, args=None):
super(Gtk, self).start(args)
def start(self):
super(Gtk, self).start()
from deluge.ui.gtkui.gtkui import GtkUI
import deluge.common

View File

@ -25,16 +25,20 @@ except ImportError:
class UI(object):
"""
Base class for UI implementations.
cmd_description = """Insert command description"""
"""
cmd_description = """Override with command description"""
def __init__(self, name="gtk", parser=None, **kwargs):
def __init__(self, name="gtk", **kwargs):
self.__name = name
self.ui_args = kwargs.pop("ui_args", None)
lang.setup_translations(setup_pygtk=(name == "gtk"))
self.__parser = parser if parser else BaseArgParser(**kwargs)
self.__parser = BaseArgParser(**kwargs)
def parse_args(self, args=None):
options = self.parser.parse_args(args)
def parse_args(self, parser, args=None):
options = parser.parse_args(args)
if not hasattr(options, "remaining"):
options.remaining = []
return options
@ -51,12 +55,11 @@ class UI(object):
def options(self):
return self.__options
def start(self, extra_args=None):
def start(self, parser=None):
args = deluge.common.unicode_argv()[1:]
if extra_args:
args.extend(extra_args)
self.__options = self.parse_args(args)
if parser is None:
parser = self.parser
self.__options = self.parse_args(parser, args)
setproctitle("deluge-%s" % self.__name)

View File

@ -13,7 +13,9 @@
"""Main starting point for Deluge"""
import argparse
import logging
import os
import sys
import pkg_resources
@ -32,27 +34,29 @@ def start_ui():
"""Entry point for ui script"""
lang.setup_translations()
# Setup the argument parser
parser = BaseArgParser()
group = parser.add_argument_group(_("UI Options"))
# Get the registered UI entry points
ui_entrypoints = dict([(entrypoint.name, entrypoint.load())
for entrypoint in pkg_resources.iter_entry_points("deluge.ui")])
ui_titles = sorted(ui_entrypoints.keys())
cmd_help = [_("The UI that you wish to launch. The UI choices are:")]
cmd_help.extend(["%s -- %s" % (k, getattr(v, "cmd_description", "")) for k, v in ui_entrypoints.iteritems()])
def add_ui_options_group(_parser):
"""Function to enable reuse of UI Options group"""
group = _parser.add_argument_group(_("UI Options"))
group.add_argument("-s", "--set-default-ui", dest="default_ui", choices=ui_titles,
help=_("Set the default UI to be run, when no UI is specified"))
return _parser
group.add_argument("-u", "--ui", action="store",
choices=ui_entrypoints.keys(), help="\n * ".join(cmd_help))
group.add_argument("-a", "--args", action="store",
help=_('Arguments to pass to the UI. Multiple args must be quoted, e.g. -a "--option args"'))
group.add_argument("-s", "--set-default-ui", dest="default_ui", choices=ui_entrypoints.keys(),
help=_("Sets the default UI to be run when no UI is specified"), action="store")
# Setup parser with Common Options and add UI Options group.
parser = add_ui_options_group(BaseArgParser())
options = parser.parse_args(deluge.common.unicode_argv()[1:])
ambiguous_args = ["-h", "--help", "-v", "-V", "--version"]
# Parse arguments without help/version as this is handled later.
args = [a for a in sys.argv if a not in ambiguous_args]
options = parser.parse_known_ui_args(args)
config = deluge.configmanager.ConfigManager("ui.conf", DEFAULT_PREFS)
log = logging.getLogger(__name__)
log.info("Deluge ui %s", deluge.common.get_version())
if options.default_ui:
config["default_ui"] = options.default_ui
@ -60,37 +64,54 @@ def start_ui():
log.info("The default UI has been changed to %s", options.default_ui)
sys.exit(0)
log.info("Deluge ui %s", deluge.common.get_version())
log.debug("options: %s", options)
selected_ui = options.ui if options.ui else config["default_ui"]
config.save()
default_ui = config["default_ui"]
config.save() # Save in case config didn't already exist.
del config
# reconstruct arguments to hand off to child client
client_args = []
if options.args:
import shlex
client_args.extend(shlex.split(options.args))
# We have parsed and got the config dir needed to get the default UI
# Now create a parser for choosing the UI. We reuse the ui option group for
# parsing to succeed and the text displayed to user, but result is not used.
parser = add_ui_options_group(BaseArgParser(common_help=True))
# Create subparser for each registered UI. Empty title is used to remove unwanted positional text.
subparsers = parser.add_subparsers(dest="selected_ui", metavar="{%s} [UI args]" % ",".join(ui_titles), title=None,
help=_("Alternative UI to launch, with optional ui args \n (default UI: *)"))
for ui in ui_titles:
parser_ui = subparsers.add_parser(ui, common_help=False,
help=getattr(ui_entrypoints[ui], "cmd_description", ""))
parser_ui.add_argument("ui_args", nargs=argparse.REMAINDER)
# If the UI is set as default, indicate this in help by prefixing with a star.
subactions = subparsers._get_subactions()
prefix = "*" if ui == default_ui else " "
subactions[-1].dest = "%s %s" % (prefix, ui)
# Insert a default UI subcommand unless one of the ambiguous_args are specified
parser.set_default_subparser(default_ui, abort_opts=ambiguous_args)
# Only parse known arguments to leave the UIs to show a help message if parsing fails.
options, remaining = parser.parse_known_args()
selected_ui = options.selected_ui
ui_args = remaining + options.ui_args
# Remove the UI argument before launching the UI.
sys.argv.remove(selected_ui)
try:
ui = ui_entrypoints[selected_ui](parser=parser)
ui = ui_entrypoints[selected_ui](prog="%s %s" % (os.path.basename(sys.argv[0]), selected_ui), ui_args=ui_args)
except KeyError as ex:
log.error("Unable to find the requested UI: '%s'. Please select a different UI with the '-u' option"
" or alternatively use the '-s' option to select a different default UI.", selected_ui)
log.error("Unable to find chosen UI: '%s'. Please choose a different UI "
"or use '--set-default-ui' to change default UI.", selected_ui)
except ImportError as ex:
import traceback
error_type, error_value, tb = sys.exc_info()
stack = traceback.extract_tb(tb)
last_frame = stack[-1]
if last_frame[0] == __file__:
log.error("Unable to find the requested UI: %s. Please select a different UI with the '-u' "
"option or alternatively use the '-s' option to select a different default UI.", selected_ui)
log.error("Unable to find chosen UI: '%s'. Please choose a different UI "
"or use '--set-default-ui' to change default UI.", selected_ui)
else:
log.exception(ex)
log.error("There was an error whilst launching the request UI: %s", selected_ui)
log.error("Look at the traceback above for more information.")
log.error("Encountered an error launching the request UI: %s", selected_ui)
sys.exit(1)
else:
ui.start(client_args)
ui.start()

View File

@ -42,8 +42,8 @@ class Web(UI):
def server(self):
return self.__server
def start(self, args=None):
super(Web, self).start(args)
def start(self):
super(Web, self).start()
from deluge.ui.web import server
self.__server = server.DelugeWeb(options=self.options)