diff --git a/README.rst b/README.rst index b8afcf8d..ea5e2635 100644 --- a/README.rst +++ b/README.rst @@ -12,7 +12,9 @@ easily. `Django <http://github.com/graphql-python/swapi-graphene>`__ implementation -*What is supported in this Python version?* **Everything**: Interfaces, ObjectTypes, Scalars, Unions and Relay (Nodes, Connections and Mutations), in addition to queries, mutations and subscriptions. +*What is supported in this Python version?* **Everything**: Interfaces, +ObjectTypes, Scalars, Unions and Relay (Nodes, Connections), in addition +to queries, mutations and subscriptions. Installation ------------ diff --git a/examples/field_example.py b/examples/field_example.py new file mode 100644 index 00000000..be41969d --- /dev/null +++ b/examples/field_example.py @@ -0,0 +1,27 @@ +import graphene + + +class Patron(graphene.ObjectType): + id = graphene.ID() + name = graphene.String() + age = graphene.ID() + + +class Query(graphene.ObjectType): + + patron = graphene.Field(Patron) + + def resolve_patron(self, args, info): + return Patron(id=1, name='Demo') + +schema = graphene.Schema(query=Query) +query = ''' + query something{ + patron { + id + name + } +} +''' +result = schema.execute(query) +print(result.data['patron']) diff --git a/graphene/contrib/django/tests/test_types.py b/graphene/contrib/django/tests/test_types.py index 0e8eaa11..5d7f582e 100644 --- a/graphene/contrib/django/tests/test_types.py +++ b/graphene/contrib/django/tests/test_types.py @@ -1,6 +1,6 @@ -from pytest import raises from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType from mock import patch +from pytest import raises from graphene import Schema from graphene.contrib.django.types import DjangoInterface, DjangoNode @@ -36,7 +36,7 @@ def test_django_interface(): @patch('graphene.contrib.django.tests.models.Article.objects.get', return_value=Article(id=1)) def test_django_get_node(get): - human = Human.get_node(1) + human = Human.get_node(1, None) get.assert_called_with(id=1) assert human.id == 1 diff --git a/graphene/contrib/django/types.py b/graphene/contrib/django/types.py index 7b223294..f17893f0 100644 --- a/graphene/contrib/django/types.py +++ b/graphene/contrib/django/types.py @@ -49,6 +49,14 @@ class InstanceObjectType(BaseObjectType): )) super(InstanceObjectType, self).__init__(_root=_root) + @property + def instance(self): + return self._root + + @instance.setter + def instance(self, value): + self._root = value + def __getattr__(self, attr): return getattr(self._root, attr) @@ -67,7 +75,7 @@ class DjangoNode(BaseNode, DjangoInterface): id = GlobalIDField() @classmethod - def get_node(cls, id): + def get_node(cls, id, info=None): try: instance = cls._meta.model.objects.get(id=id) return cls(instance) diff --git a/graphene/relay/tests/test_types.py b/graphene/relay/tests/test_types.py index 1f3c56bf..d9f64c00 100644 --- a/graphene/relay/tests/test_types.py +++ b/graphene/relay/tests/test_types.py @@ -1,5 +1,5 @@ -from pytest import raises from graphql.core.type import GraphQLList +from pytest import raises import graphene from graphene import relay @@ -11,10 +11,32 @@ class OtherNode(relay.Node): name = graphene.String() @classmethod - def get_node(cls, id): + def get_node(cls, id, info): pass +def test_works_old_get_node(): + class Part(relay.Node): + x = graphene.String() + + @classmethod + def get_node(cls, id): + return id + + assert Part.get_node(1) == 1 + + +def test_works_old_static_get_node(): + class Part(relay.Node): + x = graphene.String() + + @staticmethod + def get_node(id): + return id + + assert Part.get_node(1) == 1 + + def test_field_no_contributed_raises_error(): with raises(Exception) as excinfo: class Part(relay.Node): diff --git a/graphene/relay/types.py b/graphene/relay/types.py index 08df4869..a803d2f3 100644 --- a/graphene/relay/types.py +++ b/graphene/relay/types.py @@ -1,3 +1,6 @@ +import inspect +import warnings +from functools import wraps from graphql_relay.node.node import to_global_id from ..core.types import (Boolean, Field, InputObjectType, Interface, List, @@ -73,8 +76,27 @@ class BaseNode(object): def _prepare_class(cls): from graphene.relay.utils import is_node if is_node(cls): - assert hasattr( - cls, 'get_node'), 'get_node classmethod not found in %s Node' % cls + get_node = getattr(cls, 'get_node') + assert get_node, 'get_node classmethod not found in %s Node' % cls + assert callable(get_node), 'get_node have to be callable' + args = 3 + if isinstance(get_node, staticmethod): + args -= 1 + + get_node_num_args = len(inspect.getargspec(get_node).args) + if get_node_num_args < args: + warnings.warn("get_node will receive also the info arg" + " in future versions of graphene".format(cls.__name__), + FutureWarning) + + @staticmethod + @wraps(get_node) + def wrapped_node(*node_args): + if len(node_args) < args: + node_args += (None, ) + return get_node(*node_args[:-1]) + + setattr(cls, 'get_node', wrapped_node) def to_global_id(self): type_name = self._meta.type_name diff --git a/setup.py b/setup.py index 6b0d1458..100e2321 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ class PyTest(TestCommand): setup( name='graphene', - version='0.4.0.1', + version='0.4.1.1', description='Graphene: Python DSL for GraphQL', long_description=open('README.rst').read(),