Improved lazy types support in Graphene

This commit also adds support for string types in Field, InputField, List and NonNull, where the string will be import. Usage like: Field("graphene.String")
This commit is contained in:
Syrus Akbary 2017-04-06 22:13:06 -07:00
parent bd0d418986
commit 4b71465922
9 changed files with 106 additions and 7 deletions

View File

@ -6,6 +6,7 @@ from .argument import Argument, to_arguments
from .mountedtype import MountedType from .mountedtype import MountedType
from .structures import NonNull from .structures import NonNull
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
from .utils import get_type
base_type = type base_type = type
@ -60,9 +61,7 @@ class Field(MountedType):
@property @property
def type(self): def type(self):
if inspect.isfunction(self._type) or type(self._type) is partial: return get_type(self._type)
return self._type()
return self._type
def get_resolver(self, parent_resolver): def get_resolver(self, parent_resolver):
return self.resolver or parent_resolver return self.resolver or parent_resolver

View File

@ -1,5 +1,6 @@
from .mountedtype import MountedType from .mountedtype import MountedType
from .structures import NonNull from .structures import NonNull
from .utils import get_type
class InputField(MountedType): class InputField(MountedType):
@ -11,7 +12,11 @@ class InputField(MountedType):
self.name = name self.name = name
if required: if required:
type = NonNull(type) type = NonNull(type)
self.type = type self._type = type
self.deprecation_reason = deprecation_reason self.deprecation_reason = deprecation_reason
self.default_value = default_value self.default_value = default_value
self.description = description self.description = description
@property
def type(self):
return get_type(self._type)

View File

@ -1,4 +1,5 @@
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
from .utils import get_type
class Structure(UnmountedType): class Structure(UnmountedType):
@ -18,7 +19,11 @@ class Structure(UnmountedType):
cls_name, cls_name,
of_type_name, of_type_name,
)) ))
self.of_type = of_type self._of_type = of_type
@property
def of_type(self):
return get_type(self._of_type)
def get_type(self): def get_type(self):
''' '''

View File

@ -1,9 +1,11 @@
import pytest import pytest
from functools import partial
from ..argument import Argument from ..argument import Argument
from ..field import Field from ..field import Field
from ..structures import NonNull from ..structures import NonNull
from ..scalars import String from ..scalars import String
from .utils import MyLazyType
class MyInstance(object): class MyInstance(object):
@ -66,6 +68,17 @@ def test_field_with_lazy_type():
assert field.type == MyType assert field.type == MyType
def test_field_with_lazy_partial_type():
MyType = object()
field = Field(partial(lambda: MyType))
assert field.type == MyType
def test_field_with_string_type():
field = Field("graphene.types.tests.utils.MyLazyType")
assert field.type == MyLazyType
def test_field_not_source_and_resolver(): def test_field_not_source_and_resolver():
MyType = object() MyType = object()
with pytest.raises(Exception) as exc_info: with pytest.raises(Exception) as exc_info:

View File

@ -0,0 +1,30 @@
import pytest
from functools import partial
from ..inputfield import InputField
from ..structures import NonNull
from .utils import MyLazyType
def test_inputfield_required():
MyType = object()
field = InputField(MyType, required=True)
assert isinstance(field.type, NonNull)
assert field.type.of_type == MyType
def test_inputfield_with_lazy_type():
MyType = object()
field = InputField(lambda: MyType)
assert field.type == MyType
def test_inputfield_with_lazy_partial_type():
MyType = object()
field = InputField(partial(lambda: MyType))
assert field.type == MyType
def test_inputfield_with_string_type():
field = InputField("graphene.types.tests.utils.MyLazyType")
assert field.type == MyLazyType

View File

@ -1,7 +1,9 @@
import pytest import pytest
from functools import partial
from ..structures import List, NonNull from ..structures import List, NonNull
from ..scalars import String from ..scalars import String
from .utils import MyLazyType
def test_list(): def test_list():
@ -17,6 +19,23 @@ def test_list_with_unmounted_type():
assert str(exc_info.value) == 'List could not have a mounted String() as inner type. Try with List(String).' assert str(exc_info.value) == 'List could not have a mounted String() as inner type. Try with List(String).'
def test_list_with_lazy_type():
MyType = object()
field = List(lambda: MyType)
assert field.of_type == MyType
def test_list_with_lazy_partial_type():
MyType = object()
field = List(partial(lambda: MyType))
assert field.of_type == MyType
def test_list_with_string_type():
field = List("graphene.types.tests.utils.MyLazyType")
assert field.of_type == MyLazyType
def test_list_inherited_works_list(): def test_list_inherited_works_list():
_list = List(List(String)) _list = List(List(String))
assert isinstance(_list.of_type, List) assert isinstance(_list.of_type, List)
@ -35,6 +54,23 @@ def test_nonnull():
assert str(nonnull) == 'String!' assert str(nonnull) == 'String!'
def test_nonnull_with_lazy_type():
MyType = object()
field = NonNull(lambda: MyType)
assert field.of_type == MyType
def test_nonnull_with_lazy_partial_type():
MyType = object()
field = NonNull(partial(lambda: MyType))
assert field.of_type == MyType
def test_nonnull_with_string_type():
field = NonNull("graphene.types.tests.utils.MyLazyType")
assert field.of_type == MyLazyType
def test_nonnull_inherited_works_list(): def test_nonnull_inherited_works_list():
_list = NonNull(List(String)) _list = NonNull(List(String))
assert isinstance(_list.of_type, List) assert isinstance(_list.of_type, List)

View File

@ -0,0 +1 @@
MyLazyType = object()

View File

@ -283,6 +283,4 @@ class TypeMap(GraphQLTypeMap):
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))
if inspect.isfunction(type):
type = type()
return map.get(type._meta.name) return map.get(type._meta.name)

View File

@ -1,5 +1,9 @@
import inspect
from collections import OrderedDict from collections import OrderedDict
from functools import partial
from six import string_types
from ..utils.module_loading import import_string
from .mountedtype import MountedType from .mountedtype import MountedType
from .unmountedtype import UnmountedType from .unmountedtype import UnmountedType
@ -62,3 +66,11 @@ def yank_fields_from_attrs(attrs, _as=None, delete=True, sort=True):
if sort: if sort:
fields_with_names = sorted(fields_with_names, key=lambda f: f[1]) fields_with_names = sorted(fields_with_names, key=lambda f: f[1])
return OrderedDict(fields_with_names) return OrderedDict(fields_with_names)
def get_type(_type):
if isinstance(_type, string_types):
return import_string(_type)
if inspect.isfunction(_type) or type(_type) is partial:
return _type()
return _type