mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-10-31 16:07:27 +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