Skip to content

Commit cfba52e

Browse files
committed
Improved lazy type resolvers
1 parent bdcd533 commit cfba52e

File tree

6 files changed

+67
-16
lines changed

6 files changed

+67
-16
lines changed

graphene/core/types/base.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import six
12
from functools import total_ordering
23

34

@@ -7,20 +8,36 @@ def internal_type(cls, schema):
78
return getattr(cls, 'T', None)
89

910

10-
class LazyType(BaseType):
11-
def __init__(self, type_str):
12-
self.type_str = type_str
11+
class MountType(BaseType):
12+
parent = None
1313

14+
def mount(self, cls):
15+
self.parent = cls
16+
17+
18+
class LazyType(MountType):
19+
def __init__(self, type):
20+
self.type = type
21+
22+
@property
1423
def is_self(self):
15-
return self.type_str == 'self'
24+
return self.type == 'self'
1625

1726
def internal_type(self, schema):
18-
type = schema.get_type(self.type_str)
27+
type = None
28+
if callable(self.type):
29+
type = self.type(self.parent)
30+
elif isinstance(self.type, six.string_types):
31+
if self.is_self:
32+
type = self.parent
33+
else:
34+
type = schema.get_type(self.type)
35+
assert type, 'Type in %s %r cannot be none' % (self.type, self.parent)
1936
return schema.T(type)
2037

2138

2239
@total_ordering
23-
class OrderedType(BaseType):
40+
class OrderedType(MountType):
2441
creation_counter = 0
2542

2643
def __init__(self, _creation_counter=None):
@@ -44,6 +61,12 @@ def __lt__(self, other):
4461
return self.creation_counter < other.creation_counter
4562
return NotImplemented
4663

64+
def __gt__(self, other):
65+
# This is needed because bisect does not take a comparison function.
66+
if type(self) == type(other):
67+
return self.creation_counter > other.creation_counter
68+
return NotImplemented
69+
4770
def __hash__(self):
4871
return hash((self.creation_counter))
4972

graphene/core/types/definitions.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import six
22
from graphql.core.type import (GraphQLList, GraphQLNonNull)
33

4-
from .base import MountedType, LazyType
4+
from .base import MountType, MountedType, LazyType
55

66

77
class OfType(MountedType):
@@ -14,6 +14,11 @@ def __init__(self, of_type, *args, **kwargs):
1414
def internal_type(self, schema):
1515
return self.T(schema.T(self.of_type))
1616

17+
def mount(self, cls):
18+
self.parent = cls
19+
if isinstance(self.of_type, MountType):
20+
self.of_type.mount(cls)
21+
1722

1823
class List(OfType):
1924
T = GraphQLList

graphene/core/types/field.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from graphql.core.type import GraphQLField, GraphQLInputObjectField
66

7-
from .base import LazyType, OrderedType
7+
from .base import MountType, LazyType, OrderedType
88
from .argument import ArgumentsGroup
99
from .definitions import NonNull
1010
from ...utils import to_camel_case, ProxySnakeDict
@@ -47,8 +47,9 @@ def contribute_to_class(self, cls, attname):
4747
self.name = to_camel_case(attname)
4848
self.attname = attname
4949
self.object_type = cls
50-
if isinstance(self.type, LazyType) and self.type.is_self():
51-
self.type = cls
50+
self.mount(cls)
51+
if isinstance(self.type, MountType):
52+
self.type.mount(cls)
5253
cls._meta.add_field(self)
5354

5455
@property
@@ -68,13 +69,16 @@ def default_getter(instance, args, info):
6869
return getattr(instance, self.attname, self.default)
6970
return default_getter
7071

72+
def get_type(self, schema):
73+
return self.type
74+
7175
def internal_type(self, schema):
7276
resolver = self.resolver
7377
description = self.description
7478
arguments = self.arguments
7579
if not description and resolver:
7680
description = resolver.__doc__
77-
type = schema.T(self.type)
81+
type = schema.T(self.get_type(schema))
7882
type_objecttype = schema.objecttype(type)
7983
if type_objecttype and type_objecttype._meta.is_mutation:
8084
assert len(arguments) == 0
@@ -120,6 +124,9 @@ def contribute_to_class(self, cls, attname):
120124
self.name = to_camel_case(attname)
121125
self.attname = attname
122126
self.object_type = cls
127+
self.mount(cls)
128+
if isinstance(self.type, MountType):
129+
self.type.mount(cls)
123130
cls._meta.add_field(self)
124131

125132
def internal_type(self, schema):

graphene/core/types/tests/test_field.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from ..field import Field, InputField
44
from ..scalars import String
55
from ..base import LazyType
6+
from ..definitions import List
67
from graphene.core.types import ObjectType, InputObjectType
78
from graphene.core.schema import Schema
89

@@ -59,7 +60,19 @@ def test_field_self():
5960
class MyObjectType(ObjectType):
6061
my_field = field
6162

62-
assert field.type == MyObjectType
63+
schema = Schema()
64+
65+
assert schema.T(field).type == schema.T(MyObjectType)
66+
67+
68+
def test_field_mounted():
69+
field = Field(List('MyObjectType'), name='my_customName')
70+
71+
class MyObjectType(ObjectType):
72+
my_field = field
73+
74+
assert field.parent == MyObjectType
75+
assert field.type.parent == MyObjectType
6376

6477

6578
def test_field_string_reference():

graphene/relay/fields.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def __init__(self, field_type, resolver=None, description='',
2323
def wrap_resolved(self, value, instance, args, info):
2424
return value
2525

26+
2627
def resolve(self, instance, args, info):
2728
from graphene.relay.types import PageInfo
2829
schema = info.schema.graphene_schema
@@ -50,9 +51,10 @@ def get_connection_type(self, node):
5051
def get_edge_type(self, node):
5152
return self.edge_type or node.get_edge_type()
5253

53-
def internal_type(self, schema):
54+
def get_type(self, schema):
5455
from graphene.relay.utils import is_node
55-
node = self.get_object_type(schema)
56+
type = schema.T(self.type)
57+
node = schema.objecttype(type)
5658
assert is_node(node), 'Only nodes have connections.'
5759
schema.register(node)
5860
connection_type = self.get_connection_type(node)

graphene/relay/types.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from graphene.core.fields import BooleanField, Field, ListField, StringField
22
from graphene.core.types import (InputObjectType, Interface, Mutation,
33
ObjectType)
4+
from graphene.core.types.base import LazyType
45
from graphene.core.types.argument import ArgumentsGroup
56
from graphene.core.types.definitions import NonNull
67
from graphene.relay.fields import GlobalIDField
@@ -24,7 +25,7 @@ class Edge(ObjectType):
2425
class Meta:
2526
type_name = 'DefaultEdge'
2627

27-
node = Field(lambda field: field.object_type.node_type,
28+
node = Field(LazyType(lambda object_type: object_type.node_type),
2829
description='The item at the end of the edge')
2930
cursor = StringField(
3031
required=True, description='A cursor for use in pagination')
@@ -44,7 +45,7 @@ class Meta:
4445

4546
page_info = Field(PageInfo, required=True,
4647
description='The Information to aid in pagination')
47-
edges = ListField(lambda field: field.object_type.edge_type,
48+
edges = ListField(LazyType(lambda object_type: object_type.edge_type),
4849
description='Information to aid in pagination.')
4950

5051
_connection_data = None

0 commit comments

Comments
 (0)