Skip to content

Allow adding GraphQL types to Graphene schema #1224

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion graphene/types/objecttype.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import inspect

from .base import BaseOptions, BaseType, BaseTypeMeta
from .field import Field
from .interface import Interface
Expand Down Expand Up @@ -137,7 +139,7 @@ def __init_subclass_with_meta__(
fields = {}

for interface in interfaces:
assert issubclass(
assert inspect.isclass(interface) and issubclass(
interface, Interface
), f'All interfaces of {cls.__name__} must be a subclass of Interface. Received "{interface}".'
fields.update(interface._meta.fields)
Expand Down
9 changes: 8 additions & 1 deletion graphene/types/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
GraphQLObjectType,
GraphQLSchema,
GraphQLString,
GraphQLType,
Undefined,
)

Expand Down Expand Up @@ -106,6 +107,11 @@ def __init__(
def add_type(self, graphene_type):
if inspect.isfunction(graphene_type):
graphene_type = graphene_type()

# If type is a GraphQLType from graphql-core then return it immediately
if isinstance(graphene_type, GraphQLType):
return graphene_type

if isinstance(graphene_type, List):
return GraphQLList(self.add_type(graphene_type.of_type))
if isinstance(graphene_type, NonNull):
Expand Down Expand Up @@ -252,7 +258,8 @@ def types():
union_types = []
for graphene_objecttype in graphene_type._meta.types:
object_type = create_graphql_type(graphene_objecttype)
assert object_type.graphene_type == graphene_objecttype
if hasattr(object_type, "graphene_type"):
assert object_type.graphene_type == graphene_objecttype
union_types.append(object_type)
return union_types

Expand Down
159 changes: 159 additions & 0 deletions graphene/types/tests/test_type_map.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from textwrap import dedent

import pytest
from graphql import parse, build_ast_schema
from graphql.type import (
GraphQLArgument,
GraphQLEnumType,
Expand All @@ -20,6 +24,7 @@
from ..scalars import Int, String
from ..structures import List, NonNull
from ..schema import Schema
from ..union import Union


def create_type_map(types, auto_camelcase=True):
Expand Down Expand Up @@ -270,3 +275,157 @@ class Meta:
assert graphql_type.is_type_of
assert graphql_type.is_type_of({}, None) is True
assert graphql_type.is_type_of(MyObjectType(), None) is False


def test_graphql_type():
"""Type map should allow direct GraphQL types"""
MyGraphQLType = GraphQLObjectType(
name="MyGraphQLType",
fields={
"hello": GraphQLField(GraphQLString, resolve=lambda obj, info: "world")
},
)

class Query(ObjectType):
graphql_type = Field(MyGraphQLType)

def resolve_graphql_type(root, info):
return {}

schema = Schema(query=Query)
assert str(schema) == dedent(
"""\
type Query {
graphqlType: MyGraphQLType
}

type MyGraphQLType {
hello: String
}
"""
)

results = schema.execute(
"""
query {
graphqlType {
hello
}
}
"""
)
assert not results.errors
assert results.data == {"graphqlType": {"hello": "world"}}


def test_graphql_type_interface():
MyGraphQLInterface = GraphQLInterfaceType(
name="MyGraphQLType",
fields={
"hello": GraphQLField(GraphQLString, resolve=lambda obj, info: "world")
},
)

with pytest.raises(AssertionError) as error:

class MyGrapheneType(ObjectType):
class Meta:
interfaces = (MyGraphQLInterface,)

assert str(error.value) == (
"All interfaces of MyGrapheneType must be a subclass of Interface. "
'Received "MyGraphQLType".'
)


def test_graphql_type_union():
MyGraphQLType = GraphQLObjectType(
name="MyGraphQLType",
fields={
"hello": GraphQLField(GraphQLString, resolve=lambda obj, info: "world")
},
)

class MyGrapheneType(ObjectType):
hi = String(default_value="world")

class MyUnion(Union):
class Meta:
types = (MyGraphQLType, MyGrapheneType)

@classmethod
def resolve_type(cls, instance, info):
return MyGraphQLType

class Query(ObjectType):
my_union = Field(MyUnion)

def resolve_my_union(root, info):
return {}

schema = Schema(query=Query)
assert str(schema) == dedent(
"""\
type Query {
myUnion: MyUnion
}

union MyUnion = MyGraphQLType | MyGrapheneType

type MyGraphQLType {
hello: String
}

type MyGrapheneType {
hi: String
}
"""
)

results = schema.execute(
"""
query {
myUnion {
__typename
}
}
"""
)
assert not results.errors
assert results.data == {"myUnion": {"__typename": "MyGraphQLType"}}


def test_graphql_type_from_sdl():
types = """
type Pet {
name: String!
}

type User {
name: String!
pets: [Pet!]!
}
"""
ast_document = parse(types)
sdl_schema = build_ast_schema(ast_document)

class Query(ObjectType):
my_user = Field(sdl_schema.get_type("User"))

schema = Schema(query=Query)
assert str(schema) == dedent(
"""\
type Query {
myUser: User
}

type User {
name: String!
pets: [Pet!]!
}

type Pet {
name: String!
}
"""
)