Skip to content

Commit 24cd190

Browse files
committed
Added support for UnionTypes
1 parent d2ca8a9 commit 24cd190

File tree

5 files changed

+49
-6
lines changed

5 files changed

+49
-6
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Graphene is a Python library for building GraphQL schemas/types fast and easily.
88
- **Django:** Automatic *Django model* mapping to Graphene Types. Check a fully working [Django](http://github.com/graphql-python/swapi-graphene) implementation
99

1010

11-
*But, what is supported in this Python version?* **Everything**: Interfaces, ObjectTypes, Mutations and Relay (Nodes, Connections and Mutations).
11+
*What is supported in this Python version?* **Everything**: Interfaces, ObjectTypes, Mutations, Scalars, Unions and Relay (Nodes, Connections and Mutations).
1212

1313

1414
## Installation

README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ easily.
1212
`Django <http://github.com/graphql-python/swapi-graphene>`__
1313
implementation
1414

15-
*But, what is supported in this Python version?* **Everything**:
16-
Interfaces, ObjectTypes, Mutations and Relay (Nodes, Connections and
17-
Mutations).
15+
*What is supported in this Python version?* **Everything**: Interfaces,
16+
ObjectTypes, Mutations, Scalars, Unions and Relay (Nodes, Connections
17+
and Mutations).
1818

1919
Installation
2020
------------

graphene/core/options.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ def __init__(self, meta=None):
1313
self.local_fields = []
1414
self.is_interface = False
1515
self.is_mutation = False
16+
self.is_union = False
1617
self.interfaces = []
1718
self.parents = []
19+
self.types = []
1820
self.valid_attrs = DEFAULT_NAMES
1921

2022
def contribute_to_class(self, cls, name):

graphene/core/types/objecttype.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from graphene import signals
99
from graphql.core.type import (GraphQLInputObjectType, GraphQLInterfaceType,
10-
GraphQLObjectType)
10+
GraphQLObjectType, GraphQLUnionType)
1111

1212
from ..exceptions import SkipField
1313
from ..options import Options
@@ -51,10 +51,17 @@ def __new__(cls, name, bases, attrs):
5151

5252
new_class._meta.is_interface = new_class.is_interface(parents)
5353
new_class._meta.is_mutation = new_class.is_mutation(parents)
54+
union_types = [p for p in parents if issubclass(p, BaseObjectType)]
55+
56+
new_class._meta.is_union = len(union_types) > 1
57+
new_class._meta.types = union_types
5458

5559
assert not (
5660
new_class._meta.is_interface and new_class._meta.is_mutation)
5761

62+
assert not (
63+
new_class._meta.is_interface and new_class._meta.is_union)
64+
5865
# Add all attributes to the class.
5966
for obj_name, obj in attrs.items():
6067
new_class.add_to_class(obj_name, obj)
@@ -66,6 +73,8 @@ def __new__(cls, name, bases, attrs):
6673
new_class.add_extra_fields()
6774

6875
new_fields = new_class._meta.local_fields
76+
assert not(new_class._meta.is_union and new_fields), 'An union cannot have extra fields'
77+
6978
field_names = {f.name: f for f in new_fields}
7079

7180
for base in parents:
@@ -129,6 +138,8 @@ class BaseObjectType(BaseType):
129138
def __new__(cls, *args, **kwargs):
130139
if cls._meta.is_interface:
131140
raise Exception("An interface cannot be initialized")
141+
if cls._meta.is_union:
142+
raise Exception("An union cannot be initialized")
132143
return super(BaseObjectType, cls).__new__(cls)
133144

134145
def __init__(self, *args, **kwargs):
@@ -182,6 +193,12 @@ def internal_type(cls, schema):
182193
resolve_type=partial(cls.resolve_type, schema),
183194
fields=partial(cls.get_fields, schema)
184195
)
196+
elif cls._meta.is_union:
197+
return GraphQLUnionType(
198+
cls._meta.type_name,
199+
types=cls._meta.types,
200+
description=cls._meta.description,
201+
)
185202
return GraphQLObjectType(
186203
cls._meta.type_name,
187204
description=cls._meta.description,

graphene/core/types/tests/test_objecttype.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from graphene.core.types import Int, Interface, String
55
from graphql.core.execution.middlewares.utils import (resolver_has_tag,
66
tag_resolver)
7-
from graphql.core.type import GraphQLInterfaceType, GraphQLObjectType
7+
from graphql.core.type import (GraphQLInterfaceType, GraphQLObjectType,
8+
GraphQLUnionType)
89

910

1011
class Character(Interface):
@@ -34,6 +35,16 @@ def write_prop(self):
3435
def write_prop(self, value):
3536
self._write_prop = value
3637

38+
39+
class Droid(Character):
40+
'''Droid description'''
41+
pass
42+
43+
44+
class CharacterType(Droid, Human):
45+
'''Union Type'''
46+
pass
47+
3748
schema = Schema()
3849

3950

@@ -52,6 +63,19 @@ def test_interface_cannot_initialize():
5263
assert 'An interface cannot be initialized' == str(excinfo.value)
5364

5465

66+
def test_union():
67+
object_type = schema.T(CharacterType)
68+
assert CharacterType._meta.is_union is True
69+
assert isinstance(object_type, GraphQLUnionType)
70+
assert object_type.description == 'Union Type'
71+
72+
73+
def test_union_cannot_initialize():
74+
with raises(Exception) as excinfo:
75+
CharacterType()
76+
assert 'An union cannot be initialized' == str(excinfo.value)
77+
78+
5579
def test_interface_resolve_type():
5680
resolve_type = Character.resolve_type(schema, Human(object()))
5781
assert isinstance(resolve_type, GraphQLObjectType)

0 commit comments

Comments
 (0)