mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 09:57:41 +03:00 
			
		
		
		
	Improved lazy type resolvers
This commit is contained in:
		
							parent
							
								
									bdcd533bf9
								
							
						
					
					
						commit
						cfba52e6f3
					
				| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
import six
 | 
			
		||||
from functools import total_ordering
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7,20 +8,36 @@ class BaseType(object):
 | 
			
		|||
        return getattr(cls, 'T', None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LazyType(BaseType):
 | 
			
		||||
    def __init__(self, type_str):
 | 
			
		||||
        self.type_str = type_str
 | 
			
		||||
class MountType(BaseType):
 | 
			
		||||
    parent = None
 | 
			
		||||
 | 
			
		||||
    def mount(self, cls):
 | 
			
		||||
        self.parent = cls
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LazyType(MountType):
 | 
			
		||||
    def __init__(self, type):
 | 
			
		||||
        self.type = type
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def is_self(self):
 | 
			
		||||
        return self.type_str == 'self'
 | 
			
		||||
        return self.type == 'self'
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        type = schema.get_type(self.type_str)
 | 
			
		||||
        type = None
 | 
			
		||||
        if callable(self.type):
 | 
			
		||||
            type = self.type(self.parent)
 | 
			
		||||
        elif isinstance(self.type, six.string_types):
 | 
			
		||||
            if self.is_self:
 | 
			
		||||
                type = self.parent
 | 
			
		||||
            else:
 | 
			
		||||
                type = schema.get_type(self.type)
 | 
			
		||||
        assert type, 'Type in %s %r cannot be none' % (self.type, self.parent)
 | 
			
		||||
        return schema.T(type)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@total_ordering
 | 
			
		||||
class OrderedType(BaseType):
 | 
			
		||||
class OrderedType(MountType):
 | 
			
		||||
    creation_counter = 0
 | 
			
		||||
 | 
			
		||||
    def __init__(self, _creation_counter=None):
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +61,12 @@ class OrderedType(BaseType):
 | 
			
		|||
            return self.creation_counter < other.creation_counter
 | 
			
		||||
        return NotImplemented
 | 
			
		||||
 | 
			
		||||
    def __gt__(self, other):
 | 
			
		||||
        # This is needed because bisect does not take a comparison function.
 | 
			
		||||
        if type(self) == type(other):
 | 
			
		||||
            return self.creation_counter > other.creation_counter
 | 
			
		||||
        return NotImplemented
 | 
			
		||||
 | 
			
		||||
    def __hash__(self):
 | 
			
		||||
        return hash((self.creation_counter))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import six
 | 
			
		||||
from graphql.core.type import (GraphQLList, GraphQLNonNull)
 | 
			
		||||
 | 
			
		||||
from .base import MountedType, LazyType
 | 
			
		||||
from .base import MountType, MountedType, LazyType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OfType(MountedType):
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,11 @@ class OfType(MountedType):
 | 
			
		|||
    def internal_type(self, schema):
 | 
			
		||||
        return self.T(schema.T(self.of_type))
 | 
			
		||||
 | 
			
		||||
    def mount(self, cls):
 | 
			
		||||
        self.parent = cls
 | 
			
		||||
        if isinstance(self.of_type, MountType):
 | 
			
		||||
            self.of_type.mount(cls)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class List(OfType):
 | 
			
		||||
    T = GraphQLList
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ from functools import wraps
 | 
			
		|||
 | 
			
		||||
from graphql.core.type import GraphQLField, GraphQLInputObjectField
 | 
			
		||||
 | 
			
		||||
from .base import LazyType, OrderedType
 | 
			
		||||
from .base import MountType, LazyType, OrderedType
 | 
			
		||||
from .argument import ArgumentsGroup
 | 
			
		||||
from .definitions import NonNull
 | 
			
		||||
from ...utils import to_camel_case, ProxySnakeDict
 | 
			
		||||
| 
						 | 
				
			
			@ -47,8 +47,9 @@ class Field(OrderedType):
 | 
			
		|||
            self.name = to_camel_case(attname)
 | 
			
		||||
        self.attname = attname
 | 
			
		||||
        self.object_type = cls
 | 
			
		||||
        if isinstance(self.type, LazyType) and self.type.is_self():
 | 
			
		||||
            self.type = cls
 | 
			
		||||
        self.mount(cls)
 | 
			
		||||
        if isinstance(self.type, MountType):
 | 
			
		||||
            self.type.mount(cls)
 | 
			
		||||
        cls._meta.add_field(self)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
| 
						 | 
				
			
			@ -68,13 +69,16 @@ class Field(OrderedType):
 | 
			
		|||
            return getattr(instance, self.attname, self.default)
 | 
			
		||||
        return default_getter
 | 
			
		||||
 | 
			
		||||
    def get_type(self, schema):
 | 
			
		||||
        return self.type
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
        resolver = self.resolver
 | 
			
		||||
        description = self.description
 | 
			
		||||
        arguments = self.arguments
 | 
			
		||||
        if not description and resolver:
 | 
			
		||||
            description = resolver.__doc__
 | 
			
		||||
        type = schema.T(self.type)
 | 
			
		||||
        type = schema.T(self.get_type(schema))
 | 
			
		||||
        type_objecttype = schema.objecttype(type)
 | 
			
		||||
        if type_objecttype and type_objecttype._meta.is_mutation:
 | 
			
		||||
            assert len(arguments) == 0
 | 
			
		||||
| 
						 | 
				
			
			@ -120,6 +124,9 @@ class InputField(OrderedType):
 | 
			
		|||
            self.name = to_camel_case(attname)
 | 
			
		||||
        self.attname = attname
 | 
			
		||||
        self.object_type = cls
 | 
			
		||||
        self.mount(cls)
 | 
			
		||||
        if isinstance(self.type, MountType):
 | 
			
		||||
            self.type.mount(cls)
 | 
			
		||||
        cls._meta.add_field(self)
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ from graphql.core.type import GraphQLField, GraphQLInputObjectField, GraphQLStri
 | 
			
		|||
from ..field import Field, InputField
 | 
			
		||||
from ..scalars import String
 | 
			
		||||
from ..base import LazyType
 | 
			
		||||
from ..definitions import List
 | 
			
		||||
from graphene.core.types import ObjectType, InputObjectType
 | 
			
		||||
from graphene.core.schema import Schema
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +60,19 @@ def test_field_self():
 | 
			
		|||
    class MyObjectType(ObjectType):
 | 
			
		||||
        my_field = field
 | 
			
		||||
 | 
			
		||||
    assert field.type == MyObjectType
 | 
			
		||||
    schema = Schema()
 | 
			
		||||
 | 
			
		||||
    assert schema.T(field).type == schema.T(MyObjectType)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_field_mounted():
 | 
			
		||||
    field = Field(List('MyObjectType'), name='my_customName')
 | 
			
		||||
 | 
			
		||||
    class MyObjectType(ObjectType):
 | 
			
		||||
        my_field = field
 | 
			
		||||
 | 
			
		||||
    assert field.parent == MyObjectType
 | 
			
		||||
    assert field.type.parent == MyObjectType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_field_string_reference():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ class ConnectionField(Field):
 | 
			
		|||
    def wrap_resolved(self, value, instance, args, info):
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def resolve(self, instance, args, info):
 | 
			
		||||
        from graphene.relay.types import PageInfo
 | 
			
		||||
        schema = info.schema.graphene_schema
 | 
			
		||||
| 
						 | 
				
			
			@ -50,9 +51,10 @@ class ConnectionField(Field):
 | 
			
		|||
    def get_edge_type(self, node):
 | 
			
		||||
        return self.edge_type or node.get_edge_type()
 | 
			
		||||
 | 
			
		||||
    def internal_type(self, schema):
 | 
			
		||||
    def get_type(self, schema):
 | 
			
		||||
        from graphene.relay.utils import is_node
 | 
			
		||||
        node = self.get_object_type(schema)
 | 
			
		||||
        type = schema.T(self.type)
 | 
			
		||||
        node = schema.objecttype(type)
 | 
			
		||||
        assert is_node(node), 'Only nodes have connections.'
 | 
			
		||||
        schema.register(node)
 | 
			
		||||
        connection_type = self.get_connection_type(node)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
from graphene.core.fields import BooleanField, Field, ListField, StringField
 | 
			
		||||
from graphene.core.types import (InputObjectType, Interface, Mutation,
 | 
			
		||||
                                 ObjectType)
 | 
			
		||||
from graphene.core.types.base import LazyType
 | 
			
		||||
from graphene.core.types.argument import ArgumentsGroup
 | 
			
		||||
from graphene.core.types.definitions import NonNull
 | 
			
		||||
from graphene.relay.fields import GlobalIDField
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +25,7 @@ class Edge(ObjectType):
 | 
			
		|||
    class Meta:
 | 
			
		||||
        type_name = 'DefaultEdge'
 | 
			
		||||
 | 
			
		||||
    node = Field(lambda field: field.object_type.node_type,
 | 
			
		||||
    node = Field(LazyType(lambda object_type: object_type.node_type),
 | 
			
		||||
                 description='The item at the end of the edge')
 | 
			
		||||
    cursor = StringField(
 | 
			
		||||
        required=True, description='A cursor for use in pagination')
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +45,7 @@ class Connection(ObjectType):
 | 
			
		|||
 | 
			
		||||
    page_info = Field(PageInfo, required=True,
 | 
			
		||||
                      description='The Information to aid in pagination')
 | 
			
		||||
    edges = ListField(lambda field: field.object_type.edge_type,
 | 
			
		||||
    edges = ListField(LazyType(lambda object_type: object_type.edge_type),
 | 
			
		||||
                      description='Information to aid in pagination.')
 | 
			
		||||
 | 
			
		||||
    _connection_data = None
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user