From a66f6f299076215a8b712502707669ed2eade25a Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Tue, 2 Feb 2016 19:00:36 -0800 Subject: [PATCH] Added source argument to Fields. Fixed #101 --- graphene/core/classtypes/objecttype.py | 3 ++ graphene/core/types/field.py | 14 +++++++-- graphene/core/types/tests/test_field.py | 38 +++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/graphene/core/classtypes/objecttype.py b/graphene/core/classtypes/objecttype.py index 442d78f5..d542f28c 100644 --- a/graphene/core/classtypes/objecttype.py +++ b/graphene/core/classtypes/objecttype.py @@ -46,6 +46,9 @@ class ObjectType(six.with_metaclass(ObjectTypeMeta, FieldsClassType)): class Meta: abstract = True + def __getattr__(self, name): + return self._root and getattr(self._root, name) + def __init__(self, *args, **kwargs): signals.pre_init.send(self.__class__, args=args, kwargs=kwargs) self._root = kwargs.pop('_root', None) diff --git a/graphene/core/types/field.py b/graphene/core/types/field.py index 3db7ed68..3109ffe0 100644 --- a/graphene/core/types/field.py +++ b/graphene/core/types/field.py @@ -4,6 +4,7 @@ from functools import wraps import six from graphql.core.type import GraphQLField, GraphQLInputObjectField +from ...utils import maybe_func from ..classtypes.base import FieldsClassType from ..classtypes.inputobjecttype import InputObjectType from ..classtypes.mutation import Mutation @@ -18,7 +19,8 @@ class Field(NamedType, OrderedType): def __init__( self, type, description=None, args=None, name=None, resolver=None, - required=False, default=None, deprecation_reason=None, *args_list, **kwargs): + source=None, required=False, default=None, deprecation_reason=None, + *args_list, **kwargs): _creation_counter = kwargs.pop('_creation_counter', None) if isinstance(name, (Argument, ArgumentType)): kwargs['name'] = name @@ -33,7 +35,12 @@ class Field(NamedType, OrderedType): args = OrderedDict(args or {}, **kwargs) self.arguments = ArgumentsGroup(*args_list, **args) self.object_type = None + self.attname = None + self.default_name = None self.resolver_fn = resolver + self.source = source + assert not (self.source and self.resolver_fn), ('You cannot have a source' + ' and a resolver at the same time') self.default = default def contribute_to_class(self, cls, attname): @@ -68,7 +75,8 @@ class Field(NamedType, OrderedType): return getattr(self.object_type, resolve_fn_name) def default_getter(instance, args, info): - return getattr(instance, self.attname, self.default) + value = getattr(instance, self.source or self.attname, self.default) + return maybe_func(value) return default_getter def get_type(self, schema): @@ -80,6 +88,8 @@ class Field(NamedType, OrderedType): return snake_case_args(resolver) def internal_type(self, schema): + if not self.object_type: + raise Exception('The field is not mounted in any ClassType') resolver = self.resolver description = self.description arguments = self.arguments diff --git a/graphene/core/types/tests/test_field.py b/graphene/core/types/tests/test_field.py index 34690223..444e91b5 100644 --- a/graphene/core/types/tests/test_field.py +++ b/graphene/core/types/tests/test_field.py @@ -180,3 +180,41 @@ def test_field_internal_type_deprecated(): type = schema.T(field) assert isinstance(type, GraphQLField) assert type.deprecation_reason == deprecation_reason + + +def test_field_resolve_object(): + class Root(object): + att = True + + @staticmethod + def att_func(): + return True + + field = Field(String(), description='My argument') + field_func = Field(String(), description='My argument') + + class Query(ObjectType): + att = field + att_func = field_func + + assert field.resolver(Root, {}, None) is True + assert field.resolver(Root, {}, None) is True + + +def test_field_resolve_source_object(): + class Root(object): + att_source = True + + @staticmethod + def att_func_source(): + return True + + field = Field(String(), source='att_source', description='My argument') + field_func = Field(String(), source='att_source', description='My argument') + + class Query(ObjectType): + att = field + att_func = field_func + + assert field.resolver(Root, {}, None) is True + assert field.resolver(Root, {}, None) is True