Skip to content

Commit 3157d98

Browse files
committed
GraphQLUnion shall now accept a callable for types.
This will make functionality equivalent to all the other types. i.e. GraphQLInterfaceType and GraphQLObjectType when it comes to defining fields/interfaces/types.
1 parent c49a572 commit 3157d98

File tree

4 files changed

+61
-21
lines changed

4 files changed

+61
-21
lines changed

graphql/core/type/definition.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ def resolve_type(self, value):
425425
if isinstance(value, Cat):
426426
return CatType()
427427
"""
428-
__slots__ = 'name', 'description', '_resolve_type', '_types', '_possible_type_names'
428+
__slots__ = 'name', 'description', '_resolve_type', '_types', '_possible_type_names', '_possible_types'
429429

430430
def __init__(self, name, types=None, resolve_type=None, description=None):
431431
assert name, 'Type must be named.'
@@ -437,28 +437,15 @@ def __init__(self, name, types=None, resolve_type=None, description=None):
437437
assert callable(resolve_type), '{} must provide "resolve_type" as a function.'.format(self)
438438

439439
self._resolve_type = resolve_type
440-
441-
assert isinstance(types, (list, tuple)) and len(types) > 0, 'Must provide types for Union {}.'.format(name)
442-
has_resolve_type_fn = callable(self._resolve_type)
443-
444-
for type in types:
445-
assert isinstance(type, GraphQLObjectType), (
446-
'{} may only contain Object types, it cannot contain: {}.'.format(self, type)
447-
)
448-
449-
if not has_resolve_type_fn:
450-
assert callable(type.is_type_of), (
451-
'Union Type {} does not provide a "resolve_type" function '
452-
'and possible Type {} does not provide a "is_type_of" '
453-
'function. There is no way to resolve this possible type '
454-
'during execution.'
455-
).format(self, type)
456-
457440
self._types = types
441+
self._possible_types = None
458442
self._possible_type_names = None
459443

460444
def get_possible_types(self):
461-
return self._types
445+
if self._possible_types is None:
446+
self._possible_types = define_types(self, self._types)
447+
448+
return self._possible_types
462449

463450
def is_possible_type(self, type):
464451
if self._possible_type_names is None:
@@ -475,6 +462,29 @@ def resolve_type(self, value, info):
475462
return get_type_of(value, info, self)
476463

477464

465+
def define_types(union_type, types):
466+
if callable(types):
467+
types = types()
468+
469+
assert isinstance(types, (list, tuple)) and len(types) > 0, 'Must provide types for Union {}.'.format(union_type.name)
470+
has_resolve_type_fn = callable(union_type._resolve_type)
471+
472+
for type in types:
473+
assert isinstance(type, GraphQLObjectType), (
474+
'{} may only contain Object types, it cannot contain: {}.'.format(union_type, type)
475+
)
476+
477+
if not has_resolve_type_fn:
478+
assert callable(type.is_type_of), (
479+
'Union Type {} does not provide a "resolve_type" function '
480+
'and possible Type {} does not provide a "is_type_of" '
481+
'function. There is no way to resolve this possible type '
482+
'during execution.'
483+
).format(union_type, type)
484+
485+
return types
486+
487+
478488
class GraphQLEnumType(GraphQLType):
479489
"""Enum Type Definition
480490

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[flake8]
2-
exclude = tests,scripts,setup.py,docs,libgraphqlparser
2+
exclude = tests,scripts,setup.py,docs
33
max-line-length = 160

tests/core_type/test_definition.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def test_prohibits_putting_non_object_types_in_unions():
241241
]
242242
for x in bad_union_types:
243243
with raises(Exception) as excinfo:
244-
GraphQLUnionType('BadUnion', [x])
244+
GraphQLSchema(GraphQLObjectType('Root', fields={'union': GraphQLField(GraphQLUnionType('BadUnion', [x]))}))
245245

246246
assert 'BadUnion may only contain Object types, it cannot contain: ' + str(x) + '.' \
247247
== str(excinfo.value)

tests/core_type/test_validation.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,36 @@ def test_rejects_a_union_type_with_incorrectly_typed_types(self):
476476
assert str(excinfo.value) == 'Must provide types for Union SomeUnion.'
477477

478478

479+
# noinspection PyMethodMayBeStatic,PyPep8Naming
480+
class TestTypeSystem_UnionTypesMustBeCallableThatReturnsArray:
481+
def test_accepts_a_union_type_with_aray_types(self):
482+
assert schema_with_field_type(GraphQLUnionType(
483+
name='SomeUnion',
484+
resolve_type=_none,
485+
types=lambda: [SomeObjectType]
486+
))
487+
488+
def test_rejects_a_union_type_with_empty_types(self):
489+
with raises(AssertionError) as excinfo:
490+
schema_with_field_type(GraphQLUnionType(
491+
name='SomeUnion',
492+
resolve_type=_none,
493+
types=lambda: []
494+
))
495+
496+
assert str(excinfo.value) == 'Must provide types for Union SomeUnion.'
497+
498+
def test_rejects_a_union_type_with_incorrectly_typed_types(self):
499+
with raises(AssertionError) as excinfo:
500+
schema_with_field_type(GraphQLUnionType(
501+
name='SomeUnion',
502+
resolve_type=_none,
503+
types=lambda: {'SomeObjectType': SomeObjectType}
504+
))
505+
506+
assert str(excinfo.value) == 'Must provide types for Union SomeUnion.'
507+
508+
479509
def schema_with_input_object(input_object_type):
480510
return GraphQLSchema(
481511
query=GraphQLObjectType(

0 commit comments

Comments
 (0)