diff --git a/picard/script/functions.py b/picard/script/functions.py index 3e7a13120..01fddd7ab 100644 --- a/picard/script/functions.py +++ b/picard/script/functions.py @@ -1196,6 +1196,8 @@ Iterates over each element found in the multi-value tag `name` and updates the `_loop_value` and the count is stored in the tag `_loop_count`. This allows the element or count value to be accessed within the `code` script. +Empty elements are automatically removed. + Example: $map(First:A; Second:B,$upper(%_loop_count%=%_loop_value%)) @@ -1208,10 +1210,13 @@ def func_map(parser, multi, loop_code, separator=MULTI_VALUED_JOINER): for loop_count, value in enumerate(multi_value, 1): func_set(parser, '_loop_count', str(loop_count)) func_set(parser, '_loop_value', str(value)) + # Make changes in-place multi_value[loop_count - 1] = str(loop_code.eval(parser)) func_unset(parser, '_loop_count') func_unset(parser, '_loop_value') - return str(multi_value) + # Remove empty elements from existing multi-value variable + multi_value._multi = [x for x in multi_value if x] + return multi_value.separator.join(multi_value) @script_function(eval_args=False, documentation=N_( diff --git a/test/test_script.py b/test/test_script.py index 5179ed12d..65823a562 100644 --- a/test/test_script.py +++ b/test/test_script.py @@ -1204,19 +1204,24 @@ class ScriptParserTest(PicardTestCase): def test_cmd_map(self): context = Metadata() - context["foo"] = "First:A; Second:B; Third:C" - context["bar"] = ["First:A", "Second:B", "Third:C"] foo_output = "1=FIRST:A; SECOND:B; THIRD:C" loop_output = "1=FIRST:A; 2=SECOND:B; 3=THIRD:C" alternate_output = "1=FIRST:2=A; SECOND:3=B; THIRD:4=C" # Tests with context + context["foo"] = "First:A; Second:B; Third:C" self.assertScriptResultEquals("$map(%foo%,$upper(%_loop_count%=%_loop_value%))", foo_output, context) + context["bar"] = ["First:A", "Second:B", "Third:C"] self.assertScriptResultEquals("$map(%bar%,$upper(%_loop_count%=%_loop_value%))", loop_output, context) # Tests with static inputs self.assertScriptResultEquals("$map(First:A; Second:B; Third:C,$upper(%_loop_count%=%_loop_value%))", loop_output, context) + # Tests for removing empty elements + context["baz"] = ["First:A", "Second:B", "", "Third:C"] + self.assertScriptResultEquals("$map(%baz%,$upper(%_loop_count%=%_loop_value%))", loop_output, context) + context["baz"] = ["First:A", "Second:B", "", "Third:C"] + self.assertScriptResultEquals("$map(%baz%,$upper(%_loop_count%=%_loop_value%)) / %baz%", loop_output + " / " + loop_output, context) # Tests with missing inputs self.assertScriptResultEquals("$map(,$upper(%_loop_count%=%_loop_value%))", "", context) - self.assertScriptResultEquals("$map(First:A; Second:B; Third:C,)", "; ; ", context) + self.assertScriptResultEquals("$map(First:A; Second:B; Third:C,)", "", context) # Tests with separator override self.assertScriptResultEquals("$map(First:A; Second:B; Third:C,$upper(%_loop_count%=%_loop_value%),:)", alternate_output, context) # Tests with invalid number of arguments