mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-10-26 05:31:05 +03:00 
			
		
		
		
	Moved Interface to ObjectType. Improved integration with latest GraphQL-core
This commit is contained in:
		
							parent
							
								
									7a29502790
								
							
						
					
					
						commit
						9a9d7f8873
					
				|  | @ -2,7 +2,7 @@ import inspect | |||
| from collections import OrderedDict | ||||
| from itertools import chain | ||||
| 
 | ||||
| from graphql import GraphQLArgument | ||||
| from graphql.type.definition import GraphQLArgument, GraphQLArgumentDefinition | ||||
| from graphql.utils.assert_valid_name import assert_valid_name | ||||
| 
 | ||||
| from ..utils.orderedtype import OrderedType | ||||
|  | @ -40,11 +40,15 @@ class Argument(GraphQLArgument, OrderedType): | |||
| 
 | ||||
|     @classmethod | ||||
|     def copy_from(cls, argument): | ||||
|         if isinstance (argument, (GraphQLArgumentDefinition, Argument)): | ||||
|             name = argument.name | ||||
|         else: | ||||
|             name = None | ||||
|         return cls( | ||||
|             type=argument.type, | ||||
|             default_value=argument.default_value, | ||||
|             description=argument.description, | ||||
|             name=argument.name, | ||||
|             name=name, | ||||
|             _creation_counter=argument.creation_counter if isinstance(argument, Argument) else None, | ||||
|         ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from collections import OrderedDict | ||||
| import inspect | ||||
| 
 | ||||
| from graphql.type import GraphQLField, GraphQLInputObjectField | ||||
| from graphql.type import GraphQLField, GraphQLInputObjectField, GraphQLFieldDefinition | ||||
| from graphql.utils.assert_valid_name import assert_valid_name | ||||
| 
 | ||||
| from ..utils.orderedtype import OrderedType | ||||
|  | @ -126,18 +127,23 @@ class Field(AbstractField, GraphQLField, OrderedType): | |||
|             _creation_counter = field.creation_counter if _creation_counter is False else None | ||||
|             attname = attname or field.attname | ||||
|             parent = parent or field.parent | ||||
|             args = to_arguments(args, field.args) | ||||
|         else: | ||||
|             # If is a GraphQLField | ||||
|             type = type or field.type | ||||
|             resolver = resolver or field.resolver | ||||
|             name = field.name | ||||
|             field_args = field.args | ||||
|             if isinstance(field, GraphQLFieldDefinition): | ||||
|                 name = name or field.name | ||||
|                 field_args = OrderedDict((a.name, a) for a in field_args) | ||||
|             args = to_arguments(args, field_args) | ||||
|             _creation_counter = None | ||||
|             attname = attname or name | ||||
|             parent = parent | ||||
| 
 | ||||
|         new_field = cls( | ||||
|             type=type, | ||||
|             args=to_arguments(args, field.args), | ||||
|             args=args, | ||||
|             resolver=resolver, | ||||
|             source=source, | ||||
|             deprecation_reason=field.deprecation_reason, | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ from ..utils.get_fields import get_fields | |||
| from ..utils.is_base_type import is_base_type | ||||
| from .definitions import GrapheneGraphQLType | ||||
| from .field import InputField | ||||
| from .interface import attrs_without_fields | ||||
| from .objecttype import attrs_without_fields | ||||
| from .options import Options | ||||
| from .unmountedtype import UnmountedType | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,81 +1 @@ | |||
| import six | ||||
| 
 | ||||
| from graphql import GraphQLInterfaceType | ||||
| 
 | ||||
| from ..utils.copy_fields import copy_fields | ||||
| from ..utils.get_fields import get_fields | ||||
| from ..utils.is_base_type import is_base_type | ||||
| from .definitions import GrapheneGraphQLType | ||||
| from .field import Field | ||||
| from .options import Options | ||||
| 
 | ||||
| 
 | ||||
| class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType): | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| class InterfaceTypeMeta(type): | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def _get_interface_options(meta): | ||||
|         return Options( | ||||
|             meta, | ||||
|             name=None, | ||||
|             description=None, | ||||
|             graphql_type=None, | ||||
|             abstract=False | ||||
|         ) | ||||
| 
 | ||||
|     def __new__(cls, name, bases, attrs): | ||||
|         super_new = super(InterfaceTypeMeta, cls).__new__ | ||||
| 
 | ||||
|         # Also ensure initialization is only performed for subclasses of Model | ||||
|         # (excluding Model class itself). | ||||
|         if not is_base_type(bases, InterfaceTypeMeta): | ||||
|             return super_new(cls, name, bases, attrs) | ||||
| 
 | ||||
|         options = cls._get_interface_options(attrs.pop('Meta', None)) | ||||
| 
 | ||||
|         fields = get_fields(Interface, attrs, bases) | ||||
|         attrs = attrs_without_fields(attrs, fields) | ||||
|         cls = super_new(cls, name, bases, dict(attrs, _meta=options)) | ||||
| 
 | ||||
|         if not options.graphql_type: | ||||
|             fields = copy_fields(Field, fields, parent=cls) | ||||
|             options.graphql_type = GrapheneInterfaceType( | ||||
|                 graphene_type=cls, | ||||
|                 name=options.name or cls.__name__, | ||||
|                 resolve_type=cls.resolve_type, | ||||
|                 description=options.description or cls.__doc__, | ||||
|                 fields=fields, | ||||
|             ) | ||||
|         else: | ||||
|             assert not fields, "Can't mount Fields in an Interface with a defined graphql_type" | ||||
|             fields = copy_fields(options.graphql_type.get_fields(), parent=cls) | ||||
| 
 | ||||
|         for name, field in fields.items(): | ||||
|             setattr(cls, field.attname or name, field) | ||||
| 
 | ||||
|         return cls | ||||
| 
 | ||||
| 
 | ||||
| def attrs_without_fields(attrs, fields): | ||||
|     return {k: v for k, v in attrs.items() if k not in fields} | ||||
| 
 | ||||
| 
 | ||||
| class Interface(six.with_metaclass(InterfaceTypeMeta)): | ||||
|     resolve_type = None | ||||
| 
 | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         from .objecttype import ObjectType | ||||
|         if not isinstance(self, ObjectType): | ||||
|             raise Exception("An interface cannot be intitialized") | ||||
|         super(Interface, self).__init__(*args, **kwargs) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def implements(cls, object_type): | ||||
|         ''' | ||||
|         We use this function for customizing when a ObjectType have this class as Interface | ||||
|         For example, if we want to check that the ObjectType have some required things | ||||
|         in it like Node.get_node | ||||
|         ''' | ||||
| from .objecttype import Interface, GrapheneInterfaceType | ||||
|  |  | |||
|  | @ -1,18 +1,20 @@ | |||
| 
 | ||||
| import six | ||||
| 
 | ||||
| from graphql import GraphQLObjectType | ||||
| from graphql import GraphQLObjectType, GraphQLInterfaceType | ||||
| 
 | ||||
| from ..utils.copy_fields import copy_fields | ||||
| from ..utils.get_fields import get_fields | ||||
| from ..utils.is_base_type import is_base_type | ||||
| from .definitions import GrapheneGraphQLType | ||||
| from .field import Field | ||||
| from .interface import (GrapheneInterfaceType, Interface, InterfaceTypeMeta, | ||||
|                         attrs_without_fields) | ||||
| from .options import Options | ||||
| 
 | ||||
| 
 | ||||
| class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType): | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType): | ||||
| 
 | ||||
|     def __init__(self, *args, **kwargs): | ||||
|  | @ -42,10 +44,13 @@ def is_objecttype(bases): | |||
|     return False | ||||
| 
 | ||||
| 
 | ||||
| def attrs_without_fields(attrs, fields): | ||||
|     return {k: v for k, v in attrs.items() if k not in fields} | ||||
| 
 | ||||
| # We inherit from InterfaceTypeMeta instead of type for being able | ||||
| # to have ObjectTypes extending Interfaces using Python syntax, like: | ||||
| # class MyObjectType(ObjectType, MyInterface) | ||||
| class ObjectTypeMeta(InterfaceTypeMeta): | ||||
| class ObjectTypeMeta(type): | ||||
| 
 | ||||
|     def __new__(cls, name, bases, attrs): | ||||
|         super_new = type.__new__ | ||||
|  | @ -57,7 +62,7 @@ class ObjectTypeMeta(InterfaceTypeMeta): | |||
|             return super_new(cls, name, bases, attrs) | ||||
| 
 | ||||
|         if not is_objecttype(bases): | ||||
|             return super(ObjectTypeMeta, cls).__new__(cls, name, bases, attrs) | ||||
|             return cls._create_interface(cls, name, bases, attrs) | ||||
| 
 | ||||
|         options = Options( | ||||
|             attrs.pop('Meta', None), | ||||
|  | @ -99,6 +104,42 @@ class ObjectTypeMeta(InterfaceTypeMeta): | |||
|     def is_object_type(cls): | ||||
|         return issubclass(cls, ObjectType) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def _get_interface_options(meta): | ||||
|         return Options( | ||||
|             meta, | ||||
|             name=None, | ||||
|             description=None, | ||||
|             graphql_type=None, | ||||
|             abstract=False | ||||
|         ) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def _create_interface(cls, name, bases, attrs): | ||||
|         options = cls._get_interface_options(attrs.pop('Meta', None)) | ||||
| 
 | ||||
|         fields = get_fields(Interface, attrs, bases) | ||||
|         attrs = attrs_without_fields(attrs, fields) | ||||
|         cls = type.__new__(cls, name, bases, dict(attrs, _meta=options)) | ||||
| 
 | ||||
|         if not options.graphql_type: | ||||
|             fields = copy_fields(Field, fields, parent=cls) | ||||
|             options.graphql_type = GrapheneInterfaceType( | ||||
|                 graphene_type=cls, | ||||
|                 name=options.name or cls.__name__, | ||||
|                 resolve_type=cls.resolve_type, | ||||
|                 description=options.description or cls.__doc__, | ||||
|                 fields=fields, | ||||
|             ) | ||||
|         else: | ||||
|             assert not fields, "Can't mount Fields in an Interface with a defined graphql_type" | ||||
|             fields = copy_fields(options.graphql_type.get_fields(), parent=cls) | ||||
| 
 | ||||
|         for name, field in fields.items(): | ||||
|             setattr(cls, field.attname or name, field) | ||||
| 
 | ||||
|         return cls | ||||
| 
 | ||||
| 
 | ||||
| class ObjectType(six.with_metaclass(ObjectTypeMeta)): | ||||
| 
 | ||||
|  | @ -152,3 +193,21 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta)): | |||
|             return graphql_type.name == cls._meta.graphql_type.name | ||||
|         except: | ||||
|             return False | ||||
| 
 | ||||
| 
 | ||||
| class Interface(six.with_metaclass(ObjectTypeMeta)): | ||||
|     resolve_type = None | ||||
| 
 | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         from .objecttype import ObjectType | ||||
|         if not isinstance(self, ObjectType): | ||||
|             raise Exception("An interface cannot be intitialized") | ||||
|         super(Interface, self).__init__(*args, **kwargs) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def implements(cls, object_type): | ||||
|         ''' | ||||
|         We use this function for customizing when a ObjectType have this class as Interface | ||||
|         For example, if we want to check that the ObjectType have some required things | ||||
|         in it like Node.get_node | ||||
|         ''' | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| 
 | ||||
| from graphql import GraphQLInputObjectType, GraphQLString | ||||
| from graphql.type.definition import GraphQLInputFieldDefinition | ||||
| 
 | ||||
| from ..field import InputField | ||||
| from ..inputobjecttype import InputObjectType | ||||
|  | @ -43,7 +44,7 @@ def test_generate_objecttype_with_fields(): | |||
|     graphql_type = MyObjectType._meta.graphql_type | ||||
|     fields = graphql_type.get_fields() | ||||
|     assert 'field' in fields | ||||
|     assert isinstance(fields['field'], InputField) | ||||
|     assert isinstance(fields['field'], GraphQLInputFieldDefinition) | ||||
| 
 | ||||
| 
 | ||||
| def test_generate_objecttype_with_graphene_fields(): | ||||
|  | @ -53,4 +54,4 @@ def test_generate_objecttype_with_graphene_fields(): | |||
|     graphql_type = MyObjectType._meta.graphql_type | ||||
|     fields = graphql_type.get_fields() | ||||
|     assert 'field' in fields | ||||
|     assert isinstance(fields['field'], InputField) | ||||
|     assert isinstance(fields['field'], GraphQLInputFieldDefinition) | ||||
|  |  | |||
|  | @ -56,7 +56,7 @@ def test_interface_inheritance(): | |||
|     fields = graphql_type.get_fields() | ||||
|     assert 'field' in fields | ||||
|     assert 'inherited' in fields | ||||
|     assert fields['field'] > fields['inherited'] | ||||
|     assert MyInterface.field > MyInheritedInterface.inherited | ||||
| 
 | ||||
| 
 | ||||
| def test_interface_instance(): | ||||
|  |  | |||
|  | @ -74,11 +74,7 @@ def test_objecttype_inheritance(): | |||
| 
 | ||||
|     graphql_type = MyObjectType._meta.graphql_type | ||||
|     fields = graphql_type.get_fields() | ||||
|     assert 'field1' in fields | ||||
|     assert 'field2' in fields | ||||
|     assert 'inherited' in fields | ||||
|     assert fields['field1'] > fields['inherited'] | ||||
|     assert fields['field2'] > fields['field1'] | ||||
|     assert fields.keys() == ['inherited', 'field1', 'field2'] | ||||
| 
 | ||||
| 
 | ||||
| def test_objecttype_as_container_get_fields(): | ||||
|  | @ -195,11 +191,7 @@ def test_objecttype_graphene_interface(): | |||
|     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 | ||||
|     assert 'extended' in fields | ||||
|     assert 'name' in fields | ||||
|     assert fields['field'] > fields['extended'] > fields['name'] | ||||
|     fields = graphql_type.get_fields().keys() == ['name', 'extended', 'field'] | ||||
| 
 | ||||
| 
 | ||||
| def test_objecttype_graphene_inherit_interface(): | ||||
|  |  | |||
|  | @ -3,8 +3,9 @@ import datetime | |||
| import pytest | ||||
| 
 | ||||
| from graphene.utils.get_graphql_type import get_graphql_type | ||||
| from graphql import (GraphQLBoolean, GraphQLFloat, GraphQLInt, | ||||
|                      GraphQLScalarType, GraphQLString, graphql) | ||||
| from graphql import graphql | ||||
| from graphql.type import (GraphQLBoolean, GraphQLFloat, GraphQLInt, | ||||
|                           GraphQLScalarType, GraphQLString, GraphQLFieldDefinition) | ||||
| from graphql.language import ast | ||||
| 
 | ||||
| from ..field import Field | ||||
|  | @ -94,7 +95,7 @@ def test_scalar_in_objecttype(scalar_class, graphql_type): | |||
|     graphql_type = get_graphql_type(MyObjectType) | ||||
|     fields = graphql_type.get_fields() | ||||
|     assert list(fields.keys()) == ['before', 'field', 'after'] | ||||
|     assert isinstance(fields['field'], Field) | ||||
|     assert isinstance(fields['field'], GraphQLFieldDefinition) | ||||
| 
 | ||||
| 
 | ||||
| def test_custom_scalar_empty(): | ||||
|  |  | |||
|  | @ -11,6 +11,12 @@ class Character(Interface): | |||
|     friends = List(lambda: Character) | ||||
|     best_friend = Field(lambda: Character) | ||||
| 
 | ||||
|     def resolve_friends(self, *args): | ||||
|         return [Human(name='Peter')] | ||||
| 
 | ||||
|     def resolve_best_friend(self, *args): | ||||
|         return Human(name='Best') | ||||
| 
 | ||||
| 
 | ||||
| class Pet(ObjectType): | ||||
|     type = String() | ||||
|  | @ -26,12 +32,6 @@ class Human(ObjectType): | |||
|     def resolve_pet(self, *args): | ||||
|         return Pet(type='Dog') | ||||
| 
 | ||||
|     def resolve_friends(self, *args): | ||||
|         return [Human(name='Peter')] | ||||
| 
 | ||||
|     def resolve_best_friend(self, *args): | ||||
|         return Human(name='Best') | ||||
| 
 | ||||
| 
 | ||||
| class RootQuery(ObjectType): | ||||
|     character = Field(Character) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user