Skip to content

Commit a336d9c

Browse files
Wid-L-Hackermlin
andauthored
[WDL 1.2] add values() (#832)
Co-authored-by: Mike Lin <mlin@contractor.chanzuckerberg.com>
1 parent 120059e commit a336d9c

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

WDL/StdLib.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def sep(sep: Value.String, iterable: Value.Array) -> Value.String:
151151
if self.wdl_version not in ["draft-2", "1.0", "1.1"]:
152152
# WDL 1.2+ functions
153153
self.contains = _Contains()
154+
self.values = _Values()
154155

155156
def _read(self, parse: Callable[[str], Value.Base]) -> Callable[[Value.File], Value.Base]:
156157
"generate read_* function implementation based on parse"
@@ -1074,6 +1075,31 @@ def _call_eager(self, expr: "Expr.Apply", arguments: List[Value.Base]) -> Value.
10741075
)
10751076

10761077

1078+
class _Values(EagerFunction):
1079+
# Array[Y] values(Map[P, Y])
1080+
# Returns an array of values from a Map
1081+
1082+
def infer_type(self, expr: "Expr.Apply") -> Type.Base:
1083+
if len(expr.arguments) != 1:
1084+
raise Error.WrongArity(expr, 1)
1085+
arg0ty = expr.arguments[0].type
1086+
if not isinstance(arg0ty, Type.Map) or (expr._check_quant and arg0ty.optional):
1087+
raise Error.StaticTypeMismatch(
1088+
expr.arguments[0], Type.Map((Type.Any(), Type.Any())), arg0ty
1089+
)
1090+
# For Map[P, Y], return Array[Y]
1091+
return Type.Array(arg0ty.item_type[1].copy())
1092+
1093+
def _call_eager(self, expr: "Expr.Apply", arguments: List[Value.Base]) -> Value.Base:
1094+
assert isinstance(arguments[0], Value.Map)
1095+
mapty = arguments[0].type
1096+
assert isinstance(mapty, Type.Map)
1097+
# Return the values (p[1]) from the map
1098+
return Value.Array(
1099+
mapty.item_type[1], [p[1].coerce(mapty.item_type[1]) for p in arguments[0].value], expr
1100+
)
1101+
1102+
10771103
class _AsPairs(EagerFunction):
10781104
def infer_type(self, expr: "Expr.Apply") -> Type.Base:
10791105
if len(expr.arguments) != 1:

tests/test_5stdlib.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,6 +1907,108 @@ def test_keys(self):
19071907
}
19081908
""")
19091909

1910+
def test_values(self):
1911+
"""Test the values() function from WDL 1.2"""
1912+
1913+
# Basic functionality with different value types
1914+
outputs = self._test_task(R"""
1915+
version 1.2
1916+
task test_values {
1917+
input {
1918+
Map[String, Int] m1 = {"a": 1, "b": 2, "c": 3}
1919+
Map[Int, String] m2 = {1: "one", 2: "two"}
1920+
Map[String, Pair[Int, Int]] m3 = {
1921+
"a": (1, 2),
1922+
"b": (3, 4)
1923+
}
1924+
}
1925+
command {}
1926+
output {
1927+
Array[Int] v1 = values(m1)
1928+
Array[String] v2 = values(m2)
1929+
Array[Pair[Int, Int]] v3 = values(m3)
1930+
Array[Boolean] v4 = values({})
1931+
}
1932+
}
1933+
""")
1934+
self.assertEqual(outputs["v1"], [1, 2, 3])
1935+
self.assertEqual(outputs["v2"], ["one", "two"])
1936+
self.assertEqual(outputs["v3"], [{"left": 1, "right": 2}, {"left": 3, "right": 4}])
1937+
self.assertEqual(outputs["v4"], [])
1938+
1939+
# Complex nested types
1940+
outputs = self._test_task(R"""
1941+
version 1.2
1942+
task test_values_complex {
1943+
input {
1944+
Map[String, Array[Int]] nested = {
1945+
"x": [1, 2],
1946+
"y": [3, 4, 5]
1947+
}
1948+
}
1949+
command {}
1950+
output {
1951+
Array[Array[Int]] vals = values(nested)
1952+
}
1953+
}
1954+
""")
1955+
self.assertEqual(outputs["vals"], [[1, 2], [3, 4, 5]])
1956+
1957+
# Error: wrong arity (too few arguments)
1958+
self._test_task(R"""
1959+
version 1.2
1960+
task bad {
1961+
command {}
1962+
output {
1963+
Array[Int] x = values()
1964+
}
1965+
}
1966+
""", expected_exception=WDL.Error.WrongArity)
1967+
1968+
# Error: wrong arity (too many arguments)
1969+
self._test_task(R"""
1970+
version 1.2
1971+
task bad {
1972+
command {}
1973+
output {
1974+
Array[Int] x = values({"a": 1}, {"b": 2})
1975+
}
1976+
}
1977+
""", expected_exception=WDL.Error.WrongArity)
1978+
1979+
# Error: not available in WDL 1.1
1980+
self._test_task(R"""
1981+
version 1.1
1982+
task bad {
1983+
command {}
1984+
output {
1985+
Array[Int] x = values({"a": 1})
1986+
}
1987+
}
1988+
""", expected_exception=WDL.Error.NoSuchFunction)
1989+
1990+
# Error: not available in WDL 1.0
1991+
self._test_task(R"""
1992+
version 1.0
1993+
task bad {
1994+
command {}
1995+
output {
1996+
Array[Int] x = values({"a": 1})
1997+
}
1998+
}
1999+
""", expected_exception=WDL.Error.NoSuchFunction)
2000+
2001+
# Error: first argument not a map
2002+
self._test_task(R"""
2003+
version 1.2
2004+
task bad {
2005+
command {}
2006+
output {
2007+
Array[Int] x = values([1, 2, 3])
2008+
}
2009+
}
2010+
""", expected_exception=WDL.Error.StaticTypeMismatch)
2011+
19102012
def test_map_pairs(self):
19112013
outputs = self._test_task(R"""
19122014
version development

0 commit comments

Comments
 (0)