diff --git a/beets/ui/commands.py b/beets/ui/commands.py index cc5b14cfe..a4cd77763 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -1145,6 +1145,24 @@ def modify_items(lib, mods, dels, query, write, move, album, confirm): for item in changed_items: item.try_write() + +def modify_parse_args(args): + """Split the arguments for the modify subcommand into query parts, + assignments (field=value), and deletions (field!). Returns the result as + a three-tuple in that order. + """ + mods = [] + dels = [] + query = [] + for arg in args: + if arg.endswith('!') and '=' not in arg and ':' not in arg: + dels.append(arg[:-1]) # Strip trailing !. + elif '=' in arg and ':' not in arg.split('=', 1)[0]: + mods.append(arg) + else: + query.append(arg) + return (query, mods, dels) + modify_cmd = ui.Subcommand('modify', help='change metadata fields', aliases=('mod',)) modify_cmd.parser.add_option('-M', '--nomove', action='store_false', @@ -1162,18 +1180,7 @@ modify_cmd.parser.add_option('-f', '--format', action='store', def modify_func(lib, opts, args): args = decargs(args) - # Split the arguments into query parts, assignments (field=value), - # and deletions (field!). - mods = [] - dels = [] - query = [] - for arg in args: - if arg.endswith('!') and '=' not in arg and ':' not in arg: - dels.append(arg[:-1]) # Strip trailing !. - elif '=' in arg: - mods.append(arg) - else: - query.append(arg) + (query, mods, dels) = modify_parse_args(args) if not mods and not dels: raise ui.UserError('no modifications specified') diff --git a/test/test_ui.py b/test/test_ui.py index 34d7104b4..d25c94e1f 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -238,6 +238,30 @@ class ModifyTest(_common.TestCase): mediafile = MediaFile(item.path) self.assertIsNone(mediafile.initial_key) + def test_arg_parsing_colon_query(self): + (query, mods, dels) = commands.modify_parse_args(["title:oldTitle", + "title=newTitle"]) + self.assertEqual(query, ["title:oldTitle"]) + self.assertEqual(mods, ["title=newTitle"]) + + def test_arg_parsing_delete(self): + (query, mods, dels) = commands.modify_parse_args(["title:oldTitle", + "title!"]) + self.assertEqual(query, ["title:oldTitle"]) + self.assertEqual(dels, ["title"]) + + def test_arg_parsing_query_with_exclaimation(self): + (query, mods, dels) = commands.modify_parse_args(["title:oldTitle!", + "title=newTitle!"]) + self.assertEqual(query, ["title:oldTitle!"]) + self.assertEqual(mods, ["title=newTitle!"]) + + def test_arg_parsing_equals_in_value(self): + (query, mods, dels) = commands.modify_parse_args(["title:foo=bar", + "title=newTitle"]) + self.assertEqual(query, ["title:foo=bar"]) + self.assertEqual(mods, ["title=newTitle"]) + class MoveTest(_common.TestCase): def setUp(self):