Skip to content

Commit 5b3000f

Browse files
committed
Improved classtypes relay support
1 parent 8abcaff commit 5b3000f

File tree

4 files changed

+60
-51
lines changed

4 files changed

+60
-51
lines changed

graphene/core/classtypes/interface.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ def _resolve_type(cls, schema, instance, *args):
4040

4141
@classmethod
4242
def internal_type(cls, schema):
43-
if cls._meta.abstract:
44-
raise Exception("Abstract Interfaces don't have a specific type.")
45-
4643
if not cls._meta.interface:
4744
return super(Interface, cls).internal_type(schema)
4845

graphene/relay/fields.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,5 @@ class GlobalIDField(Field):
9090
def __init__(self, *args, **kwargs):
9191
super(GlobalIDField, self).__init__(NonNull(ID()), *args, **kwargs)
9292

93-
def contribute_to_class(self, cls, name):
94-
from graphene.relay.utils import is_node, is_node_type
95-
in_node = is_node(cls) or is_node_type(cls)
96-
assert in_node, 'GlobalIDField could only be inside a Node, but got %r' % cls
97-
super(GlobalIDField, self).contribute_to_class(cls, name)
98-
9993
def resolver(self, instance, args, info):
10094
return instance.to_global_id()

graphene/relay/types.py

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import inspect
2+
import six
23
import warnings
34
from collections import Iterable
45
from functools import wraps
56

67
from graphql_relay.connection.arrayconnection import connection_from_list
78
from graphql_relay.node.node import to_global_id
89

9-
from ..core.types import (Boolean, Field, InputObjectType, Interface, List,
10-
Mutation, ObjectType, String)
10+
from ..core.classtypes import InputObjectType, Interface, Mutation, ObjectType
11+
from ..core.classtypes.mutation import MutationMeta
12+
from ..core.classtypes.interface import InterfaceMeta
13+
from ..core.types import Boolean, Field, List, String
1114
from ..core.types.argument import ArgumentsGroup
1215
from ..core.types.definitions import NonNull
1316
from ..utils import memoize
@@ -83,33 +86,43 @@ def get_connection_data(self):
8386
return self._connection_data
8487

8588

86-
class BaseNode(object):
89+
class NodeMeta(InterfaceMeta):
90+
def construct_get_node(cls):
91+
get_node = getattr(cls, 'get_node', None)
92+
assert get_node, 'get_node classmethod not found in %s Node' % cls
93+
assert callable(get_node), 'get_node have to be callable'
94+
args = 3
95+
if isinstance(get_node, staticmethod):
96+
args -= 1
8797

88-
@classmethod
89-
def _prepare_class(cls):
90-
from graphene.relay.utils import is_node
91-
if is_node(cls):
92-
get_node = getattr(cls, 'get_node')
93-
assert get_node, 'get_node classmethod not found in %s Node' % cls
94-
assert callable(get_node), 'get_node have to be callable'
95-
args = 3
96-
if isinstance(get_node, staticmethod):
97-
args -= 1
98-
99-
get_node_num_args = len(inspect.getargspec(get_node).args)
100-
if get_node_num_args < args:
101-
warnings.warn("get_node will receive also the info arg"
102-
" in future versions of graphene".format(cls.__name__),
103-
FutureWarning)
104-
105-
@staticmethod
106-
@wraps(get_node)
107-
def wrapped_node(*node_args):
108-
if len(node_args) < args:
109-
node_args += (None, )
110-
return get_node(*node_args[:-1])
111-
112-
setattr(cls, 'get_node', wrapped_node)
98+
get_node_num_args = len(inspect.getargspec(get_node).args)
99+
if get_node_num_args < args:
100+
warnings.warn("get_node will receive also the info arg"
101+
" in future versions of graphene".format(cls.__name__),
102+
FutureWarning)
103+
104+
@staticmethod
105+
@wraps(get_node)
106+
def wrapped_node(*node_args):
107+
if len(node_args) < args:
108+
node_args += (None, )
109+
return get_node(*node_args[:-1])
110+
111+
setattr(cls, 'get_node', wrapped_node)
112+
113+
def construct(cls, *args, **kwargs):
114+
cls = super(NodeMeta, cls).construct(*args, **kwargs)
115+
if not cls._meta.abstract:
116+
cls.construct_get_node()
117+
return cls
118+
119+
120+
class Node(six.with_metaclass(NodeMeta, Interface)):
121+
'''An object with an ID'''
122+
id = GlobalIDField()
123+
124+
class Meta:
125+
abstract = True
113126

114127
def to_global_id(self):
115128
type_name = self._meta.type_name
@@ -127,27 +140,31 @@ def get_edge_type(cls):
127140
return cls.edge_type
128141

129142

130-
class Node(BaseNode, Interface):
131-
'''An object with an ID'''
132-
id = GlobalIDField()
133-
134-
135143
class MutationInputType(InputObjectType):
136144
client_mutation_id = String(required=True)
137145

138146

139-
class ClientIDMutation(Mutation):
140-
client_mutation_id = String(required=True)
147+
class RelayMutationMeta(MutationMeta):
148+
def construct(cls, *args, **kwargs):
149+
cls = super(RelayMutationMeta, cls).construct(*args, **kwargs)
150+
if not cls._meta.abstract:
151+
assert hasattr(
152+
cls, 'mutate_and_get_payload'), 'You have to implement mutate_and_get_payload'
153+
return cls
141154

142-
@classmethod
143-
def _construct_arguments(cls, items):
144-
assert hasattr(
145-
cls, 'mutate_and_get_payload'), 'You have to implement mutate_and_get_payload'
155+
def construct_arguments(cls, items):
146156
new_input_type = type('{}Input'.format(
147157
cls._meta.type_name), (MutationInputType, ), items)
148158
cls.add_to_class('input_type', new_input_type)
149159
return ArgumentsGroup(input=NonNull(new_input_type))
150160

161+
162+
class ClientIDMutation(six.with_metaclass(RelayMutationMeta, Mutation)):
163+
client_mutation_id = String(required=True)
164+
165+
class Meta:
166+
abstract = True
167+
151168
@classmethod
152169
def mutate(cls, instance, args, info):
153170
input = args.get('input')

graphene/relay/utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from .types import BaseNode
1+
from .types import Node
22

33

44
def is_node(object_type):
55
return object_type and issubclass(
6-
object_type, BaseNode) and not is_node_type(object_type)
6+
object_type, Node) and not object_type._meta.abstract
77

88

99
def is_node_type(object_type):
10-
return BaseNode in object_type.__bases__
10+
return object_type and issubclass(
11+
object_type, Node) and object_type._meta.abstract

0 commit comments

Comments
 (0)