diff --git a/picard/script/functions.py b/picard/script/functions.py index c6004810c..6787429f6 100644 --- a/picard/script/functions.py +++ b/picard/script/functions.py @@ -1296,3 +1296,29 @@ Result: C; B; A def func_reversemulti(parser, multi, separator=MULTI_VALUED_JOINER): multi_value = MultiValue(parser, multi, separator) return multi_value.separator.join(reversed(multi_value)) + + +@script_function(eval_args=False, documentation=N_( + """`$uniquemulti(name,case_sensitive="",separator="; ")` + +Returns a copy of the multi-value tag `name` with no duplicate elements. + By default, a case-insensitive comparison of the elements is performed. + +Example 1: + + $uniquemulti(a; A; B; b; cd; Cd; cD; CD; a; A; b) + +Result: A; b; CD + +Example 2: + + $uniquemulti(a; A; B; b; a; b; A; B, cd,True) + +Result: a; A; B; b; cd +""" +)) +def func_uniquemulti(parser, multi, case_sensitive="", separator=MULTI_VALUED_JOINER): + multi_value = MultiValue(parser, multi, separator) + if not case_sensitive: + multi_value._multi = list({v.lower(): v for v in multi_value}.values()) + return multi_value.separator.join(sorted(list(set(multi_value)))) diff --git a/test/test_script.py b/test/test_script.py index a719c1f0f..a1869453a 100644 --- a/test/test_script.py +++ b/test/test_script.py @@ -1494,3 +1494,27 @@ class ScriptParserTest(PicardTestCase): self.parser.eval("$reversemulti()") with self.assertRaisesRegex(ScriptError, areg): self.parser.eval("$reversemulti(B:AB; D:C; E:D; A:A; C:X,:,extra)") + + def test_cmd_uniquemulti(self): + context = Metadata() + context["foo"] = ['a', 'A', 'B', 'b', 'cd', 'Cd', 'cD', 'CD', 'a', 'A', 'b'] + context["bar"] = "a; A; B; b; cd; Cd; cD; CD; a; A; b" + # Tests with context + self.assertScriptResultEquals("$uniquemulti(%foo%)", "A; CD; b", context) + self.assertScriptResultEquals("$uniquemulti(%bar%)", "a; A; B; b; cd; Cd; cD; CD; a; A; b", context) + # Tests with static inputs + self.assertScriptResultEquals("$uniquemulti(a; A; B; b; cd; Cd; cD; CD; a; A; b)", "A; CD; b", context) + # Tests with separator override + self.assertScriptResultEquals("$uniquemulti(a: A: B: b: cd: Cd: cD: CD: a: A: b,,: )", "A: CD: b", context) + # Tests with case-sensitive comparison + self.assertScriptResultEquals("$uniquemulti(%foo%,1)", "A; B; CD; Cd; a; b; cD; cd", context) + # Tests with missing inputs + self.assertScriptResultEquals("$uniquemulti(,)", "", context) + self.assertScriptResultEquals("$uniquemulti(,,)", "", context) + self.assertScriptResultEquals("$uniquemulti(,:)", "", context) + # Tests with invalid number of arguments + areg = r"^\d+:\d+:\$uniquemulti: Wrong number of arguments for \$uniquemulti: Expected between 1 and 3, " + with self.assertRaisesRegex(ScriptError, areg): + self.parser.eval("$uniquemulti()") + with self.assertRaisesRegex(ScriptError, areg): + self.parser.eval("$uniquemulti(B:AB; D:C; E:D; A:A; C:X,1,:,extra)")