diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 764f904c94..b93d168ab5 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -920,6 +920,13 @@ def _raw_main(args, lib=None): help=optparse.SUPPRESS_HELP) options, subargs = parser.parse_global_options(args) + + # Bypass _setup so that an invalid configuration does not prevent + # the editor from starting. + if subargs[0] == 'config' and ('-e' in subargs or '--edit' in subargs): + from beets.ui.commands import config_edit + return config_edit() + subcommands, plugins, lib = _setup(options, lib) parser.add_subcommand(*subcommands) diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 855ae27482..910fe02432 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -1485,32 +1485,38 @@ def config_func(lib, opts, args): # Open in editor. elif opts.edit: - path = config.user_config_path() - - if 'EDITOR' in os.environ: - editor = os.environ['EDITOR'] - args = [editor, editor, path] - elif platform.system() == 'Darwin': - args = ['open', 'open', '-n', path] - elif platform.system() == 'Windows': - # On windows we can execute arbitrary files. The os will - # take care of starting an appropriate application - args = [path, path] - else: - # Assume Unix - args = ['xdg-open', 'xdg-open', path] - - try: - os.execlp(*args) - except OSError: - raise ui.UserError("Could not edit configuration. Please" - "set the EDITOR environment variable.") + config_edit() # Dump configuration. else: print(config.dump(full=opts.defaults)) +def config_edit(): + """Open a program to edit the user configuration. + """ + path = config.user_config_path() + + if 'EDITOR' in os.environ: + editor = os.environ['EDITOR'] + args = [editor, editor, path] + elif platform.system() == 'Darwin': + args = ['open', 'open', '-n', path] + elif platform.system() == 'Windows': + # On windows we can execute arbitrary files. The os will + # take care of starting an appropriate application + args = [path, path] + else: + # Assume Unix + args = ['xdg-open', 'xdg-open', path] + + try: + os.execlp(*args) + except OSError: + raise ui.UserError("Could not edit configuration. Please" + "set the EDITOR environment variable.") + + config_cmd = ui.Subcommand('config', help='show or edit the user configuration') config_cmd.parser.add_option( diff --git a/test/test_config_command.py b/test/test_config_command.py index 442be97845..b68b5bab9c 100644 --- a/test/test_config_command.py +++ b/test/test_config_command.py @@ -10,6 +10,7 @@ import _common from _common import unittest from helper import TestHelper, capture_stdout +from beets.library import Library class ConfigCommandTest(unittest.TestCase, TestHelper): @@ -105,6 +106,19 @@ def test_config_editor_not_found(self): self.assertIn('Could not edit configuration', str(user_error.exception.args[0])) + def test_edit_invalid_config_file(self): + self.lib = Library(':memory:') + with open(self.config_path, 'w') as file: + file.write('invalid: [') + config.clear() + config._materialized = False + + os.environ['EDITOR'] = 'myeditor' + with patch('os.execlp') as execlp: + self.run_command('config', '-e') + execlp.assert_called_once_with( + 'myeditor', 'myeditor', self.config_path) + def suite(): return unittest.TestLoader().loadTestsFromName(__name__)