From 1c24e1b95435c899fb0917c476634e4def17a158 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 12 Aug 2016 18:06:01 -0700 Subject: [PATCH] Added Union type --- graphene/generators/definitions.py | 6 ++- graphene/new_types/interface.py | 5 ++- graphene/new_types/objecttype.py | 3 ++ graphene/new_types/scalars.py | 3 ++ graphene/new_types/tests/test_definition.py | 35 +++++++++++------ graphene/new_types/tests/test_union.py | 42 +++++++++++++++++++++ graphene/new_types/union.py | 37 ++++++++++++++++++ 7 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 graphene/new_types/tests/test_union.py create mode 100644 graphene/new_types/union.py diff --git a/graphene/generators/definitions.py b/graphene/generators/definitions.py index 42f08f52..1fdb2d47 100644 --- a/graphene/generators/definitions.py +++ b/graphene/generators/definitions.py @@ -1,6 +1,6 @@ from graphql import (GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLObjectType, - GraphQLScalarType) + GraphQLScalarType, GraphQLUnionType) class GrapheneGraphQLType(object): @@ -18,6 +18,10 @@ class GrapheneInterfaceType(GrapheneGraphQLType, GraphQLInterfaceType): pass +class GrapheneUnionType(GrapheneGraphQLType, GraphQLUnionType): + pass + + class GrapheneObjectType(GrapheneGraphQLType, GraphQLObjectType): pass diff --git a/graphene/new_types/interface.py b/graphene/new_types/interface.py index 8058c82d..e4975e14 100644 --- a/graphene/new_types/interface.py +++ b/graphene/new_types/interface.py @@ -28,12 +28,15 @@ class InterfaceMeta(AbstractTypeMeta): return type.__new__(cls, name, bases, dict(attrs, _meta=options)) + def __str__(cls): + return cls._meta.name + class Interface(six.with_metaclass(InterfaceMeta)): resolve_type = None def __init__(self, *args, **kwargs): - raise Exception("An interface cannot be intitialized") + raise Exception("An Interface cannot be intitialized") # @classmethod # def implements(cls, objecttype): diff --git a/graphene/new_types/objecttype.py b/graphene/new_types/objecttype.py index 59e527e4..3c1c7791 100644 --- a/graphene/new_types/objecttype.py +++ b/graphene/new_types/objecttype.py @@ -28,6 +28,9 @@ class ObjectTypeMeta(AbstractTypeMeta): return type.__new__(cls, name, bases, dict(attrs, _meta=options)) + def __str__(cls): + return cls._meta.name + class ObjectType(six.with_metaclass(ObjectTypeMeta)): diff --git a/graphene/new_types/scalars.py b/graphene/new_types/scalars.py index 8a967dc3..838fbd2e 100644 --- a/graphene/new_types/scalars.py +++ b/graphene/new_types/scalars.py @@ -25,6 +25,9 @@ class ScalarTypeMeta(type): return super_new(cls, name, bases, dict(attrs, _meta=options)) + def __str__(cls): + return cls._meta.name + class Scalar(six.with_metaclass(ScalarTypeMeta, UnmountedType)): serialize = None diff --git a/graphene/new_types/tests/test_definition.py b/graphene/new_types/tests/test_definition.py index fb7e9b1c..c7b5210d 100644 --- a/graphene/new_types/tests/test_definition.py +++ b/graphene/new_types/tests/test_definition.py @@ -3,6 +3,8 @@ from collections import OrderedDict from py.test import raises from ..objecttype import ObjectType +from ..interface import Interface +from ..union import Union from ..scalars import String, Int, Boolean from ..field import Field from ..structures import List @@ -44,6 +46,15 @@ class Subscription(ObjectType): article_subscribe = Field(Article) # id=String() +class MyInterface(Interface): + pass + + +class MyUnion(Union): + class Meta: + types = (Article, ) + + def test_defines_a_query_only_schema(): blog_schema = Schema(Query) @@ -177,18 +188,18 @@ def test_defines_a_subscription_schema(): # assert schema.get_type_map()['SomeSubtype'] == SomeSubtype -# def test_stringifies_simple_types(): -# assert str(GraphQLInt) == 'Int' -# assert str(BlogArticle) == 'Article' -# assert str(InterfaceType) == 'Interface' -# assert str(UnionType) == 'Union' -# assert str(EnumType) == 'Enum' -# assert str(InputObjectType) == 'InputObject' -# assert str(GraphQLNonNull(GraphQLInt)) == 'Int!' -# assert str(GraphQLList(GraphQLInt)) == '[Int]' -# assert str(GraphQLNonNull(GraphQLList(GraphQLInt))) == '[Int]!' -# assert str(GraphQLList(GraphQLNonNull(GraphQLInt))) == '[Int!]' -# assert str(GraphQLList(GraphQLList(GraphQLInt))) == '[[Int]]' +def test_stringifies_simple_types(): + assert str(Int) == 'Int' + assert str(Article) == 'Article' + assert str(MyInterface) == 'MyInterface' + assert str(MyUnion) == 'MyUnion' + # assert str(EnumType) == 'Enum' + # assert str(InputObjectType) == 'InputObject' + # assert str(GraphQLNonNull(GraphQLInt)) == 'Int!' + # assert str(GraphQLList(GraphQLInt)) == '[Int]' + # assert str(GraphQLNonNull(GraphQLList(GraphQLInt))) == '[Int]!' + # assert str(GraphQLList(GraphQLNonNull(GraphQLInt))) == '[Int!]' + # assert str(GraphQLList(GraphQLList(GraphQLInt))) == '[[Int]]' # def test_identifies_input_types(): diff --git a/graphene/new_types/tests/test_union.py b/graphene/new_types/tests/test_union.py new file mode 100644 index 00000000..474a5193 --- /dev/null +++ b/graphene/new_types/tests/test_union.py @@ -0,0 +1,42 @@ +import pytest + +from ..objecttype import ObjectType +from ..union import Union + + +class MyObjectType1(ObjectType): + pass + + +class MyObjectType2(ObjectType): + pass + + +def test_generate_union(): + class MyUnion(Union): + '''Documentation''' + class Meta: + types = (MyObjectType1, MyObjectType2) + + assert MyUnion._meta.name == "MyUnion" + assert MyUnion._meta.description == "Documentation" + assert MyUnion._meta.types == (MyObjectType1, MyObjectType2) + + +def test_generate_union_with_meta(): + class MyUnion(Union): + class Meta: + name = 'MyOtherUnion' + description = 'Documentation' + types = (MyObjectType1, MyObjectType2) + + assert MyUnion._meta.name == "MyOtherUnion" + assert MyUnion._meta.description == "Documentation" + + +def test_generate_union_with_no_types(): + with pytest.raises(Exception) as exc_info: + class MyUnion(Union): + pass + + assert str(exc_info.value) == 'Must provide types for Union MyUnion.' diff --git a/graphene/new_types/union.py b/graphene/new_types/union.py new file mode 100644 index 00000000..5803c0be --- /dev/null +++ b/graphene/new_types/union.py @@ -0,0 +1,37 @@ +import six + +from ..utils.is_base_type import is_base_type +from .options import Options + + +class UnionMeta(type): + + def __new__(cls, name, bases, attrs): + # Also ensure initialization is only performed for subclasses of + # Union + if not is_base_type(bases, UnionMeta): + return type.__new__(cls, name, bases, attrs) + + options = Options( + attrs.pop('Meta', None), + name=name, + description=attrs.get('__doc__'), + types=(), + ) + + assert ( + isinstance(options.types, (list, tuple)) and + len(options.types) > 0 + ), 'Must provide types for Union {}.'.format(options.name) + + return type.__new__(cls, name, bases, dict(attrs, _meta=options)) + + def __str__(cls): + return cls._meta.name + + +class Union(six.with_metaclass(UnionMeta)): + resolve_type = None + + def __init__(self, *args, **kwargs): + raise Exception("An Union cannot be intitialized")