handle user-visible exceptions at top level

This makes error messages more friendly (i.e., traceback-free) when exceptions
occur during UI setup -- e.g., unopenable database.
This commit is contained in:
Adrian Sampson 2012-08-27 22:45:28 -07:00
parent 08d8e6c55b
commit af2a329477
2 changed files with 17 additions and 6 deletions

View file

@ -76,6 +76,9 @@ NULL_REPLACE = '<strip>'
class UserError(Exception): class UserError(Exception):
pass pass
# Main logger.
log = logging.getLogger('beets')
# Utilities. # Utilities.
@ -674,8 +677,10 @@ class SubcommandsOptionParser(optparse.OptionParser):
# The root parser and its main function. # The root parser and its main function.
def main(args=None, configfh=None): def _raw_main(args, configfh):
"""Run the main command-line interface for beets.""" """A helper function for `main` without top-level exception
handling.
"""
# Get the default subcommands. # Get the default subcommands.
from beets.ui.commands import default_commands from beets.ui.commands import default_commands
@ -750,7 +755,6 @@ def main(args=None, configfh=None):
plugins.send("library_opened", lib=lib) plugins.send("library_opened", lib=lib)
# Configure the logger. # Configure the logger.
log = logging.getLogger('beets')
if options.verbose: if options.verbose:
log.setLevel(logging.DEBUG) log.setLevel(logging.DEBUG)
else: else:
@ -760,11 +764,18 @@ def main(args=None, configfh=None):
log.debug(u'library directory: %s' % util.displayable_path(lib.directory)) log.debug(u'library directory: %s' % util.displayable_path(lib.directory))
# Invoke the subcommand. # Invoke the subcommand.
subcommand.func(lib, config, suboptions, subargs)
def main(args=None, configfh=None):
"""Run the main command-line interface for beets. Includes top-level
exception handlers that print friendly error messages.
"""
try: try:
subcommand.func(lib, config, suboptions, subargs) _raw_main(args, configfh)
except UserError as exc: except UserError as exc:
message = exc.args[0] if exc.args else None message = exc.args[0] if exc.args else None
subcommand.parser.error(message) log.error(u'error: {0}'.format(message))
sys.exit(1)
except util.HumanReadableException as exc: except util.HumanReadableException as exc:
exc.log(log) exc.log(log)
sys.exit(1) sys.exit(1)

View file

@ -507,7 +507,7 @@ class ConfigTest(unittest.TestCase):
commands.default_commands.pop() commands.default_commands.pop()
def _run_main(self, args, config, func): def _run_main(self, args, config, func):
self.test_cmd.func = func self.test_cmd.func = func
ui.main(args + ['test'], StringIO(config)) ui._raw_main(args + ['test'], StringIO(config))
def test_paths_section_respected(self): def test_paths_section_respected(self):
def func(lib, config, opts, args): def func(lib, config, opts, args):