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 collections import OrderedDict | ||||||
| from itertools import chain | 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 graphql.utils.assert_valid_name import assert_valid_name | ||||||
| 
 | 
 | ||||||
| from ..utils.orderedtype import OrderedType | from ..utils.orderedtype import OrderedType | ||||||
|  | @ -40,11 +40,15 @@ class Argument(GraphQLArgument, OrderedType): | ||||||
| 
 | 
 | ||||||
|     @classmethod |     @classmethod | ||||||
|     def copy_from(cls, argument): |     def copy_from(cls, argument): | ||||||
|  |         if isinstance (argument, (GraphQLArgumentDefinition, Argument)): | ||||||
|  |             name = argument.name | ||||||
|  |         else: | ||||||
|  |             name = None | ||||||
|         return cls( |         return cls( | ||||||
|             type=argument.type, |             type=argument.type, | ||||||
|             default_value=argument.default_value, |             default_value=argument.default_value, | ||||||
|             description=argument.description, |             description=argument.description, | ||||||
|             name=argument.name, |             name=name, | ||||||
|             _creation_counter=argument.creation_counter if isinstance(argument, Argument) else None, |             _creation_counter=argument.creation_counter if isinstance(argument, Argument) else None, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
|  | from collections import OrderedDict | ||||||
| import inspect | 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 graphql.utils.assert_valid_name import assert_valid_name | ||||||
| 
 | 
 | ||||||
| from ..utils.orderedtype import OrderedType | 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 |             _creation_counter = field.creation_counter if _creation_counter is False else None | ||||||
|             attname = attname or field.attname |             attname = attname or field.attname | ||||||
|             parent = parent or field.parent |             parent = parent or field.parent | ||||||
|  |             args = to_arguments(args, field.args) | ||||||
|         else: |         else: | ||||||
|             # If is a GraphQLField |             # If is a GraphQLField | ||||||
|             type = type or field.type |             type = type or field.type | ||||||
|             resolver = resolver or field.resolver |             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 |             _creation_counter = None | ||||||
|             attname = attname or name |             attname = attname or name | ||||||
|             parent = parent |             parent = parent | ||||||
| 
 | 
 | ||||||
|         new_field = cls( |         new_field = cls( | ||||||
|             type=type, |             type=type, | ||||||
|             args=to_arguments(args, field.args), |             args=args, | ||||||
|             resolver=resolver, |             resolver=resolver, | ||||||
|             source=source, |             source=source, | ||||||
|             deprecation_reason=field.deprecation_reason, |             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 ..utils.is_base_type import is_base_type | ||||||
| from .definitions import GrapheneGraphQLType | from .definitions import GrapheneGraphQLType | ||||||
| from .field import InputField | from .field import InputField | ||||||
| from .interface import attrs_without_fields | from .objecttype import attrs_without_fields | ||||||
| from .options import Options | from .options import Options | ||||||
| from .unmountedtype import UnmountedType | from .unmountedtype import UnmountedType | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,81 +1 @@ | ||||||
| import six | from .objecttype import Interface, GrapheneInterfaceType | ||||||
| 
 |  | ||||||
| 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 |  | ||||||
|         ''' |  | ||||||
|  |  | ||||||
|  | @ -1,18 +1,20 @@ | ||||||
| 
 | 
 | ||||||
| import six | import six | ||||||
| 
 | 
 | ||||||
| from graphql import GraphQLObjectType | from graphql import GraphQLObjectType, GraphQLInterfaceType | ||||||
| 
 | 
 | ||||||
| from ..utils.copy_fields import copy_fields | from ..utils.copy_fields import copy_fields | ||||||
| from ..utils.get_fields import get_fields | from ..utils.get_fields import get_fields | ||||||
| from ..utils.is_base_type import is_base_type | from ..utils.is_base_type import is_base_type | ||||||
| from .definitions import GrapheneGraphQLType | from .definitions import GrapheneGraphQLType | ||||||
| from .field import Field | from .field import Field | ||||||
| from .interface import (GrapheneInterfaceType, Interface, InterfaceTypeMeta, |  | ||||||
|                         attrs_without_fields) |  | ||||||
| from .options import Options | from .options import Options | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType): | ||||||
|  |     pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType): | class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType): | ||||||
| 
 | 
 | ||||||
|     def __init__(self, *args, **kwargs): |     def __init__(self, *args, **kwargs): | ||||||
|  | @ -42,10 +44,13 @@ def is_objecttype(bases): | ||||||
|     return False |     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 | # We inherit from InterfaceTypeMeta instead of type for being able | ||||||
| # to have ObjectTypes extending Interfaces using Python syntax, like: | # to have ObjectTypes extending Interfaces using Python syntax, like: | ||||||
| # class MyObjectType(ObjectType, MyInterface) | # class MyObjectType(ObjectType, MyInterface) | ||||||
| class ObjectTypeMeta(InterfaceTypeMeta): | class ObjectTypeMeta(type): | ||||||
| 
 | 
 | ||||||
|     def __new__(cls, name, bases, attrs): |     def __new__(cls, name, bases, attrs): | ||||||
|         super_new = type.__new__ |         super_new = type.__new__ | ||||||
|  | @ -57,7 +62,7 @@ class ObjectTypeMeta(InterfaceTypeMeta): | ||||||
|             return super_new(cls, name, bases, attrs) |             return super_new(cls, name, bases, attrs) | ||||||
| 
 | 
 | ||||||
|         if not is_objecttype(bases): |         if not is_objecttype(bases): | ||||||
|             return super(ObjectTypeMeta, cls).__new__(cls, name, bases, attrs) |             return cls._create_interface(cls, name, bases, attrs) | ||||||
| 
 | 
 | ||||||
|         options = Options( |         options = Options( | ||||||
|             attrs.pop('Meta', None), |             attrs.pop('Meta', None), | ||||||
|  | @ -99,6 +104,42 @@ class ObjectTypeMeta(InterfaceTypeMeta): | ||||||
|     def is_object_type(cls): |     def is_object_type(cls): | ||||||
|         return issubclass(cls, ObjectType) |         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)): | 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 |             return graphql_type.name == cls._meta.graphql_type.name | ||||||
|         except: |         except: | ||||||
|             return False |             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 import GraphQLInputObjectType, GraphQLString | ||||||
|  | from graphql.type.definition import GraphQLInputFieldDefinition | ||||||
| 
 | 
 | ||||||
| from ..field import InputField | from ..field import InputField | ||||||
| from ..inputobjecttype import InputObjectType | from ..inputobjecttype import InputObjectType | ||||||
|  | @ -43,7 +44,7 @@ def test_generate_objecttype_with_fields(): | ||||||
|     graphql_type = MyObjectType._meta.graphql_type |     graphql_type = MyObjectType._meta.graphql_type | ||||||
|     fields = graphql_type.get_fields() |     fields = graphql_type.get_fields() | ||||||
|     assert 'field' in fields |     assert 'field' in fields | ||||||
|     assert isinstance(fields['field'], InputField) |     assert isinstance(fields['field'], GraphQLInputFieldDefinition) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_generate_objecttype_with_graphene_fields(): | def test_generate_objecttype_with_graphene_fields(): | ||||||
|  | @ -53,4 +54,4 @@ def test_generate_objecttype_with_graphene_fields(): | ||||||
|     graphql_type = MyObjectType._meta.graphql_type |     graphql_type = MyObjectType._meta.graphql_type | ||||||
|     fields = graphql_type.get_fields() |     fields = graphql_type.get_fields() | ||||||
|     assert 'field' in 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() |     fields = graphql_type.get_fields() | ||||||
|     assert 'field' in fields |     assert 'field' in fields | ||||||
|     assert 'inherited' in fields |     assert 'inherited' in fields | ||||||
|     assert fields['field'] > fields['inherited'] |     assert MyInterface.field > MyInheritedInterface.inherited | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_interface_instance(): | def test_interface_instance(): | ||||||
|  |  | ||||||
|  | @ -74,11 +74,7 @@ def test_objecttype_inheritance(): | ||||||
| 
 | 
 | ||||||
|     graphql_type = MyObjectType._meta.graphql_type |     graphql_type = MyObjectType._meta.graphql_type | ||||||
|     fields = graphql_type.get_fields() |     fields = graphql_type.get_fields() | ||||||
|     assert 'field1' in fields |     assert fields.keys() == ['inherited', 'field1', 'field2'] | ||||||
|     assert 'field2' in fields |  | ||||||
|     assert 'inherited' in fields |  | ||||||
|     assert fields['field1'] > fields['inherited'] |  | ||||||
|     assert fields['field2'] > fields['field1'] |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_objecttype_as_container_get_fields(): | def test_objecttype_as_container_get_fields(): | ||||||
|  | @ -195,11 +191,7 @@ def test_objecttype_graphene_interface(): | ||||||
|     graphql_type = GrapheneObjectType._meta.graphql_type |     graphql_type = GrapheneObjectType._meta.graphql_type | ||||||
|     assert graphql_type.get_interfaces() == (GrapheneInterface._meta.graphql_type, ) |     assert graphql_type.get_interfaces() == (GrapheneInterface._meta.graphql_type, ) | ||||||
|     assert graphql_type.is_type_of(GrapheneObjectType(), None, None) |     assert graphql_type.is_type_of(GrapheneObjectType(), None, None) | ||||||
|     fields = graphql_type.get_fields() |     fields = graphql_type.get_fields().keys() == ['name', 'extended', 'field'] | ||||||
|     assert 'field' in fields |  | ||||||
|     assert 'extended' in fields |  | ||||||
|     assert 'name' in fields |  | ||||||
|     assert fields['field'] > fields['extended'] > fields['name'] |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_objecttype_graphene_inherit_interface(): | def test_objecttype_graphene_inherit_interface(): | ||||||
|  |  | ||||||
|  | @ -3,8 +3,9 @@ import datetime | ||||||
| import pytest | import pytest | ||||||
| 
 | 
 | ||||||
| from graphene.utils.get_graphql_type import get_graphql_type | from graphene.utils.get_graphql_type import get_graphql_type | ||||||
| from graphql import (GraphQLBoolean, GraphQLFloat, GraphQLInt, | from graphql import graphql | ||||||
|                      GraphQLScalarType, GraphQLString, graphql) | from graphql.type import (GraphQLBoolean, GraphQLFloat, GraphQLInt, | ||||||
|  |                           GraphQLScalarType, GraphQLString, GraphQLFieldDefinition) | ||||||
| from graphql.language import ast | from graphql.language import ast | ||||||
| 
 | 
 | ||||||
| from ..field import Field | from ..field import Field | ||||||
|  | @ -94,7 +95,7 @@ def test_scalar_in_objecttype(scalar_class, graphql_type): | ||||||
|     graphql_type = get_graphql_type(MyObjectType) |     graphql_type = get_graphql_type(MyObjectType) | ||||||
|     fields = graphql_type.get_fields() |     fields = graphql_type.get_fields() | ||||||
|     assert list(fields.keys()) == ['before', 'field', 'after'] |     assert list(fields.keys()) == ['before', 'field', 'after'] | ||||||
|     assert isinstance(fields['field'], Field) |     assert isinstance(fields['field'], GraphQLFieldDefinition) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_custom_scalar_empty(): | def test_custom_scalar_empty(): | ||||||
|  |  | ||||||
|  | @ -11,6 +11,12 @@ class Character(Interface): | ||||||
|     friends = List(lambda: Character) |     friends = List(lambda: Character) | ||||||
|     best_friend = Field(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): | class Pet(ObjectType): | ||||||
|     type = String() |     type = String() | ||||||
|  | @ -26,12 +32,6 @@ class Human(ObjectType): | ||||||
|     def resolve_pet(self, *args): |     def resolve_pet(self, *args): | ||||||
|         return Pet(type='Dog') |         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): | class RootQuery(ObjectType): | ||||||
|     character = Field(Character) |     character = Field(Character) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user