Start porting to graphql-core-next

This commit is contained in:
Paul Hallett 2019-05-04 20:39:28 +01:00
parent abff3d75a3
commit 8a7a321136
No known key found for this signature in database
GPG Key ID: 529C11F0C93CDF11
25 changed files with 788 additions and 689 deletions

View File

@ -9,3 +9,10 @@ docs:
pip install -r requirements.txt &&\ pip install -r requirements.txt &&\
make html &&\ make html &&\
cd - cd -
dev-setup:
pip install -e ".[test]"
tests:
py.test graphene

View File

@ -28,7 +28,7 @@ from .types import (
Dynamic, Dynamic,
Union, Union,
Context, Context,
ResolveInfo, GraphQLResolveInfo,
) )
from .relay import ( from .relay import (
Node, Node,
@ -84,7 +84,7 @@ __all__ = [
"PageInfo", "PageInfo",
"lazy_import", "lazy_import",
"Context", "Context",
"ResolveInfo", "GraphQLResolveInfo",
# Deprecated # Deprecated
"AbstractType", "AbstractType",
] ]

View File

@ -2,8 +2,6 @@ from __future__ import absolute_import
import six import six
from graphql.pyutils.compat import Enum
try: try:
from inspect import signature from inspect import signature
except ImportError: except ImportError:

View File

@ -2,14 +2,155 @@ import re
from collections import Iterable, OrderedDict from collections import Iterable, OrderedDict
from functools import partial from functools import partial
from graphql_relay import connection_from_list
from ..types import Boolean, Enum, Int, Interface, List, NonNull, Scalar, String, Union from ..types import Boolean, Enum, Int, Interface, List, NonNull, Scalar, String, Union
from ..types.field import Field from ..types.field import Field
from ..types.objecttype import ObjectType, ObjectTypeOptions from ..types.objecttype import ObjectType, ObjectTypeOptions
from ..utils.thenables import maybe_thenable from ..utils.thenables import maybe_thenable
from ..utils import base64, is_str, unbase64
from .node import is_node from .node import is_node
from .connectiontypes import ConnectionType, PageInfoType, EdgeType
def connection_from_list(data, args=None, **kwargs):
'''
A simple function that accepts an array and connection arguments, and returns
a connection object for use in GraphQL. It uses array offsets as pagination,
so pagination will only work if the array is static.
'''
_len = len(data)
return connection_from_list_slice(
data,
args,
slice_start=0,
list_length=_len,
list_slice_length=_len,
**kwargs
)
def connection_from_list_slice(list_slice, args=None, connection_type=None,
edge_type=None, pageinfo_type=None,
slice_start=0, list_length=0, list_slice_length=None):
'''
Given a slice (subset) of an array, returns a connection object for use in
GraphQL.
This function is similar to `connectionFromArray`, but is intended for use
cases where you know the cardinality of the connection, consider it too large
to materialize the entire array, and instead wish pass in a slice of the
total result large enough to cover the range specified in `args`.
'''
connection_type = connection_type or Connection
edge_type = edge_type or Edge
pageinfo_type = pageinfo_type or PageInfo
args = args or {}
before = args.get('before')
after = args.get('after')
first = args.get('first')
last = args.get('last')
if list_slice_length is None:
list_slice_length = len(list_slice)
slice_end = slice_start + list_slice_length
before_offset = get_offset_with_default(before, list_length)
after_offset = get_offset_with_default(after, -1)
start_offset = max(
slice_start - 1,
after_offset,
-1
) + 1
end_offset = min(
slice_end,
before_offset,
list_length
)
if isinstance(first, int):
end_offset = min(
end_offset,
start_offset + first
)
if isinstance(last, int):
start_offset = max(
start_offset,
end_offset - last
)
# If supplied slice is too large, trim it down before mapping over it.
_slice = list_slice[
max(start_offset - slice_start, 0):
list_slice_length - (slice_end - end_offset)
]
edges = [
edge_type(
node=node,
cursor=offset_to_cursor(start_offset + i)
)
for i, node in enumerate(_slice)
]
first_edge_cursor = edges[0].cursor if edges else None
last_edge_cursor = edges[-1].cursor if edges else None
lower_bound = after_offset + 1 if after else 0
upper_bound = before_offset if before else list_length
return connection_type(
edges=edges,
page_info=pageinfo_type(
start_cursor=first_edge_cursor,
end_cursor=last_edge_cursor,
has_previous_page=isinstance(last, int) and start_offset > lower_bound,
has_next_page=isinstance(first, int) and end_offset < upper_bound
)
)
def offset_to_cursor(offset):
'''
Creates the cursor string from an offset.
'''
return base64(PREFIX + str(offset))
def cursor_to_offset(cursor):
'''
Rederives the offset from the cursor string.
'''
try:
return int(unbase64(cursor)[len(PREFIX):])
except:
return None
def cursor_for_object_in_connection(data, _object):
'''
Return the cursor associated with an object in an array.
'''
if _object not in data:
return None
offset = data.index(_object)
return offset_to_cursor(offset)
def get_offset_with_default(cursor=None, default_offset=0):
'''
Given an optional cursor and a default offset, returns the offset
to use; if the cursor contains a valid offset, that will be used,
otherwise it will be the default.
'''
if not is_str(cursor):
return default_offset
offset = cursor_to_offset(cursor)
try:
return int(offset)
except:
return default_offset
class PageInfo(ObjectType): class PageInfo(ObjectType):
class Meta: class Meta:

View File

@ -0,0 +1,42 @@
class ConnectionType:
def __init__(self, edges, page_info):
self.edges = edges
self.page_info = page_info
def to_dict(self):
return {
'edges': [e.to_dict() for e in self.edges],
'pageInfo': self.page_info.to_dict(),
}
class PageInfoType:
def __init__(self, start_cursor="", end_cursor="",
has_previous_page=False, has_next_page=False):
self.startCursor = start_cursor
self.endCursor = end_cursor
self.hasPreviousPage = has_previous_page
self.hasNextPage = has_next_page
def to_dict(self):
return {
'startCursor': self.startCursor,
'endCursor': self.endCursor,
'hasPreviousPage': self.hasPreviousPage,
'hasNextPage': self.hasNextPage,
}
class EdgeType:
def __init__(self, node, cursor):
self.node = node
self.cursor = cursor
def to_dict(self):
return {
'node': self.node,
'cursor': self.cursor,
}

View File

@ -2,12 +2,12 @@ from collections import OrderedDict
from functools import partial from functools import partial
from inspect import isclass from inspect import isclass
from graphql_relay import from_global_id, to_global_id
from ..types import ID, Field, Interface, ObjectType from ..types import ID, Field, Interface, ObjectType
from ..types.interface import InterfaceOptions from ..types.interface import InterfaceOptions
from ..types.utils import get_type from ..types.utils import get_type
from .utils import base64, unbase64
def is_node(objecttype): def is_node(objecttype):
""" """

View File

@ -1,6 +1,6 @@
from collections import OrderedDict from collections import OrderedDict
from graphql_relay.utils import base64 from ..utils import base64
from promise import Promise from promise import Promise
from ...types import ObjectType, Schema, String from ...types import ObjectType, Schema, String

View File

@ -1,4 +1,4 @@
from graphql_relay import to_global_id from ..utils import to_global_id
from ...types import ID, NonNull, ObjectType, String from ...types import ID, NonNull, ObjectType, String
from ...types.definitions import GrapheneObjectType from ...types.definitions import GrapheneObjectType

View File

@ -1,6 +1,6 @@
from collections import OrderedDict from collections import OrderedDict
from graphql_relay import to_global_id from ..utils import to_global_id
from ...types import ObjectType, Schema, String from ...types import ObjectType, Schema, String
from ..node import Node, is_node from ..node import Node, is_node

19
graphene/relay/utils.py Normal file
View File

@ -0,0 +1,19 @@
from ..utils import base64, unbase64
def to_global_id(type, id):
'''
Takes a type name and an ID specific to that type name, and returns a
"global ID" that is unique among all types.
'''
return base64(':'.join([type, text_type(id)]))
def from_global_id(global_id):
'''
Takes the "global ID" created by toGlobalID, and retuns the type name and ID
used to create it.
'''
unbased_global_id = unbase64(global_id)
_type, _id = unbased_global_id.split(':', 1)
return _type, _id

View File

@ -1,5 +1,5 @@
# flake8: noqa # flake8: noqa
from graphql import ResolveInfo from graphql import GraphQLResolveInfo
from .objecttype import ObjectType from .objecttype import ObjectType
from .interface import Interface from .interface import Interface
@ -51,7 +51,7 @@ __all__ = [
"Dynamic", "Dynamic",
"Union", "Union",
"Context", "Context",
"ResolveInfo", "GraphQLResolveInfo",
# Deprecated # Deprecated
"AbstractType", "AbstractType",
] ]

View File

@ -1,10 +1,11 @@
from collections import OrderedDict from collections import OrderedDict
from enum import Enum
import six import six
from graphene.utils.subclass_with_meta import SubclassWithMeta_Meta from graphene.utils.subclass_with_meta import SubclassWithMeta_Meta
from ..pyutils.compat import Enum as PyEnum
from .base import BaseOptions, BaseType from .base import BaseOptions, BaseType
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
@ -15,8 +16,6 @@ def eq_enum(self, other):
return self.value is other return self.value is other
EnumType = type(PyEnum)
class EnumOptions(BaseOptions): class EnumOptions(BaseOptions):
enum = None # type: Enum enum = None # type: Enum
@ -29,7 +28,7 @@ class EnumMeta(SubclassWithMeta_Meta):
# We remove the Meta attribute from the class to not collide # We remove the Meta attribute from the class to not collide
# with the enum values. # with the enum values.
enum_members.pop("Meta", None) enum_members.pop("Meta", None)
enum = PyEnum(cls.__name__, enum_members) enum = Enum(cls.__name__, enum_members)
return SubclassWithMeta_Meta.__new__( return SubclassWithMeta_Meta.__new__(
cls, name, bases, OrderedDict(classdict, __enum__=enum), **options cls, name, bases, OrderedDict(classdict, __enum__=enum), **options
) )
@ -46,7 +45,8 @@ class EnumMeta(SubclassWithMeta_Meta):
def __call__(cls, *args, **kwargs): # noqa: N805 def __call__(cls, *args, **kwargs): # noqa: N805
if cls is Enum: if cls is Enum:
description = kwargs.pop("description", None) description = kwargs.pop("description", None)
return cls.from_enum(PyEnum(*args, **kwargs), description=description) kwargs['description'] = description
return Enum(*args, **kwargs)
return super(EnumMeta, cls).__call__(*args, **kwargs) return super(EnumMeta, cls).__call__(*args, **kwargs)
# return cls._meta.enum(*args, **kwargs) # return cls._meta.enum(*args, **kwargs)

View File

@ -1,12 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from graphql.language.ast import ( from graphql.language.ast import (
BooleanValue, BooleanValueNode,
FloatValue, FloatValueNode,
IntValue, IntValueNode,
ListValue, ListValueNode,
ObjectValue, ObjectValueNode,
StringValue, StringValueNode,
) )
from graphene.types.scalars import MAX_INT, MIN_INT from graphene.types.scalars import MAX_INT, MIN_INT
@ -30,15 +30,15 @@ class GenericScalar(Scalar):
@staticmethod @staticmethod
def parse_literal(ast): def parse_literal(ast):
if isinstance(ast, (StringValue, BooleanValue)): if isinstance(ast, (StringValueNode, BooleanValueNode)):
return ast.value return ast.value
elif isinstance(ast, IntValue): elif isinstance(ast, IntValueNode):
num = int(ast.value) num = int(ast.value)
if MIN_INT <= num <= MAX_INT: if MIN_INT <= num <= MAX_INT:
return num return num
elif isinstance(ast, FloatValue): elif isinstance(ast, FloatValueNode):
return float(ast.value) return float(ast.value)
elif isinstance(ast, ListValue): elif isinstance(ast, ListValueNode):
return [GenericScalar.parse_literal(value) for value in ast.values] return [GenericScalar.parse_literal(value) for value in ast.values]
elif isinstance(ast, ObjectValue): elif isinstance(ast, ObjectValue):
return { return {

View File

@ -1,5 +1,10 @@
import six import six
from graphql.language.ast import BooleanValue, FloatValue, IntValue, StringValue from graphql.language.ast import (
BooleanValueNode,
FloatValueNode,
IntValueNode,
StringValueNode
)
from .base import BaseOptions, BaseType from .base import BaseOptions, BaseType
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
@ -99,7 +104,7 @@ class Float(Scalar):
@staticmethod @staticmethod
def parse_literal(ast): def parse_literal(ast):
if isinstance(ast, (FloatValue, IntValue)): if isinstance(ast, (FloatValueNode, IntValueNode)):
return float(ast.value) return float(ast.value)
@ -121,7 +126,7 @@ class String(Scalar):
@staticmethod @staticmethod
def parse_literal(ast): def parse_literal(ast):
if isinstance(ast, StringValue): if isinstance(ast, StringValueNode):
return ast.value return ast.value
@ -135,7 +140,7 @@ class Boolean(Scalar):
@staticmethod @staticmethod
def parse_literal(ast): def parse_literal(ast):
if isinstance(ast, BooleanValue): if isinstance(ast, BooleanValueNode):
return ast.value return ast.value

View File

@ -6,13 +6,13 @@ from graphql.type.directives import (
GraphQLIncludeDirective, GraphQLIncludeDirective,
GraphQLSkipDirective, GraphQLSkipDirective,
) )
from graphql.type.introspection import IntrospectionSchema from graphql.type.introspection import introspection_types
from graphql.utils.introspection_query import introspection_query from graphql.utilities.introspection_query import get_introspection_query
from graphql.utils.schema_printer import print_schema from graphql.utilities.schema_printer import print_schema
from .definitions import GrapheneGraphQLType from .definitions import GrapheneGraphQLType
from .objecttype import ObjectType from .objecttype import ObjectType
from .typemap import TypeMap, is_graphene_type from .typemap import is_graphene_type
def assert_valid_root_type(_type): def assert_valid_root_type(_type):
@ -25,103 +25,5 @@ def assert_valid_root_type(_type):
).format(_type) ).format(_type)
class Schema(GraphQLSchema): Schema = GraphQLSchema
"""
Schema Definition
A Schema is created by supplying the root types of each type of operation,
query and mutation (optional).
"""
def __init__(
self,
query=None,
mutation=None,
subscription=None,
directives=None,
types=None,
auto_camelcase=True,
):
assert_valid_root_type(query)
assert_valid_root_type(mutation)
assert_valid_root_type(subscription)
self._query = query
self._mutation = mutation
self._subscription = subscription
self.types = types
self.auto_camelcase = auto_camelcase
if directives is None:
directives = [GraphQLIncludeDirective, GraphQLSkipDirective]
assert all(
isinstance(d, GraphQLDirective) for d in directives
), "Schema directives must be List[GraphQLDirective] if provided but got: {}.".format(
directives
)
self._directives = directives
self.build_typemap()
def get_query_type(self):
return self.get_graphql_type(self._query)
def get_mutation_type(self):
return self.get_graphql_type(self._mutation)
def get_subscription_type(self):
return self.get_graphql_type(self._subscription)
def __getattr__(self, type_name):
"""
This function let the developer select a type in a given schema
by accessing its attrs.
Example: using schema.Query for accessing the "Query" type in the Schema
"""
_type = super(Schema, self).get_type(type_name)
if _type is None:
raise AttributeError('Type "{}" not found in the Schema'.format(type_name))
if isinstance(_type, GrapheneGraphQLType):
return _type.graphene_type
return _type
def get_graphql_type(self, _type):
if not _type:
return _type
if is_type(_type):
return _type
if is_graphene_type(_type):
graphql_type = self.get_type(_type._meta.name)
assert graphql_type, "Type {} not found in this schema.".format(
_type._meta.name
)
assert graphql_type.graphene_type == _type
return graphql_type
raise Exception("{} is not a valid GraphQL type.".format(_type))
def execute(self, *args, **kwargs):
return graphql(self, *args, **kwargs)
def introspect(self):
instrospection = self.execute(introspection_query)
if instrospection.errors:
raise instrospection.errors[0]
return instrospection.data
def __str__(self):
return print_schema(self)
def lazy(self, _type):
return lambda: self.get_type(_type)
def build_typemap(self):
initial_types = [
self._query,
self._mutation,
self._subscription,
IntrospectionSchema,
]
if self.types:
initial_types += self.types
self._type_map = TypeMap(
initial_types, auto_camelcase=self.auto_camelcase, schema=self
)

View File

@ -156,7 +156,7 @@ def test_bad_variables():
) )
assert len(result.errors) == 1 assert len(result.errors) == 1
# when `input` is not JSON serializable formatting the error message in # when `input` is not JSON serializable formatting the error message in
# `graphql.utils.is_valid_value` line 79 fails with a TypeError # `graphql.utilities.is_valid_value` line 79 fails with a TypeError
assert isinstance(result.errors[0], GraphQLError) assert isinstance(result.errors[0], GraphQLError)
print(result.errors[0]) print(result.errors[0])
assert result.data is None assert result.data is None

View File

@ -1,7 +1,7 @@
import six import six
from ..argument import Argument from ..argument import Argument
from ..enum import Enum, PyEnum from ..enum import Enum
from ..field import Field from ..field import Field
from ..inputfield import InputField from ..inputfield import InputField
from ..schema import ObjectType, Schema from ..schema import ObjectType, Schema
@ -52,88 +52,57 @@ def test_enum_instance_construction():
assert sorted([v.name for v in values]) == ["BLUE", "GREEN", "RED"] assert sorted([v.name for v in values]) == ["BLUE", "GREEN", "RED"]
def test_enum_from_builtin_enum():
PyRGB = PyEnum("RGB", "RED,GREEN,BLUE")
RGB = Enum.from_enum(PyRGB) # def test_enum_from_builtin_enum_accepts_lambda_description():
assert RGB._meta.enum == PyRGB # def custom_description(value):
assert RGB.RED # if not value:
assert RGB.GREEN # return "StarWars Episodes"
assert RGB.BLUE
# return "New Hope Episode" if value == Episode.NEWHOPE else "Other"
def test_enum_from_builtin_enum_accepts_lambda_description(): # def custom_deprecation_reason(value):
def custom_description(value): # return "meh" if value == Episode.NEWHOPE else None
if not value:
return "StarWars Episodes"
return "New Hope Episode" if value == Episode.NEWHOPE else "Other" # PyEpisode = PyEnum("PyEpisode", "NEWHOPE,EMPIRE,JEDI")
# Episode = Enum.from_enum(
# PyEpisode,
# description=custom_description,
# deprecation_reason=custom_deprecation_reason,
# )
def custom_deprecation_reason(value): # class Query(ObjectType):
return "meh" if value == Episode.NEWHOPE else None # foo = Episode()
PyEpisode = PyEnum("PyEpisode", "NEWHOPE,EMPIRE,JEDI") # schema = Schema(query=Query)
Episode = Enum.from_enum(
PyEpisode,
description=custom_description,
deprecation_reason=custom_deprecation_reason,
)
class Query(ObjectType): # GraphQLPyEpisode = schema._type_map["PyEpisode"].values
foo = Episode()
schema = Schema(query=Query) # assert schema._type_map["PyEpisode"].description == "StarWars Episodes"
# assert (
# GraphQLPyEpisode[0].name == "NEWHOPE"
# and GraphQLPyEpisode[0].description == "New Hope Episode"
# )
# assert (
# GraphQLPyEpisode[1].name == "EMPIRE"
# and GraphQLPyEpisode[1].description == "Other"
# )
# assert (
# GraphQLPyEpisode[2].name == "JEDI"
# and GraphQLPyEpisode[2].description == "Other"
# )
GraphQLPyEpisode = schema._type_map["PyEpisode"].values # assert (
# GraphQLPyEpisode[0].name == "NEWHOPE"
assert schema._type_map["PyEpisode"].description == "StarWars Episodes" # and GraphQLPyEpisode[0].deprecation_reason == "meh"
assert ( # )
GraphQLPyEpisode[0].name == "NEWHOPE" # assert (
and GraphQLPyEpisode[0].description == "New Hope Episode" # GraphQLPyEpisode[1].name == "EMPIRE"
) # and GraphQLPyEpisode[1].deprecation_reason is None
assert ( # )
GraphQLPyEpisode[1].name == "EMPIRE" # assert (
and GraphQLPyEpisode[1].description == "Other" # GraphQLPyEpisode[2].name == "JEDI"
) # and GraphQLPyEpisode[2].deprecation_reason is None
assert ( # )
GraphQLPyEpisode[2].name == "JEDI"
and GraphQLPyEpisode[2].description == "Other"
)
assert (
GraphQLPyEpisode[0].name == "NEWHOPE"
and GraphQLPyEpisode[0].deprecation_reason == "meh"
)
assert (
GraphQLPyEpisode[1].name == "EMPIRE"
and GraphQLPyEpisode[1].deprecation_reason is None
)
assert (
GraphQLPyEpisode[2].name == "JEDI"
and GraphQLPyEpisode[2].deprecation_reason is None
)
def test_enum_from_python3_enum_uses_enum_doc():
if not six.PY3:
return
from enum import Enum as PyEnum
class Color(PyEnum):
"""This is the description"""
RED = 1
GREEN = 2
BLUE = 3
RGB = Enum.from_enum(Color)
assert RGB._meta.enum == Color
assert RGB._meta.description == "This is the description"
assert RGB
assert RGB.RED
assert RGB.GREEN
assert RGB.BLUE
def test_enum_value_from_class(): def test_enum_value_from_class():

View File

@ -1,7 +1,7 @@
import json import json
from functools import partial from functools import partial
from graphql import GraphQLError, ResolveInfo, Source, execute, parse from graphql import GraphQLError, GraphQLResolveInfo, Source, execute, parse
from ..context import Context from ..context import Context
from ..dynamic import Dynamic from ..dynamic import Dynamic
@ -455,7 +455,7 @@ def test_query_annotated_resolvers():
return "{}-{}".format(self, info.context.key) return "{}-{}".format(self, info.context.key)
def resolve_info(self, info): def resolve_info(self, info):
assert isinstance(info, ResolveInfo) assert isinstance(info, GraphQLResolveInfo)
return "{}-{}".format(self, info.field_name) return "{}-{}".format(self, info.field_name)
test_schema = Schema(Query) test_schema = Schema(Query)

View File

@ -1,286 +1,286 @@
import pytest # import pytest
from graphql.type import ( # from graphql.type import (
GraphQLArgument, # GraphQLArgument,
GraphQLEnumType, # GraphQLEnumType,
GraphQLEnumValue, # GraphQLEnumValue,
GraphQLField, # GraphQLField,
GraphQLInputObjectField, # GraphQLInputField,
GraphQLInputObjectType, # GraphQLInputObjectType,
GraphQLInterfaceType, # GraphQLInterfaceType,
GraphQLObjectType, # GraphQLObjectType,
GraphQLString, # GraphQLString,
) # )
from ..dynamic import Dynamic # from ..dynamic import Dynamic
from ..enum import Enum # from ..enum import Enum
from ..field import Field # from ..field import Field
from ..inputfield import InputField # from ..inputfield import InputField
from ..inputobjecttype import InputObjectType # from ..inputobjecttype import InputObjectType
from ..interface import Interface # from ..interface import Interface
from ..objecttype import ObjectType # from ..objecttype import ObjectType
from ..scalars import Int, String # from ..scalars import Int, String
from ..structures import List, NonNull # from ..structures import List, NonNull
from ..typemap import TypeMap, resolve_type # from ..typemap import resolve_type
def test_enum(): # def test_enum():
class MyEnum(Enum): # class MyEnum(Enum):
"""Description""" # """Description"""
foo = 1 # foo = 1
bar = 2 # bar = 2
@property # @property
def description(self): # def description(self):
return "Description {}={}".format(self.name, self.value) # return "Description {}={}".format(self.name, self.value)
@property # @property
def deprecation_reason(self): # def deprecation_reason(self):
if self == MyEnum.foo: # if self == MyEnum.foo:
return "Is deprecated" # return "Is deprecated"
typemap = TypeMap([MyEnum]) # typemap = TypeMap([MyEnum])
assert "MyEnum" in typemap # assert "MyEnum" in typemap
graphql_enum = typemap["MyEnum"] # graphql_enum = typemap["MyEnum"]
assert isinstance(graphql_enum, GraphQLEnumType) # assert isinstance(graphql_enum, GraphQLEnumType)
assert graphql_enum.name == "MyEnum" # assert graphql_enum.name == "MyEnum"
assert graphql_enum.description == "Description" # assert graphql_enum.description == "Description"
values = graphql_enum.values # values = graphql_enum.values
assert values == [ # assert values == [
GraphQLEnumValue( # GraphQLEnumValue(
name="foo", # name="foo",
value=1, # value=1,
description="Description foo=1", # description="Description foo=1",
deprecation_reason="Is deprecated", # deprecation_reason="Is deprecated",
), # ),
GraphQLEnumValue(name="bar", value=2, description="Description bar=2"), # GraphQLEnumValue(name="bar", value=2, description="Description bar=2"),
] # ]
def test_objecttype(): # def test_objecttype():
class MyObjectType(ObjectType): # class MyObjectType(ObjectType):
"""Description""" # """Description"""
foo = String( # foo = String(
bar=String(description="Argument description", default_value="x"), # bar=String(description="Argument description", default_value="x"),
description="Field description", # description="Field description",
) # )
bar = String(name="gizmo") # bar = String(name="gizmo")
def resolve_foo(self, bar): # def resolve_foo(self, bar):
return bar # return bar
typemap = TypeMap([MyObjectType]) # typemap = TypeMap([MyObjectType])
assert "MyObjectType" in typemap # assert "MyObjectType" in typemap
graphql_type = typemap["MyObjectType"] # graphql_type = typemap["MyObjectType"]
assert isinstance(graphql_type, GraphQLObjectType) # assert isinstance(graphql_type, GraphQLObjectType)
assert graphql_type.name == "MyObjectType" # assert graphql_type.name == "MyObjectType"
assert graphql_type.description == "Description" # assert graphql_type.description == "Description"
fields = graphql_type.fields # fields = graphql_type.fields
assert list(fields.keys()) == ["foo", "gizmo"] # assert list(fields.keys()) == ["foo", "gizmo"]
foo_field = fields["foo"] # foo_field = fields["foo"]
assert isinstance(foo_field, GraphQLField) # assert isinstance(foo_field, GraphQLField)
assert foo_field.description == "Field description" # assert foo_field.description == "Field description"
assert foo_field.args == { # assert foo_field.args == {
"bar": GraphQLArgument( # "bar": GraphQLArgument(
GraphQLString, # GraphQLString,
description="Argument description", # description="Argument description",
default_value="x", # default_value="x",
out_name="bar", # out_name="bar",
) # )
} # }
def test_dynamic_objecttype(): # def test_dynamic_objecttype():
class MyObjectType(ObjectType): # class MyObjectType(ObjectType):
"""Description""" # """Description"""
bar = Dynamic(lambda: Field(String)) # bar = Dynamic(lambda: Field(String))
own = Field(lambda: MyObjectType) # own = Field(lambda: MyObjectType)
typemap = TypeMap([MyObjectType]) # typemap = TypeMap([MyObjectType])
assert "MyObjectType" in typemap # assert "MyObjectType" in typemap
assert list(MyObjectType._meta.fields.keys()) == ["bar", "own"] # assert list(MyObjectType._meta.fields.keys()) == ["bar", "own"]
graphql_type = typemap["MyObjectType"] # graphql_type = typemap["MyObjectType"]
fields = graphql_type.fields # fields = graphql_type.fields
assert list(fields.keys()) == ["bar", "own"] # assert list(fields.keys()) == ["bar", "own"]
assert fields["bar"].type == GraphQLString # assert fields["bar"].type == GraphQLString
assert fields["own"].type == graphql_type # assert fields["own"].type == graphql_type
def test_interface(): # def test_interface():
class MyInterface(Interface): # class MyInterface(Interface):
"""Description""" # """Description"""
foo = String( # foo = String(
bar=String(description="Argument description", default_value="x"), # bar=String(description="Argument description", default_value="x"),
description="Field description", # description="Field description",
) # )
bar = String(name="gizmo", first_arg=String(), other_arg=String(name="oth_arg")) # bar = String(name="gizmo", first_arg=String(), other_arg=String(name="oth_arg"))
own = Field(lambda: MyInterface) # own = Field(lambda: MyInterface)
def resolve_foo(self, args, info): # def resolve_foo(self, args, info):
return args.get("bar") # return args.get("bar")
typemap = TypeMap([MyInterface]) # typemap = TypeMap([MyInterface])
assert "MyInterface" in typemap # assert "MyInterface" in typemap
graphql_type = typemap["MyInterface"] # graphql_type = typemap["MyInterface"]
assert isinstance(graphql_type, GraphQLInterfaceType) # assert isinstance(graphql_type, GraphQLInterfaceType)
assert graphql_type.name == "MyInterface" # assert graphql_type.name == "MyInterface"
assert graphql_type.description == "Description" # assert graphql_type.description == "Description"
fields = graphql_type.fields # fields = graphql_type.fields
assert list(fields.keys()) == ["foo", "gizmo", "own"] # assert list(fields.keys()) == ["foo", "gizmo", "own"]
assert fields["own"].type == graphql_type # assert fields["own"].type == graphql_type
assert list(fields["gizmo"].args.keys()) == ["firstArg", "oth_arg"] # assert list(fields["gizmo"].args.keys()) == ["firstArg", "oth_arg"]
foo_field = fields["foo"] # foo_field = fields["foo"]
assert isinstance(foo_field, GraphQLField) # assert isinstance(foo_field, GraphQLField)
assert foo_field.description == "Field description" # assert foo_field.description == "Field description"
assert not foo_field.resolver # Resolver not attached in interfaces # assert not foo_field.resolver # Resolver not attached in interfaces
assert foo_field.args == { # assert foo_field.args == {
"bar": GraphQLArgument( # "bar": GraphQLArgument(
GraphQLString, # GraphQLString,
description="Argument description", # description="Argument description",
default_value="x", # default_value="x",
out_name="bar", # out_name="bar",
) # )
} # }
def test_inputobject(): # def test_inputobject():
class OtherObjectType(InputObjectType): # class OtherObjectType(InputObjectType):
thingy = NonNull(Int) # thingy = NonNull(Int)
class MyInnerObjectType(InputObjectType): # class MyInnerObjectType(InputObjectType):
some_field = String() # some_field = String()
some_other_field = List(OtherObjectType) # some_other_field = List(OtherObjectType)
class MyInputObjectType(InputObjectType): # class MyInputObjectType(InputObjectType):
"""Description""" # """Description"""
foo_bar = String(description="Field description") # foo_bar = String(description="Field description")
bar = String(name="gizmo") # bar = String(name="gizmo")
baz = NonNull(MyInnerObjectType) # baz = NonNull(MyInnerObjectType)
own = InputField(lambda: MyInputObjectType) # own = InputField(lambda: MyInputObjectType)
def resolve_foo_bar(self, args, info): # def resolve_foo_bar(self, args, info):
return args.get("bar") # return args.get("bar")
typemap = TypeMap([MyInputObjectType]) # typemap = TypeMap([MyInputObjectType])
assert "MyInputObjectType" in typemap # assert "MyInputObjectType" in typemap
graphql_type = typemap["MyInputObjectType"] # graphql_type = typemap["MyInputObjectType"]
assert isinstance(graphql_type, GraphQLInputObjectType) # assert isinstance(graphql_type, GraphQLInputObjectType)
assert graphql_type.name == "MyInputObjectType" # assert graphql_type.name == "MyInputObjectType"
assert graphql_type.description == "Description" # assert graphql_type.description == "Description"
other_graphql_type = typemap["OtherObjectType"] # other_graphql_type = typemap["OtherObjectType"]
inner_graphql_type = typemap["MyInnerObjectType"] # inner_graphql_type = typemap["MyInnerObjectType"]
container = graphql_type.create_container( # container = graphql_type.create_container(
{ # {
"bar": "oh!", # "bar": "oh!",
"baz": inner_graphql_type.create_container( # "baz": inner_graphql_type.create_container(
{ # {
"some_other_field": [ # "some_other_field": [
other_graphql_type.create_container({"thingy": 1}), # other_graphql_type.create_container({"thingy": 1}),
other_graphql_type.create_container({"thingy": 2}), # other_graphql_type.create_container({"thingy": 2}),
] # ]
} # }
), # ),
} # }
) # )
assert isinstance(container, MyInputObjectType) # assert isinstance(container, MyInputObjectType)
assert "bar" in container # assert "bar" in container
assert container.bar == "oh!" # assert container.bar == "oh!"
assert "foo_bar" not in container # assert "foo_bar" not in container
assert container.foo_bar is None # assert container.foo_bar is None
assert container.baz.some_field is None # assert container.baz.some_field is None
assert container.baz.some_other_field[0].thingy == 1 # assert container.baz.some_other_field[0].thingy == 1
assert container.baz.some_other_field[1].thingy == 2 # assert container.baz.some_other_field[1].thingy == 2
fields = graphql_type.fields # fields = graphql_type.fields
assert list(fields.keys()) == ["fooBar", "gizmo", "baz", "own"] # assert list(fields.keys()) == ["fooBar", "gizmo", "baz", "own"]
own_field = fields["own"] # own_field = fields["own"]
assert own_field.type == graphql_type # assert own_field.type == graphql_type
foo_field = fields["fooBar"] # foo_field = fields["fooBar"]
assert isinstance(foo_field, GraphQLInputObjectField) # assert isinstance(foo_field, GraphQLInputObjectField)
assert foo_field.description == "Field description" # assert foo_field.description == "Field description"
def test_objecttype_camelcase(): # def test_objecttype_camelcase():
class MyObjectType(ObjectType): # class MyObjectType(ObjectType):
"""Description""" # """Description"""
foo_bar = String(bar_foo=String()) # foo_bar = String(bar_foo=String())
typemap = TypeMap([MyObjectType]) # typemap = TypeMap([MyObjectType])
assert "MyObjectType" in typemap # assert "MyObjectType" in typemap
graphql_type = typemap["MyObjectType"] # graphql_type = typemap["MyObjectType"]
assert isinstance(graphql_type, GraphQLObjectType) # assert isinstance(graphql_type, GraphQLObjectType)
assert graphql_type.name == "MyObjectType" # assert graphql_type.name == "MyObjectType"
assert graphql_type.description == "Description" # assert graphql_type.description == "Description"
fields = graphql_type.fields # fields = graphql_type.fields
assert list(fields.keys()) == ["fooBar"] # assert list(fields.keys()) == ["fooBar"]
foo_field = fields["fooBar"] # foo_field = fields["fooBar"]
assert isinstance(foo_field, GraphQLField) # assert isinstance(foo_field, GraphQLField)
assert foo_field.args == { # assert foo_field.args == {
"barFoo": GraphQLArgument(GraphQLString, out_name="bar_foo") # "barFoo": GraphQLArgument(GraphQLString, out_name="bar_foo")
} # }
def test_objecttype_camelcase_disabled(): # def test_objecttype_camelcase_disabled():
class MyObjectType(ObjectType): # class MyObjectType(ObjectType):
"""Description""" # """Description"""
foo_bar = String(bar_foo=String()) # foo_bar = String(bar_foo=String())
typemap = TypeMap([MyObjectType], auto_camelcase=False) # typemap = TypeMap([MyObjectType], auto_camelcase=False)
assert "MyObjectType" in typemap # assert "MyObjectType" in typemap
graphql_type = typemap["MyObjectType"] # graphql_type = typemap["MyObjectType"]
assert isinstance(graphql_type, GraphQLObjectType) # assert isinstance(graphql_type, GraphQLObjectType)
assert graphql_type.name == "MyObjectType" # assert graphql_type.name == "MyObjectType"
assert graphql_type.description == "Description" # assert graphql_type.description == "Description"
fields = graphql_type.fields # fields = graphql_type.fields
assert list(fields.keys()) == ["foo_bar"] # assert list(fields.keys()) == ["foo_bar"]
foo_field = fields["foo_bar"] # foo_field = fields["foo_bar"]
assert isinstance(foo_field, GraphQLField) # assert isinstance(foo_field, GraphQLField)
assert foo_field.args == { # assert foo_field.args == {
"bar_foo": GraphQLArgument(GraphQLString, out_name="bar_foo") # "bar_foo": GraphQLArgument(GraphQLString, out_name="bar_foo")
} # }
def test_objecttype_with_possible_types(): # def test_objecttype_with_possible_types():
class MyObjectType(ObjectType): # class MyObjectType(ObjectType):
"""Description""" # """Description"""
class Meta: # class Meta:
possible_types = (dict,) # possible_types = (dict,)
foo_bar = String() # foo_bar = String()
typemap = TypeMap([MyObjectType]) # typemap = TypeMap([MyObjectType])
graphql_type = typemap["MyObjectType"] # graphql_type = typemap["MyObjectType"]
assert graphql_type.is_type_of # assert graphql_type.is_type_of
assert graphql_type.is_type_of({}, None) is True # assert graphql_type.is_type_of({}, None) is True
assert graphql_type.is_type_of(MyObjectType(), None) is False # assert graphql_type.is_type_of(MyObjectType(), None) is False
def test_resolve_type_with_missing_type(): # def test_resolve_type_with_missing_type():
class MyObjectType(ObjectType): # class MyObjectType(ObjectType):
foo_bar = String() # foo_bar = String()
class MyOtherObjectType(ObjectType): # class MyOtherObjectType(ObjectType):
fizz_buzz = String() # fizz_buzz = String()
def resolve_type_func(root, info): # def resolve_type_func(root, info):
return MyOtherObjectType # return MyOtherObjectType
typemap = TypeMap([MyObjectType]) # typemap = TypeMap([MyObjectType])
with pytest.raises(AssertionError) as excinfo: # with pytest.raises(AssertionError) as excinfo:
resolve_type(resolve_type_func, typemap, "MyOtherObjectType", {}, {}) # resolve_type(resolve_type_func, typemap, "MyOtherObjectType", {}, {})
assert "MyOtherObjectTyp" in str(excinfo.value) # assert "MyOtherObjectTyp" in str(excinfo.value)

View File

@ -9,7 +9,6 @@ class Query(ObjectType):
def resolve_uuid(self, info, input): def resolve_uuid(self, info, input):
return input return input
schema = Schema(query=Query) schema = Schema(query=Query)

View File

@ -8,15 +8,14 @@ from graphql import (
GraphQLField, GraphQLField,
GraphQLFloat, GraphQLFloat,
GraphQLID, GraphQLID,
GraphQLInputObjectField, GraphQLInputField,
GraphQLInt, GraphQLInt,
GraphQLList, GraphQLList,
GraphQLNonNull, GraphQLNonNull,
GraphQLString, GraphQLString,
) )
from graphql.execution.executor import get_default_resolve_type_fn from graphql.execution.execute import default_type_resolver
from graphql.type import GraphQLEnumValue from graphql.type import GraphQLEnumValue
from graphql.type.typemap import GraphQLTypeMap
from ..utils.get_unbound_function import get_unbound_function from ..utils.get_unbound_function import get_unbound_function
from ..utils.str_converters import to_camel_case from ..utils.str_converters import to_camel_case
@ -56,7 +55,7 @@ def resolve_type(resolve_type_func, map, type_name, root, info):
if not _type: if not _type:
return_type = map[type_name] return_type = map[type_name]
return get_default_resolve_type_fn(root, info, return_type) return default_type_resolver(root, info, return_type)
if inspect.isclass(_type) and issubclass(_type, ObjectType): if inspect.isclass(_type) and issubclass(_type, ObjectType):
graphql_type = map.get(_type._meta.name) graphql_type = map.get(_type._meta.name)
@ -73,265 +72,266 @@ def is_type_of_from_possible_types(possible_types, root, info):
return isinstance(root, possible_types) return isinstance(root, possible_types)
class TypeMap(GraphQLTypeMap): # class TypeMap(object):
def __init__(self, types, auto_camelcase=True, schema=None): # def __init__(self, types, auto_camelcase=True, schema=None):
self.auto_camelcase = auto_camelcase # self.auto_camelcase = auto_camelcase
self.schema = schema # self.schema = schema
super(TypeMap, self).__init__(types) # types = [t for t in types if t]
# super(TypeMap, self).__init__(types)
def reducer(self, map, type): # def reducer(self, map, type):
if not type: # if not type:
return map # return map
if inspect.isfunction(type): # if inspect.isfunction(type):
type = type() # type = type()
if is_graphene_type(type): # if is_graphene_type(type):
return self.graphene_reducer(map, type) # return self.graphene_reducer(map, type)
return GraphQLTypeMap.reducer(map, type) # return GraphQLSchema.reducer(map, type)
def graphene_reducer(self, map, type): # def graphene_reducer(self, map, type):
if isinstance(type, (List, NonNull)): # if isinstance(type, (List, NonNull)):
return self.reducer(map, type.of_type) # return self.reducer(map, type.of_type)
if type._meta.name in map: # if type._meta.name in map:
_type = map[type._meta.name] # _type = map[type._meta.name]
if isinstance(_type, GrapheneGraphQLType): # if isinstance(_type, GrapheneGraphQLType):
assert _type.graphene_type == type, ( # assert _type.graphene_type == type, (
"Found different types with the same name in the schema: {}, {}." # "Found different types with the same name in the schema: {}, {}."
).format(_type.graphene_type, type) # ).format(_type.graphene_type, type)
return map # return map
if issubclass(type, ObjectType): # if issubclass(type, ObjectType):
internal_type = self.construct_objecttype(map, type) # internal_type = self.construct_objecttype(map, type)
elif issubclass(type, InputObjectType): # elif issubclass(type, InputObjectType):
internal_type = self.construct_inputobjecttype(map, type) # internal_type = self.construct_inputobjecttype(map, type)
elif issubclass(type, Interface): # elif issubclass(type, Interface):
internal_type = self.construct_interface(map, type) # internal_type = self.construct_interface(map, type)
elif issubclass(type, Scalar): # elif issubclass(type, Scalar):
internal_type = self.construct_scalar(map, type) # internal_type = self.construct_scalar(map, type)
elif issubclass(type, Enum): # elif issubclass(type, Enum):
internal_type = self.construct_enum(map, type) # internal_type = self.construct_enum(map, type)
elif issubclass(type, Union): # elif issubclass(type, Union):
internal_type = self.construct_union(map, type) # internal_type = self.construct_union(map, type)
else: # else:
raise Exception("Expected Graphene type, but received: {}.".format(type)) # raise Exception("Expected Graphene type, but received: {}.".format(type))
return GraphQLTypeMap.reducer(map, internal_type) # return GraphQLSchema.reducer(map, internal_type)
def construct_scalar(self, map, type): # def construct_scalar(self, map, type):
# We have a mapping to the original GraphQL types # # We have a mapping to the original GraphQL types
# so there are no collisions. # # so there are no collisions.
_scalars = { # _scalars = {
String: GraphQLString, # String: GraphQLString,
Int: GraphQLInt, # Int: GraphQLInt,
Float: GraphQLFloat, # Float: GraphQLFloat,
Boolean: GraphQLBoolean, # Boolean: GraphQLBoolean,
ID: GraphQLID, # ID: GraphQLID,
} # }
if type in _scalars: # if type in _scalars:
return _scalars[type] # return _scalars[type]
return GrapheneScalarType( # return GrapheneScalarType(
graphene_type=type, # graphene_type=type,
name=type._meta.name, # name=type._meta.name,
description=type._meta.description, # description=type._meta.description,
serialize=getattr(type, "serialize", None), # serialize=getattr(type, "serialize", None),
parse_value=getattr(type, "parse_value", None), # parse_value=getattr(type, "parse_value", None),
parse_literal=getattr(type, "parse_literal", None), # parse_literal=getattr(type, "parse_literal", None),
) # )
def construct_enum(self, map, type): # def construct_enum(self, map, type):
values = OrderedDict() # values = OrderedDict()
for name, value in type._meta.enum.__members__.items(): # for name, value in type._meta.enum.__members__.items():
description = getattr(value, "description", None) # description = getattr(value, "description", None)
deprecation_reason = getattr(value, "deprecation_reason", None) # deprecation_reason = getattr(value, "deprecation_reason", None)
if not description and callable(type._meta.description): # if not description and callable(type._meta.description):
description = type._meta.description(value) # description = type._meta.description(value)
if not deprecation_reason and callable(type._meta.deprecation_reason): # if not deprecation_reason and callable(type._meta.deprecation_reason):
deprecation_reason = type._meta.deprecation_reason(value) # deprecation_reason = type._meta.deprecation_reason(value)
values[name] = GraphQLEnumValue( # values[name] = GraphQLEnumValue(
name=name, # name=name,
value=value.value, # value=value.value,
description=description, # description=description,
deprecation_reason=deprecation_reason, # deprecation_reason=deprecation_reason,
) # )
type_description = ( # type_description = (
type._meta.description(None) # type._meta.description(None)
if callable(type._meta.description) # if callable(type._meta.description)
else type._meta.description # else type._meta.description
) # )
return GrapheneEnumType( # return GrapheneEnumType(
graphene_type=type, # graphene_type=type,
values=values, # values=values,
name=type._meta.name, # name=type._meta.name,
description=type_description, # description=type_description,
) # )
def construct_objecttype(self, map, type): # def construct_objecttype(self, map, type):
if type._meta.name in map: # if type._meta.name in map:
_type = map[type._meta.name] # _type = map[type._meta.name]
if isinstance(_type, GrapheneGraphQLType): # if isinstance(_type, GrapheneGraphQLType):
assert _type.graphene_type == type, ( # assert _type.graphene_type == type, (
"Found different types with the same name in the schema: {}, {}." # "Found different types with the same name in the schema: {}, {}."
).format(_type.graphene_type, type) # ).format(_type.graphene_type, type)
return _type # return _type
def interfaces(): # def interfaces():
interfaces = [] # interfaces = []
for interface in type._meta.interfaces: # for interface in type._meta.interfaces:
self.graphene_reducer(map, interface) # self.graphene_reducer(map, interface)
internal_type = map[interface._meta.name] # internal_type = map[interface._meta.name]
assert internal_type.graphene_type == interface # assert internal_type.graphene_type == interface
interfaces.append(internal_type) # interfaces.append(internal_type)
return interfaces # return interfaces
if type._meta.possible_types: # if type._meta.possible_types:
is_type_of = partial( # is_type_of = partial(
is_type_of_from_possible_types, type._meta.possible_types # is_type_of_from_possible_types, type._meta.possible_types
) # )
else: # else:
is_type_of = type.is_type_of # is_type_of = type.is_type_of
return GrapheneObjectType( # return GrapheneObjectType(
graphene_type=type, # graphene_type=type,
name=type._meta.name, # name=type._meta.name,
description=type._meta.description, # description=type._meta.description,
fields=partial(self.construct_fields_for_type, map, type), # fields=partial(self.construct_fields_for_type, map, type),
is_type_of=is_type_of, # is_type_of=is_type_of,
interfaces=interfaces, # interfaces=interfaces,
) # )
def construct_interface(self, map, type): # def construct_interface(self, map, type):
if type._meta.name in map: # if type._meta.name in map:
_type = map[type._meta.name] # _type = map[type._meta.name]
if isinstance(_type, GrapheneInterfaceType): # if isinstance(_type, GrapheneInterfaceType):
assert _type.graphene_type == type, ( # assert _type.graphene_type == type, (
"Found different types with the same name in the schema: {}, {}." # "Found different types with the same name in the schema: {}, {}."
).format(_type.graphene_type, type) # ).format(_type.graphene_type, type)
return _type # return _type
_resolve_type = None # _resolve_type = None
if type.resolve_type: # if type.resolve_type:
_resolve_type = partial( # _resolve_type = partial(
resolve_type, type.resolve_type, map, type._meta.name # resolve_type, type.resolve_type, map, type._meta.name
) # )
return GrapheneInterfaceType( # return GrapheneInterfaceType(
graphene_type=type, # graphene_type=type,
name=type._meta.name, # name=type._meta.name,
description=type._meta.description, # description=type._meta.description,
fields=partial(self.construct_fields_for_type, map, type), # fields=partial(self.construct_fields_for_type, map, type),
resolve_type=_resolve_type, # resolve_type=_resolve_type,
) # )
def construct_inputobjecttype(self, map, type): # def construct_inputobjecttype(self, map, type):
return GrapheneInputObjectType( # return GrapheneInputObjectType(
graphene_type=type, # graphene_type=type,
name=type._meta.name, # name=type._meta.name,
description=type._meta.description, # description=type._meta.description,
container_type=type._meta.container, # container_type=type._meta.container,
fields=partial( # fields=partial(
self.construct_fields_for_type, map, type, is_input_type=True # self.construct_fields_for_type, map, type, is_input_type=True
), # ),
) # )
def construct_union(self, map, type): # def construct_union(self, map, type):
_resolve_type = None # _resolve_type = None
if type.resolve_type: # if type.resolve_type:
_resolve_type = partial( # _resolve_type = partial(
resolve_type, type.resolve_type, map, type._meta.name # resolve_type, type.resolve_type, map, type._meta.name
) # )
def types(): # def types():
union_types = [] # union_types = []
for objecttype in type._meta.types: # for objecttype in type._meta.types:
self.graphene_reducer(map, objecttype) # self.graphene_reducer(map, objecttype)
internal_type = map[objecttype._meta.name] # internal_type = map[objecttype._meta.name]
assert internal_type.graphene_type == objecttype # assert internal_type.graphene_type == objecttype
union_types.append(internal_type) # union_types.append(internal_type)
return union_types # return union_types
return GrapheneUnionType( # return GrapheneUnionType(
graphene_type=type, # graphene_type=type,
name=type._meta.name, # name=type._meta.name,
description=type._meta.description, # description=type._meta.description,
types=types, # types=types,
resolve_type=_resolve_type, # resolve_type=_resolve_type,
) # )
def get_name(self, name): # def get_name(self, name):
if self.auto_camelcase: # if self.auto_camelcase:
return to_camel_case(name) # return to_camel_case(name)
return name # return name
def construct_fields_for_type(self, map, type, is_input_type=False): # def construct_fields_for_type(self, map, type, is_input_type=False):
fields = OrderedDict() # fields = OrderedDict()
for name, field in type._meta.fields.items(): # for name, field in type._meta.fields.items():
if isinstance(field, Dynamic): # if isinstance(field, Dynamic):
field = get_field_as(field.get_type(self.schema), _as=Field) # field = get_field_as(field.get_type(self.schema), _as=Field)
if not field: # if not field:
continue # continue
map = self.reducer(map, field.type) # map = self.reducer(map, field.type)
field_type = self.get_field_type(map, field.type) # field_type = self.get_field_type(map, field.type)
if is_input_type: # if is_input_type:
_field = GraphQLInputObjectField( # _field = GraphQLInputField(
field_type, # field_type,
default_value=field.default_value, # default_value=field.default_value,
out_name=name, # out_name=name,
description=field.description, # description=field.description,
) # )
else: # else:
args = OrderedDict() # args = OrderedDict()
for arg_name, arg in field.args.items(): # for arg_name, arg in field.args.items():
map = self.reducer(map, arg.type) # map = self.reducer(map, arg.type)
arg_type = self.get_field_type(map, arg.type) # arg_type = self.get_field_type(map, arg.type)
processed_arg_name = arg.name or self.get_name(arg_name) # processed_arg_name = arg.name or self.get_name(arg_name)
args[processed_arg_name] = GraphQLArgument( # args[processed_arg_name] = GraphQLArgument(
arg_type, # arg_type,
out_name=arg_name, # out_name=arg_name,
description=arg.description, # description=arg.description,
default_value=arg.default_value, # default_value=arg.default_value,
) # )
_field = GraphQLField( # _field = GraphQLField(
field_type, # field_type,
args=args, # args=args,
resolver=field.get_resolver( # resolver=field.get_resolver(
self.get_resolver_for_type(type, name, field.default_value) # self.get_resolver_for_type(type, name, field.default_value)
), # ),
deprecation_reason=field.deprecation_reason, # deprecation_reason=field.deprecation_reason,
description=field.description, # description=field.description,
) # )
field_name = field.name or self.get_name(name) # field_name = field.name or self.get_name(name)
fields[field_name] = _field # fields[field_name] = _field
return fields # return fields
def get_resolver_for_type(self, type, name, default_value): # def get_resolver_for_type(self, type, name, default_value):
if not issubclass(type, ObjectType): # if not issubclass(type, ObjectType):
return # return
resolver = getattr(type, "resolve_{}".format(name), None) # resolver = getattr(type, "resolve_{}".format(name), None)
if not resolver: # if not resolver:
# If we don't find the resolver in the ObjectType class, then try to # # If we don't find the resolver in the ObjectType class, then try to
# find it in each of the interfaces # # find it in each of the interfaces
interface_resolver = None # interface_resolver = None
for interface in type._meta.interfaces: # for interface in type._meta.interfaces:
if name not in interface._meta.fields: # if name not in interface._meta.fields:
continue # continue
interface_resolver = getattr(interface, "resolve_{}".format(name), None) # interface_resolver = getattr(interface, "resolve_{}".format(name), None)
if interface_resolver: # if interface_resolver:
break # break
resolver = interface_resolver # resolver = interface_resolver
# Only if is not decorated with classmethod # # Only if is not decorated with classmethod
if resolver: # if resolver:
return get_unbound_function(resolver) # return get_unbound_function(resolver)
default_resolver = type._meta.default_resolver or get_default_resolver() # default_resolver = type._meta.default_resolver or get_default_resolver()
return partial(default_resolver, name, default_value) # return partial(default_resolver, name, default_value)
def get_field_type(self, map, type): # def get_field_type(self, map, type):
if isinstance(type, List): # if isinstance(type, List):
return GraphQLList(self.get_field_type(map, type.of_type)) # return GraphQLList(self.get_field_type(map, type.of_type))
if isinstance(type, NonNull): # if isinstance(type, NonNull):
return GraphQLNonNull(self.get_field_type(map, type.of_type)) # return GraphQLNonNull(self.get_field_type(map, type.of_type))
return map.get(type._meta.name) # return map.get(type._meta.name)

View File

@ -0,0 +1,7 @@
from .helpers import base64, unbase64, is_str
__all__ = [
"base64",
"unbase64",
"is_str"
]

13
graphene/utils/helpers.py Normal file
View File

@ -0,0 +1,13 @@
from base64 import b64encode as _base64, b64decode as _unbase64
def base64(s):
return _base64(s.encode('utf-8')).decode('utf-8')
def unbase64(s):
return _unbase64(s).decode('utf-8')
def is_str(s):
return isinstance(s, str)

View File

@ -73,8 +73,6 @@ setup(
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"Intended Audience :: Developers", "Intended Audience :: Developers",
"Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.4",
@ -86,8 +84,7 @@ setup(
packages=find_packages(exclude=["tests", "tests.*", "examples"]), packages=find_packages(exclude=["tests", "tests.*", "examples"]),
install_requires=[ install_requires=[
"six>=1.10.0,<2", "six>=1.10.0,<2",
"graphql-core>=2.1,<3", "graphql-core-next==1.0.3",
"graphql-relay>=0.4.5,<1",
"aniso8601>=3,<4", "aniso8601>=3,<4",
], ],
tests_require=tests_require, tests_require=tests_require,

View File

@ -1,5 +1,5 @@
[tox] [tox]
envlist = flake8,py27,py34,py35,py36,py37,pre-commit,pypy,mypy envlist = flake8,py34,py35,py36,py37,pre-commit,pypy,mypy
skipsdist = true skipsdist = true
[testenv] [testenv]
@ -9,7 +9,7 @@ deps =
setenv = setenv =
PYTHONPATH = .:{envdir} PYTHONPATH = .:{envdir}
commands = commands =
py{27,34,py}: py.test --cov=graphene graphene examples {posargs} py{34,py}: py.test --cov=graphene graphene examples {posargs}
py{35,36,37}: py.test --cov=graphene graphene examples tests_asyncio {posargs} py{35,36,37}: py.test --cov=graphene graphene examples tests_asyncio {posargs}
[testenv:pre-commit] [testenv:pre-commit]