1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
from typing import TYPE_CHECKING
from ..utils.deprecated import warn_deprecation
from ..utils.get_unbound_function import get_unbound_function
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 type checker
if TYPE_CHECKING:
from .argument import Argument # 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):
"""
Object Type Definition (mutation field)
Mutation is a convenience type that helps us build a Field which takes Arguments and returns a
mutation Output ObjectType.
.. code:: python
import graphene
class CreatePerson(graphene.Mutation):
class Arguments:
name = graphene.String()
ok = graphene.Boolean()
person = graphene.Field(Person)
def mutate(parent, info, name):
person = Person(name=name)
ok = True
return CreatePerson(person=person, ok=ok)
class Mutation(graphene.ObjectType):
create_person = CreatePerson.Field()
Meta class options (optional):
output (graphene.ObjectType): Or ``Output`` inner class with attributes on Mutation class.
Or attributes from Mutation class. Fields which can be returned from this mutation
field.
resolver (Callable resolver method): Or ``mutate`` method on Mutation class. Perform data
change and return output.
arguments (Dict[str, graphene.Argument]): Or ``Arguments`` inner class with attributes on
Mutation class. Arguments to use for the mutation Field.
name (str): Name of the GraphQL type (must be unique in schema). Defaults to class
name.
description (str): Description of the GraphQL type in the schema. Defaults to class
docstring.
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``).
"""
@classmethod
def __init_subclass_with_meta__(
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
), f'All interfaces of {cls.__name__} must be a subclass of Interface. Received "{interface}".'
fields.update(interface._meta.fields)
if not output:
# If output is defined, we don't need to get the fields
fields = {}
for base in reversed(cls.__mro__):
fields.update(yank_fields_from_attrs(base.__dict__, _as=Field))
output = cls
if not arguments:
input_class = getattr(cls, "Arguments", None)
if not input_class:
input_class = getattr(cls, "Input", None)
if input_class:
warn_deprecation(
f"Please use {cls.__name__}.Arguments instead of {cls.__name__}.Input."
" Input is now only used in ClientMutationID.\n"
"Read more:"
" https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#mutation-input"
)
arguments = props(input_class) if input_class else {}
if not resolver:
mutate = getattr(cls, "mutate", None)
assert mutate, "All mutations must define a mutate method in it"
resolver = get_unbound_function(mutate)
if _meta.fields:
_meta.fields.update(fields)
else:
_meta.fields = fields
_meta.interfaces = interfaces
_meta.output = output
_meta.resolver = resolver
_meta.arguments = arguments
super(Mutation, cls).__init_subclass_with_meta__(_meta=_meta, **options)
@classmethod
def Field(
cls, name=None, description=None, deprecation_reason=None, required=False
):
"""Mount instance of mutation Field."""
return Field(
cls._meta.output,
args=cls._meta.arguments,
resolver=cls._meta.resolver,
name=name,
description=description or cls._meta.description,
deprecation_reason=deprecation_reason,
required=required,
)
|