Skip to content

Commit a66f6f2

Browse files
committed
Added source argument to Fields. Fixed #101
1 parent cb81295 commit a66f6f2

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

graphene/core/classtypes/objecttype.py

+3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta, FieldsClassType)):
4646
class Meta:
4747
abstract = True
4848

49+
def __getattr__(self, name):
50+
return self._root and getattr(self._root, name)
51+
4952
def __init__(self, *args, **kwargs):
5053
signals.pre_init.send(self.__class__, args=args, kwargs=kwargs)
5154
self._root = kwargs.pop('_root', None)

graphene/core/types/field.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import six
55
from graphql.core.type import GraphQLField, GraphQLInputObjectField
66

7+
from ...utils import maybe_func
78
from ..classtypes.base import FieldsClassType
89
from ..classtypes.inputobjecttype import InputObjectType
910
from ..classtypes.mutation import Mutation
@@ -18,7 +19,8 @@ class Field(NamedType, OrderedType):
1819

1920
def __init__(
2021
self, type, description=None, args=None, name=None, resolver=None,
21-
required=False, default=None, deprecation_reason=None, *args_list, **kwargs):
22+
source=None, required=False, default=None, deprecation_reason=None,
23+
*args_list, **kwargs):
2224
_creation_counter = kwargs.pop('_creation_counter', None)
2325
if isinstance(name, (Argument, ArgumentType)):
2426
kwargs['name'] = name
@@ -33,7 +35,12 @@ def __init__(
3335
args = OrderedDict(args or {}, **kwargs)
3436
self.arguments = ArgumentsGroup(*args_list, **args)
3537
self.object_type = None
38+
self.attname = None
39+
self.default_name = None
3640
self.resolver_fn = resolver
41+
self.source = source
42+
assert not (self.source and self.resolver_fn), ('You cannot have a source'
43+
' and a resolver at the same time')
3744
self.default = default
3845

3946
def contribute_to_class(self, cls, attname):
@@ -68,7 +75,8 @@ def get_resolver_fn(self):
6875
return getattr(self.object_type, resolve_fn_name)
6976

7077
def default_getter(instance, args, info):
71-
return getattr(instance, self.attname, self.default)
78+
value = getattr(instance, self.source or self.attname, self.default)
79+
return maybe_func(value)
7280
return default_getter
7381

7482
def get_type(self, schema):
@@ -80,6 +88,8 @@ def decorate_resolver(self, resolver):
8088
return snake_case_args(resolver)
8189

8290
def internal_type(self, schema):
91+
if not self.object_type:
92+
raise Exception('The field is not mounted in any ClassType')
8393
resolver = self.resolver
8494
description = self.description
8595
arguments = self.arguments

graphene/core/types/tests/test_field.py

+38
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,41 @@ class Query(ObjectType):
180180
type = schema.T(field)
181181
assert isinstance(type, GraphQLField)
182182
assert type.deprecation_reason == deprecation_reason
183+
184+
185+
def test_field_resolve_object():
186+
class Root(object):
187+
att = True
188+
189+
@staticmethod
190+
def att_func():
191+
return True
192+
193+
field = Field(String(), description='My argument')
194+
field_func = Field(String(), description='My argument')
195+
196+
class Query(ObjectType):
197+
att = field
198+
att_func = field_func
199+
200+
assert field.resolver(Root, {}, None) is True
201+
assert field.resolver(Root, {}, None) is True
202+
203+
204+
def test_field_resolve_source_object():
205+
class Root(object):
206+
att_source = True
207+
208+
@staticmethod
209+
def att_func_source():
210+
return True
211+
212+
field = Field(String(), source='att_source', description='My argument')
213+
field_func = Field(String(), source='att_source', description='My argument')
214+
215+
class Query(ObjectType):
216+
att = field
217+
att_func = field_func
218+
219+
assert field.resolver(Root, {}, None) is True
220+
assert field.resolver(Root, {}, None) is True

0 commit comments

Comments
 (0)