Skip to content

Commit b663897

Browse files
committed
Implement 'R.<type>.CanBe` decorator.
1 parent a62c21b commit b663897

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

epoxy/metaclasses/object_type.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __new__(mcs, name, bases, attrs):
3636
return cls
3737

3838
@staticmethod
39-
def _register(object_type):
39+
def _register(object_type, cls):
4040
raise NotImplementedError('_register must be implemented in the sub-metaclass')
4141

4242
@staticmethod

epoxy/registry.py

+12
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(self):
4747
self._added_impl_types = set()
4848
self._interface_declared_fields = {}
4949
self._registered_types_can_be = defaultdict(set)
50+
self._pending_types_can_be = defaultdict(set)
5051
self.ObjectType = self._create_object_type_class()
5152
self.Implements = ClassTypeCreator(self, self._create_object_type_class)
5253
self.Union = ClassTypeCreator(self, self._create_union_type_class)
@@ -185,11 +186,22 @@ def _add_interface_declared_fields(self, interface, attrs):
185186
def _get_interface_declared_fields(self, interface):
186187
return self._interface_declared_fields.get(interface, {})
187188

189+
def _register_possible_type_for(self, type_name, klass):
190+
type = self._registered_types.get(type_name)
191+
if type:
192+
self._registered_types_can_be[type].add(klass)
193+
194+
else:
195+
self._pending_types_can_be[type_name].add(klass)
196+
188197
def _add_impl_to_interfaces(self):
189198
for type in self._registered_types.values():
190199
if not isinstance(type, GraphQLObjectType):
191200
continue
192201

202+
if type.name in self._pending_types_can_be:
203+
self._registered_types_can_be[type] |= self._pending_types_can_be.pop(type.name)
204+
193205
if type in self._added_impl_types:
194206
continue
195207

epoxy/thunk.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def __call__(self):
6969

7070
# noinspection PyPep8Naming
7171
def CanBe(self, klass):
72-
raise NotImplementedError('CanBe not yet implemented.')
72+
self.registry._register_possible_type_for(self.item, klass)
73+
return klass
7374

7475

7576
class ThunkList(object):

tests/test_can_be.py

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from graphql.core import graphql
2+
from epoxy import TypeRegistry
3+
4+
5+
def test_can_be():
6+
R = TypeRegistry()
7+
8+
@R.Cat.CanBe
9+
class MyCat(object):
10+
def __init__(self, name, meow):
11+
self.name = name
12+
self.meow = meow
13+
14+
class Pet(R.Interface):
15+
name = R.String
16+
17+
class Dog(R.Implements.Pet):
18+
bark = R.String
19+
20+
class Cat(R.Implements.Pet):
21+
meow = R.String
22+
23+
class Bird(R.Implements.Pet):
24+
tweet = R.String
25+
26+
class Query(R.ObjectType):
27+
pets = R.Pet.List
28+
29+
@R.Dog.CanBe
30+
class MyDog(object):
31+
def __init__(self, name, bark):
32+
self.name = name
33+
self.bark = bark
34+
35+
schema = R.Schema(Query)
36+
37+
@R.Bird.CanBe
38+
class MyBird(object):
39+
def __init__(self, name, tweet):
40+
self.name = name
41+
self.tweet = tweet
42+
43+
data = Query(pets=[
44+
MyDog(name='Clifford', bark='Really big bark, because it\'s a really big dog.'),
45+
MyCat(name='Garfield', meow='Lasagna'),
46+
MyBird(name='Tweetie', tweet='#yolo'),
47+
48+
Dog(name='OTClifford', bark='Really big bark, because it\'s a really big dog.'),
49+
Cat(name='OTGarfield', meow='Lasagna'),
50+
Bird(name='OTTweetie', tweet='#yolo'),
51+
])
52+
53+
result = graphql(schema, '''
54+
{
55+
pets {
56+
name
57+
__typename
58+
... on Dog {
59+
bark
60+
}
61+
62+
... on Cat {
63+
meow
64+
}
65+
66+
... on Bird {
67+
tweet
68+
}
69+
}
70+
}
71+
72+
''', data)
73+
assert not result.errors
74+
assert result.data == {
75+
'pets': [
76+
{'__typename': 'Dog', 'bark': "Really big bark, because it's a really big dog.", 'name': 'Clifford'},
77+
{'__typename': 'Cat', 'meow': 'Lasagna', 'name': 'Garfield'},
78+
{'__typename': 'Bird', 'tweet': '#yolo', 'name': 'Tweetie'},
79+
{'__typename': 'Dog', 'bark': "Really big bark, because it's a really big dog.", 'name': 'OTClifford'},
80+
{'__typename': 'Cat', 'meow': 'Lasagna', 'name': 'OTGarfield'},
81+
{'__typename': 'Bird', 'tweet': '#yolo', 'name': 'OTTweetie'},
82+
]
83+
}

0 commit comments

Comments
 (0)