mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-23 10:03:54 +03:00
Added mutation and props utility
This commit is contained in:
parent
4c8f5367ba
commit
01190fb6ff
28
graphene/types/mutation.py
Normal file
28
graphene/types/mutation.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
from functools import partial
|
||||||
|
import six
|
||||||
|
|
||||||
|
from .objecttype import ObjectTypeMeta, ObjectType
|
||||||
|
from .field import Field
|
||||||
|
|
||||||
|
from ..utils.props import props
|
||||||
|
|
||||||
|
|
||||||
|
class MutationMeta(ObjectTypeMeta):
|
||||||
|
|
||||||
|
def construct_field(cls, field_attrs):
|
||||||
|
resolver = getattr(cls, 'mutate', None)
|
||||||
|
assert resolver, 'All mutations must define a mutate method in it'
|
||||||
|
return partial(Field, cls, args=field_attrs, resolver=resolver)
|
||||||
|
|
||||||
|
def construct(cls, bases, attrs):
|
||||||
|
super(MutationMeta, cls).construct(bases, attrs)
|
||||||
|
if not cls._meta.abstract:
|
||||||
|
Input = attrs.pop('Input', None)
|
||||||
|
field_attrs = props(Input) if Input else {}
|
||||||
|
cls.Field = cls.construct_field(field_attrs)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
|
||||||
|
class Mutation(six.with_metaclass(MutationMeta, ObjectType)):
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
234
graphene/types/tests/test_mutation.py
Normal file
234
graphene/types/tests/test_mutation.py
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from graphql import GraphQLObjectType, GraphQLField, GraphQLString, GraphQLInterfaceType
|
||||||
|
|
||||||
|
from ..schema import Schema
|
||||||
|
from ..objecttype import ObjectType
|
||||||
|
from ..mutation import Mutation
|
||||||
|
from ..interface import Interface
|
||||||
|
from ..scalars import String
|
||||||
|
from ..field import Field
|
||||||
|
from ..argument import Argument
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_mutation_no_args():
|
||||||
|
class MyMutation(Mutation):
|
||||||
|
'''Documentation'''
|
||||||
|
@classmethod
|
||||||
|
def mutate(cls, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert issubclass(MyMutation, ObjectType)
|
||||||
|
graphql_type = MyMutation._meta.graphql_type
|
||||||
|
assert isinstance(graphql_type, GraphQLObjectType)
|
||||||
|
assert graphql_type.name == "MyMutation"
|
||||||
|
assert graphql_type.description == "Documentation"
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_mutation_with_args():
|
||||||
|
class MyMutation(Mutation):
|
||||||
|
'''Documentation'''
|
||||||
|
class Input:
|
||||||
|
s = String()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mutate(cls, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
graphql_type = MyMutation._meta.graphql_type
|
||||||
|
field = MyMutation.Field()
|
||||||
|
assert isinstance(graphql_type, GraphQLObjectType)
|
||||||
|
assert graphql_type.name == "MyMutation"
|
||||||
|
assert graphql_type.description == "Documentation"
|
||||||
|
assert isinstance(field, Field)
|
||||||
|
assert field.type == MyMutation._meta.graphql_type
|
||||||
|
assert 's' in field.args
|
||||||
|
assert field.args['s'].type == GraphQLString
|
||||||
|
|
||||||
|
|
||||||
|
def test_generate_mutation_with_meta():
|
||||||
|
class MyMutation(Mutation):
|
||||||
|
class Meta:
|
||||||
|
name = 'MyOtherMutation'
|
||||||
|
description = 'Documentation'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def mutate(cls, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
graphql_type = MyMutation._meta.graphql_type
|
||||||
|
assert isinstance(graphql_type, GraphQLObjectType)
|
||||||
|
assert graphql_type.name == "MyOtherMutation"
|
||||||
|
assert graphql_type.description == "Documentation"
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_mutation_has_meta():
|
||||||
|
class MyMutation(Mutation):
|
||||||
|
@classmethod
|
||||||
|
def mutate(cls, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert MyMutation._meta
|
||||||
|
|
||||||
|
|
||||||
|
def test_mutation_raises_exception_if_no_mutate():
|
||||||
|
with pytest.raises(AssertionError) as excinfo:
|
||||||
|
class MyMutation(Mutation):
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert "All mutations must define a mutate method in it" == str(excinfo.value)
|
||||||
|
|
||||||
|
# def test_objecttype_inheritance():
|
||||||
|
# class MyInheritedObjectType(ObjectType):
|
||||||
|
# inherited = Field(GraphQLString)
|
||||||
|
|
||||||
|
# class MyObjectType(MyInheritedObjectType):
|
||||||
|
# field = Field(GraphQLString)
|
||||||
|
|
||||||
|
# graphql_type = MyObjectType._meta.graphql_type
|
||||||
|
# fields = graphql_type.get_fields()
|
||||||
|
# assert 'field' in fields
|
||||||
|
# assert 'inherited' in fields
|
||||||
|
# assert fields['field'] > fields['inherited']
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_as_container_only_args():
|
||||||
|
# container = Container("1", "2")
|
||||||
|
# assert container.field1 == "1"
|
||||||
|
# assert container.field2 == "2"
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_as_container_args_kwargs():
|
||||||
|
# container = Container("1", field2="2")
|
||||||
|
# assert container.field1 == "1"
|
||||||
|
# assert container.field2 == "2"
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_as_container_few_kwargs():
|
||||||
|
# container = Container(field2="2")
|
||||||
|
# assert container.field2 == "2"
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_as_container_all_kwargs():
|
||||||
|
# container = Container(field1="1", field2="2")
|
||||||
|
# assert container.field1 == "1"
|
||||||
|
# assert container.field2 == "2"
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_as_container_extra_args():
|
||||||
|
# with pytest.raises(IndexError) as excinfo:
|
||||||
|
# Container("1", "2", "3")
|
||||||
|
|
||||||
|
# assert "Number of args exceeds number of fields" == str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_as_container_invalid_kwargs():
|
||||||
|
# with pytest.raises(TypeError) as excinfo:
|
||||||
|
# Container(unexisting_field="3")
|
||||||
|
|
||||||
|
# assert "'unexisting_field' is an invalid keyword argument for this function" == str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_reuse_graphql_type():
|
||||||
|
# MyGraphQLType = GraphQLObjectType('MyGraphQLType', fields={
|
||||||
|
# 'field': GraphQLField(GraphQLString)
|
||||||
|
# })
|
||||||
|
|
||||||
|
# class GrapheneObjectType(ObjectType):
|
||||||
|
# class Meta:
|
||||||
|
# graphql_type = MyGraphQLType
|
||||||
|
|
||||||
|
# graphql_type = GrapheneObjectType._meta.graphql_type
|
||||||
|
# assert graphql_type == MyGraphQLType
|
||||||
|
# instance = GrapheneObjectType(field="A")
|
||||||
|
# assert instance.field == "A"
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_add_fields_in_reused_graphql_type():
|
||||||
|
# MyGraphQLType = GraphQLObjectType('MyGraphQLType', fields={
|
||||||
|
# 'field': GraphQLField(GraphQLString)
|
||||||
|
# })
|
||||||
|
|
||||||
|
# with pytest.raises(AssertionError) as excinfo:
|
||||||
|
# class GrapheneObjectType(ObjectType):
|
||||||
|
# field = Field(GraphQLString)
|
||||||
|
|
||||||
|
# class Meta:
|
||||||
|
# graphql_type = MyGraphQLType
|
||||||
|
|
||||||
|
# assert """Field "MyGraphQLType.field" can only be mounted in ObjectType or Interface, received GrapheneObjectType.""" == str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_graphql_interface():
|
||||||
|
# MyInterface = GraphQLInterfaceType('MyInterface', fields={
|
||||||
|
# 'field': GraphQLField(GraphQLString)
|
||||||
|
# })
|
||||||
|
|
||||||
|
# class GrapheneObjectType(ObjectType):
|
||||||
|
# class Meta:
|
||||||
|
# interfaces = [MyInterface]
|
||||||
|
|
||||||
|
# graphql_type = GrapheneObjectType._meta.graphql_type
|
||||||
|
# assert graphql_type.get_interfaces() == (MyInterface, )
|
||||||
|
# # assert graphql_type.is_type_of(MyInterface, None, None)
|
||||||
|
# fields = graphql_type.get_fields()
|
||||||
|
# assert 'field' in fields
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_graphene_interface():
|
||||||
|
# class GrapheneInterface(Interface):
|
||||||
|
# field = Field(GraphQLString)
|
||||||
|
|
||||||
|
# class GrapheneObjectType(ObjectType):
|
||||||
|
# class Meta:
|
||||||
|
# interfaces = [GrapheneInterface]
|
||||||
|
|
||||||
|
# graphql_type = GrapheneObjectType._meta.graphql_type
|
||||||
|
# assert graphql_type.get_interfaces() == (GrapheneInterface._meta.graphql_type, )
|
||||||
|
# assert graphql_type.is_type_of(GrapheneObjectType(), None, None)
|
||||||
|
# fields = graphql_type.get_fields()
|
||||||
|
# assert 'field' in fields
|
||||||
|
|
||||||
|
|
||||||
|
# def test_objecttype_graphene_interface_extended():
|
||||||
|
# class GrapheneInterface(Interface):
|
||||||
|
# field = Field(GraphQLString)
|
||||||
|
|
||||||
|
# class GrapheneObjectType(ObjectType):
|
||||||
|
# class Meta:
|
||||||
|
# interfaces = [GrapheneInterface]
|
||||||
|
|
||||||
|
# schema = Schema(query=GrapheneObjectType)
|
||||||
|
# assert str(schema) == """
|
||||||
|
# schema {
|
||||||
|
# query: GrapheneObjectType
|
||||||
|
# }
|
||||||
|
|
||||||
|
# interface GrapheneInterface {
|
||||||
|
# field: String
|
||||||
|
# }
|
||||||
|
|
||||||
|
# type GrapheneObjectType implements GrapheneInterface {
|
||||||
|
# field: String
|
||||||
|
# }
|
||||||
|
# """.lstrip()
|
||||||
|
# GrapheneInterface._meta.graphql_type.add_field(Field(String, name='dynamic'))
|
||||||
|
# # GrapheneObjectType._meta.graphql_type._field_map = None
|
||||||
|
# assert GrapheneInterface._meta.graphql_type.get_fields().keys() == ['field', 'dynamic']
|
||||||
|
# assert GrapheneObjectType._meta.graphql_type.get_fields().keys() == ['field', 'dynamic']
|
||||||
|
# schema.rebuild()
|
||||||
|
# assert str(schema) == """
|
||||||
|
# schema {
|
||||||
|
# query: GrapheneObjectType
|
||||||
|
# }
|
||||||
|
|
||||||
|
# interface GrapheneInterface {
|
||||||
|
# field: String
|
||||||
|
# dynamic: String
|
||||||
|
# }
|
||||||
|
|
||||||
|
# type GrapheneObjectType implements GrapheneInterface {
|
||||||
|
# field: String
|
||||||
|
# dynamic: String
|
||||||
|
# }
|
||||||
|
# """.lstrip()
|
15
graphene/utils/props.py
Normal file
15
graphene/utils/props.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class _OldClass:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class _NewClass(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
_all_vars = set(dir(_OldClass) + dir(_NewClass))
|
||||||
|
|
||||||
|
|
||||||
|
def props(x):
|
||||||
|
return {
|
||||||
|
key: value for key, value in vars(x).items() if key not in _all_vars
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user