diff --git a/picard/script.py b/picard/script.py index 1fca623c0..487d99b52 100644 --- a/picard/script.py +++ b/picard/script.py @@ -387,9 +387,33 @@ def func_in(parser, text, needle): return "" -def func_inmulti(parser, text, value, separator=MULTI_VALUED_JOINER): - """Splits ``text`` by ``separator``, and returns true if the resulting list contains ``value``.""" - return func_in(parser, text.split(separator) if separator else [text], value) +def func_inmulti(parser, haystack, needle, separator=MULTI_VALUED_JOINER): + """Searches for ``needle`` in ``haystack``, supporting a list variable for + ``haystack``. If a string is used instead, then a ``separator`` can be + used to split it. In both cases, it returns true if the resulting list + contains ``needle``.""" + + needle = needle.eval(parser) + if (isinstance(haystack, ScriptExpression) and + len(haystack) == 1 and + isinstance(haystack[0], ScriptVariable)): + haystack = haystack[0] + + if isinstance(haystack, ScriptVariable): + if haystack.name.startswith(u"_"): + name = u"~" + haystack.name[1:] + else: + name = haystack.name + values = parser.context.getall(name) + + return func_in(parser, values, needle) + + # I'm not sure if it is actually possible to continue in this code path, + # but just in case, it's better to have a fallback to correct behaviour + haystack = haystack.eval(parser) + return func_in(parser, + haystack.split(separator) if separator else [haystack], + needle) def func_rreplace(parser, text, old, new): @@ -819,7 +843,7 @@ register_script_function(func_lte, "lte") register_script_function(func_gt, "gt") register_script_function(func_gte, "gte") register_script_function(func_in, "in") -register_script_function(func_inmulti, "inmulti") +register_script_function(func_inmulti, "inmulti", eval_args=False) register_script_function(func_copy, "copy") register_script_function(func_copymerge, "copymerge") register_script_function(func_len, "len") diff --git a/test/test_script.py b/test/test_script.py index 35e45cffd..c7102c581 100644 --- a/test/test_script.py +++ b/test/test_script.py @@ -6,15 +6,19 @@ from picard.script import ScriptParser, ScriptError, register_script_function from picard.metadata import Metadata from picard.ui.options.renaming import _DEFAULT_FILE_NAMING_FORMAT + class ScriptParserTest(unittest.TestCase): def setUp(self): config.setting = { 'enabled_plugins': '', } + self.parser = ScriptParser() + def func_noargstest(parser): return "" + register_script_function(func_noargstest, "noargstest") def test_cmd_noop(self): @@ -370,3 +374,33 @@ class ScriptParserTest(unittest.TestCase): self.parser.eval("$unset(performer:*)", context) self.assertNotIn('performer:bar', context) self.assertNotIn('performer:foo', context) + + def test_cmd_inmulti(self): + context = Metadata() + self.parser.eval("$set(foo,First; Second; Third)", context) + self.assertEqual( + self.parser.eval("$in(%foo%,Second)", context), "1") + self.assertEqual( + self.parser.eval("$in(%foo%,irst; Second; Thi)", context), "1") + self.assertEqual( + self.parser.eval("$in(%foo%,First; Second; Third)", context), "1") + self.assertEqual( + self.parser.eval("$inmulti(%foo%,Second)", context), "") + self.assertEqual( + self.parser.eval("$inmulti(%foo%,irst; Second; Thi)", context), "") + self.assertEqual( + self.parser.eval("$inmulti(%foo%,First; Second; Third)", context), "1") + + self.parser.eval("$setmulti(foo,First; Second; Third)", context) + self.assertEqual( + self.parser.eval("$in(%foo%,Second)", context), "1") + self.assertEqual( + self.parser.eval("$in(%foo%,irst; Second; Thi)", context), "1") + self.assertEqual( + self.parser.eval("$in(%foo%,First; Second; Third)", context), "1") + self.assertEqual( + self.parser.eval("$inmulti(%foo%,Second)", context), "1") + self.assertEqual( + self.parser.eval("$inmulti(%foo%,irst; Second; Thi)", context), "") + self.assertEqual( + self.parser.eval("$inmulti(%foo%,First; Second; Third)", context), "")