Repository: tartiflette/tartiflette (python)

Issue:
Exception is raised when enum list on argument are coerced
* **Tartiflette version:** 0.10.0
* **Python version:** 3.7.1
* **Executed in docker:** No
* **Is a regression from a previous versions?** No

SDL example:
```graphql
enum MyEnum { V_1, V_2, V_3 }

type Query {
  listEnum(param: [MyEnum]): [MyEnum]
}
```

Query:
```graphql
query {
  listEnum(param: [V_1, V_2])
} == {
  "data": {
    "listEnum": null
  },
  "errors": [
    {
      "locations": [
        {
          "column": 29,
          "line": 1
        }
      ],
      "message": "unhashable type: \"list\"",
      "path": [
        "listEnum"
      ]
    }
  ]
}
```

Expected:
```json
{"data": {"listEnum": ["V_1", "V_2"]}}
```

Pull request:
Handle input coercion on enum list
Closes #233.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cbd2423..abcf7fe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 ## [Released]
 
 - [0.10.x]
+  - [0.10.1](./changelogs/0.10.1.md) - 2019-06-07
   - [0.10.0](./changelogs/0.10.0.md) - 2019-05-13
 - [0.9.x]
   - [0.9.0](./changelogs/0.9.0.md) - 2019-04-30
diff --git a/changelogs/0.10.1.md b/changelogs/0.10.1.md
new file mode 100644
index 0000000..f9752ed
--- /dev/null
+++ b/changelogs/0.10.1.md
@@ -0,0 +1,5 @@
+# [0.10.1] - 2019-06-07
+
+## Fixed
+
+[ISSUE-233](https://github.com/tartiflette/tartiflette/issues/233) - Handle input coercion on enum list
diff --git a/setup.py b/setup.py
index f340323..e946b0f 100644
--- a/setup.py
+++ b/setup.py
@@ -60,7 +60,7 @@ _TEST_REQUIRE = [
 
 _BENCHMARK_REQUIRE = ["pytest-benchmark==3.2.2"]
 
-_VERSION = "0.10.0"
+_VERSION = "0.10.1"
 
 _PACKAGES = find_packages(exclude=["tests*"])
 
diff --git a/tartiflette/types/enum.py b/tartiflette/types/enum.py
index 2089ef1..78a4b12 100644
--- a/tartiflette/types/enum.py
+++ b/tartiflette/types/enum.py
@@ -184,11 +184,20 @@ class GraphQLEnumType(GraphQLType):
         )
 
         # Manage the fact that, val can be inputed as None.
-        if not val:
+        if val is None:
             return rval
 
         # Call Value Directives
         # This is done POST coercion, so VAL exists in map
+        if isinstance(val, list):
+            return [
+                None
+                if raw_item is None
+                else await self._value_map[raw_item].directives[
+                    CoercerWay.INPUT
+                ](result_item, *args, **kwargs)
+                for raw_item, result_item in zip(val, rval)
+            ]
         return await self._value_map[val].directives[CoercerWay.INPUT](
             rval, *args, **kwargs
         )


Test patch:
diff --git a/tests/functional/regressions/test_issue_233.py b/tests/functional/regressions/test_issue_233.py
new file mode 100644
index 0000000..13441e9
--- /dev/null
+++ b/tests/functional/regressions/test_issue_233.py
@@ -0,0 +1,203 @@
+from enum import Enum
+
+import pytest
+
+from tartiflette import Engine, Resolver
+from tartiflette.directive import CommonDirective, Directive
+
+_SDL = """
+directive @actAsPyEnum(name: String!) on ENUM
+
+enum FirstEnum @actAsPyEnum(name: "FirstEnum") { V_1, V_2, V_3 }
+enum SecondEnum @actAsPyEnum(name: "SecondEnum") { V_1, V_2, V_3 }
+
+type Query {
+  anEnum(param: FirstEnum): FirstEnum
+  listEnum(param: [SecondEnum]): [SecondEnum]
+}
+"""
+
+
+class FirstEnum(Enum):
+    V_1 = "v1"
+    V_2 = "v2"
+    V_3 = "v3"
+
+
+class SecondEnum(Enum):
+    V_1 = 0
+    V_2 = 1
+    V_3 = 2
+
+
+_ENUM_MAP = {"FirstEnum": FirstEnum, "SecondEnum": SecondEnum}
+
+
+@Directive("actAsPyEnum", schema_name="test_issue_233")
+class ActAsPyEnumDirective(CommonDirective):
+    @staticmethod
+    async def on_post_input_coercion(
+        directive_args, next_directive, value, argument_definition, ctx, info
+    ):
+        value = await next_directive(value, argument_definition, ctx, info)
+        if value is None:
+            return value
+
+        try:
+            py_enum = _ENUM_MAP[directive_args["name"]]
+            if isinstance(value, list):
+                return [
+                    None if item is None else py_enum[item].value
+                    for item in value
+                ]
+            return py_enum[value].value
+        except Exception:
+            pass
+        return value
+
+    @staticmethod
+    async def on_pre_output_coercion(
+        directive_args, next_directive, value, field_definition, ctx, info
+    ):
+        value = await next_directive(value, field_definition, ctx, info)
+        if value is None:
+            return value
+
+        try:
+            py_enum = _ENUM_MAP[directive_args["name"]]
+            if isinstance(value, list):
+                return [
+                    None if item is None else py_enum(item).name
+                    for item in value
+                ]
+            return py_enum(value).name
+        except Exception:
+            pass
+        return value
+
+
+@Resolver("Query.anEnum", schema_name="test_issue_233")
+@Resolver("Query.listEnum", schema_name="test_issue_233")
+async def resolve_query_fields(parent_result, args, ctx, info):
+    return args.get("param")
+
+
+_ENGINE = Engine(_SDL, schema_name="test_issue_233")
+
+
+@pytest.mark.asyncio
+@pytest.mark.parametrize(
+    "query,variables,expected",
+    [
+        # anEnum
+        ("""{ anEnum }""", None, {"data": {"anEnum": None}}),
+        ("""{ anEnum(param: null) }""", None, {"data": {"anEnum": None}}),
+        ("""{ anEnum(param: V_1) }""", None, {"data": {"anEnum": "V_1"}}),
+        ("""{ anEnum(param: V_2) }""", None, {"data": {"anEnum": "V_2"}}),
+        (
+            """query ($param: FirstEnum) { anEnum(param: $param) }""",
+            None,
+            {"data": {"anEnum": None}},
+        ),
+        (
+            """query ($param: FirstEnum) { anEnum(param: $param) }""",
+            {"param": None},
+            {"data": {"anEnum": None}},
+        ),
+        (
+            """query ($param: FirstEnum) { anEnum(param: $param) }""",
+            {"param": "V_1"},
+            {"data": {"anEnum": "V_1"}},
+        ),
+        (
+            """query ($param: FirstEnum) { anEnum(param: $param) }""",
+            {"param": "V_2"},
+            {"data": {"anEnum": "V_2"}},
+        ),
+        # listEnum
+        ("""{ listEnum }""", None, {"data": {"listEnum": None}}),
+        ("""{ listEnum(param: null) }""", None, {"data": {"listEnum": None}}),
+        (
+            """{ listEnum(param: [null]) }""",
+            None,
+            {"data": {"listEnum": [None]}},
+        ),
+        (
+            """{ listEnum(param: V_1) }""",
+            None,
+            {"data": {"listEnum": ["V_1"]}},
+        ),
+        (
+            """{ listEnum(param: [V_1]) }""",
+            None,
+            {"data": {"listEnum": ["V_1"]}},
+        ),
+        (
+            """{ listEnum(param: V_2) }""",
+            None,
+            {"data": {"listEnum": ["V_2"]}},
+        ),
+        (
+            """{ listEnum(param: [V_2]) }""",
+            None,
+            {"data": {"listEnum": ["V_2"]}},
+        ),
+        (
+            """{ listEnum(param: [V_1, V_2]) }""",
+            None,
+            {"data": {"listEnum": ["V_1", "V_2"]}},
+        ),
+        (
+            """{ listEnum(param: [V_1, V_2, null]) }""",
+            None,
+            {"data": {"listEnum": ["V_1", "V_2", None]}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            None,
+            {"data": {"listEnum": None}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": None},
+            {"data": {"listEnum": None}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": [None]},
+            {"data": {"listEnum": [None]}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": "V_1"},
+            {"data": {"listEnum": ["V_1"]}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": ["V_1"]},
+            {"data": {"listEnum": ["V_1"]}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": "V_2"},
+            {"data": {"listEnum": ["V_2"]}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": ["V_2"]},
+            {"data": {"listEnum": ["V_2"]}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": ["V_1", "V_2"]},
+            {"data": {"listEnum": ["V_1", "V_2"]}},
+        ),
+        (
+            """query ($param: SecondEnum) { listEnum(param: $param) }""",
+            {"param": ["V_1", "V_2", None]},
+            {"data": {"listEnum": ["V_1", "V_2", None]}},
+        ),
+    ],
+)
+async def test_issue_233(query, variables, expected):
+    assert await _ENGINE.execute(query, variables=variables) == expected