From c96bd680d7a161b65020fab3f12e799c5d3d03aa Mon Sep 17 00:00:00 2001
From: Ntale Shadik <shadikntale@gmail.com>
Date: Wed, 24 Jul 2019 20:44:22 +0300
Subject: [PATCH] Add interfaces meta argument on Mutations (#1023)

---
 graphene/types/mutation.py            | 23 +++++++++++++++++++----
 graphene/types/objecttype.py          |  3 ++-
 graphene/types/tests/test_mutation.py |  7 +++++++
 3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/graphene/types/mutation.py b/graphene/types/mutation.py
index 504d8470..c96162e4 100644
--- a/graphene/types/mutation.py
+++ b/graphene/types/mutation.py
@@ -6,18 +6,20 @@ from ..utils.props import props
 from .field import Field
 from .objecttype import ObjectType, ObjectTypeOptions
 from .utils import yank_fields_from_attrs
+from .interface import Interface
 
 # For static type checking with Mypy
 MYPY = False
 if MYPY:
     from .argument import Argument  # NOQA
-    from typing import Dict, Type, Callable  # NOQA
+    from typing import Dict, Type, Callable, Iterable  # NOQA
 
 
 class MutationOptions(ObjectTypeOptions):
     arguments = None  # type: Dict[str, Argument]
     output = None  # type: Type[ObjectType]
     resolver = None  # type: Callable
+    interfaces = ()  # type: Iterable[Type[Interface]]
 
 
 class Mutation(ObjectType):
@@ -58,8 +60,7 @@ class Mutation(ObjectType):
             name.
         description (str): Description of the GraphQL type in the schema. Defaults to class
             docstring.
-        interfaces (Iterable[graphene.Interface]): NOT IMPLEMENTED (use ``output`` to define a
-            payload implementing interfaces). GraphQL interfaces to extend with the payload
+        interfaces (Iterable[graphene.Interface]): GraphQL interfaces to extend with the payload
             object. All fields from interface will be included in this object's schema.
         fields (Dict[str, graphene.Field]): Dictionary of field name to Field. Not recommended to
             use (prefer class attributes or ``Meta.output``).
@@ -67,13 +68,26 @@ class Mutation(ObjectType):
 
     @classmethod
     def __init_subclass_with_meta__(
-        cls, resolver=None, output=None, arguments=None, _meta=None, **options
+        cls,
+        interfaces=(),
+        resolver=None,
+        output=None,
+        arguments=None,
+        _meta=None,
+        **options
     ):
         if not _meta:
             _meta = MutationOptions(cls)
 
         output = output or getattr(cls, "Output", None)
         fields = {}
+
+        for interface in interfaces:
+            assert issubclass(interface, Interface), (
+                'All interfaces of {} must be a subclass of Interface. Received "{}".'
+            ).format(cls.__name__, interface)
+            fields.update(interface._meta.fields)
+
         if not output:
             # If output is defined, we don't need to get the fields
             fields = OrderedDict()
@@ -110,6 +124,7 @@ class Mutation(ObjectType):
         else:
             _meta.fields = fields
 
+        _meta.interfaces = interfaces
         _meta.output = output
         _meta.resolver = resolver
         _meta.arguments = arguments
diff --git a/graphene/types/objecttype.py b/graphene/types/objecttype.py
index edd687c5..88c9f5bc 100644
--- a/graphene/types/objecttype.py
+++ b/graphene/types/objecttype.py
@@ -121,7 +121,8 @@ class ObjectType(BaseType):
         else:
             _meta.fields = fields
 
-        _meta.interfaces = interfaces
+        if not _meta.interfaces:
+            _meta.interfaces = interfaces
         _meta.possible_types = possible_types
         _meta.default_resolver = default_resolver
 
diff --git a/graphene/types/tests/test_mutation.py b/graphene/types/tests/test_mutation.py
index 8558dc7a..69d9b4cc 100644
--- a/graphene/types/tests/test_mutation.py
+++ b/graphene/types/tests/test_mutation.py
@@ -7,6 +7,11 @@ from ..objecttype import ObjectType
 from ..scalars import String
 from ..schema import Schema
 from ..structures import NonNull
+from ..interface import Interface
+
+
+class MyType(Interface):
+    pass
 
 
 def test_generate_mutation_no_args():
@@ -28,12 +33,14 @@ def test_generate_mutation_with_meta():
         class Meta:
             name = "MyOtherMutation"
             description = "Documentation"
+            interfaces = (MyType,)
 
         def mutate(self, info, **args):
             return args
 
     assert MyMutation._meta.name == "MyOtherMutation"
     assert MyMutation._meta.description == "Documentation"
+    assert MyMutation._meta.interfaces == (MyType,)
     resolved = MyMutation.Field().resolver(None, None, name="Peter")
     assert resolved == {"name": "Peter"}