Added Field arguments.

This commit is contained in:
Syrus Akbary 2016-08-13 01:50:32 -07:00
parent 70a9de63f9
commit a7b3d193eb
7 changed files with 83 additions and 26 deletions

View File

@ -0,0 +1,33 @@
from collections import OrderedDict
from itertools import chain
from ..utils.orderedtype import OrderedType
class Argument(OrderedType):
def __init__(self, type, default_value=None, description=None, name=None, _creation_counter=None):
super(Argument, self).__init__(_creation_counter=_creation_counter)
self.name = name
self.type = type
self.default_value = default_value
self.description = description
def to_arguments(args, extra_args):
from .unmountedtype import UnmountedType
extra_args = sorted(extra_args.items(), key=lambda f: f[1])
iter_arguments = chain(args.items() + extra_args)
arguments = OrderedDict()
for default_name, arg in iter_arguments:
if isinstance(arg, UnmountedType):
arg = arg.as_argument()
if not isinstance(arg, Argument):
raise ValueError('Unknown argument "{}".'.format(default_name))
arg_name = default_name or arg.name
assert arg_name not in arguments, 'More than one Argument have same name "{}".'.format(arg.name)
arguments[arg_name] = arg
return arguments

View File

@ -1,9 +1,10 @@
import inspect import inspect
from functools import partial from functools import partial
from collections import OrderedDict from collections import OrderedDict, Mapping
from ..utils.orderedtype import OrderedType from ..utils.orderedtype import OrderedType
from .structures import NonNull from .structures import NonNull
from .argument import to_arguments
def source_resolver(source, root, args, context, info): def source_resolver(source, root, args, context, info):
@ -25,7 +26,9 @@ class Field(OrderedType):
if required: if required:
type = NonNull(type) type = NonNull(type)
self._type = type self._type = type
self.args = args or OrderedDict() if args:
assert isinstance(args, Mapping), 'Arguments in a field have to be a mapping, received "{}".'.format(args)
self.args = to_arguments(args or OrderedDict(), extra_args)
# self.args = to_arguments(args, extra_args) # self.args = to_arguments(args, extra_args)
assert not (source and resolver), ('A Field cannot have a source and a ' assert not (source and resolver), ('A Field cannot have a source and a '
'resolver in at the same time.') 'resolver in at the same time.')

View File

@ -2,6 +2,7 @@ import pytest
from ..field import Field from ..field import Field
from ..structures import NonNull from ..structures import NonNull
from ..argument import Argument
class MyInstance(object): class MyInstance(object):
@ -11,7 +12,7 @@ class MyInstance(object):
def test_field_basic(): def test_field_basic():
MyType = object() MyType = object()
args = {} args = {'my arg': Argument(True)}
resolver = lambda: None resolver = lambda: None
deprecation_reason = 'Deprecated now' deprecation_reason = 'Deprecated now'
description = 'My Field' description = 'My Field'
@ -49,7 +50,22 @@ def test_field_not_source_and_resolver():
Field(MyType, source='value', resolver=lambda: None) Field(MyType, source='value', resolver=lambda: None)
assert str(exc_info.value) == 'A Field cannot have a source and a resolver in at the same time.' assert str(exc_info.value) == 'A Field cannot have a source and a resolver in at the same time.'
def test_field_source_func(): def test_field_source_func():
MyType = object() MyType = object()
field = Field(MyType, source='value_func') field = Field(MyType, source='value_func')
assert field.resolver(MyInstance(), {}, None, None) == MyInstance.value_func() assert field.resolver(MyInstance(), {}, None, None) == MyInstance.value_func()
def test_field_source_argument_as_kw():
MyType = object()
field = Field(MyType, b=NonNull(True), c=Argument(None), a=NonNull(False))
assert field.args.keys() == ['b', 'c', 'a']
assert isinstance(field.args['b'], Argument)
assert isinstance(field.args['b'].type, NonNull)
assert field.args['b'].type.of_type is True
assert isinstance(field.args['c'], Argument)
assert field.args['c'].type is None
assert isinstance(field.args['a'], Argument)
assert isinstance(field.args['a'].type, NonNull)
assert field.args['a'].type.of_type is False

View File

@ -54,7 +54,7 @@ def test_ordered_fields_in_interface():
def test_generate_interface_unmountedtype(): def test_generate_interface_unmountedtype():
class MyInterface(Interface): class MyInterface(Interface):
field = MyScalar(MyType) field = MyScalar()
assert 'field' in MyInterface._meta.fields assert 'field' in MyInterface._meta.fields
assert isinstance(MyInterface._meta.fields['field'], Field) assert isinstance(MyInterface._meta.fields['field'], Field)
@ -62,10 +62,10 @@ def test_generate_interface_unmountedtype():
def test_generate_interface_inherit_abstracttype(): def test_generate_interface_inherit_abstracttype():
class MyAbstractType(AbstractType): class MyAbstractType(AbstractType):
field1 = MyScalar(MyType) field1 = MyScalar()
class MyInterface(Interface, MyAbstractType): class MyInterface(Interface, MyAbstractType):
field2 = MyScalar(MyType) field2 = MyScalar()
assert MyInterface._meta.fields.keys() == ['field1', 'field2'] assert MyInterface._meta.fields.keys() == ['field1', 'field2']
assert [type(x) for x in MyInterface._meta.fields.values()] == [Field, Field] assert [type(x) for x in MyInterface._meta.fields.values()] == [Field, Field]
@ -73,10 +73,10 @@ def test_generate_interface_inherit_abstracttype():
def test_generate_interface_inherit_abstracttype_reversed(): def test_generate_interface_inherit_abstracttype_reversed():
class MyAbstractType(AbstractType): class MyAbstractType(AbstractType):
field1 = MyScalar(MyType) field1 = MyScalar()
class MyInterface(MyAbstractType, Interface): class MyInterface(MyAbstractType, Interface):
field2 = MyScalar(MyType) field2 = MyScalar()
assert MyInterface._meta.fields.keys() == ['field1', 'field2'] assert MyInterface._meta.fields.keys() == ['field1', 'field2']
assert [type(x) for x in MyInterface._meta.fields.values()] == [Field, Field] assert [type(x) for x in MyInterface._meta.fields.values()] == [Field, Field]

View File

@ -62,10 +62,10 @@ def test_ordered_fields_in_objecttype():
def test_generate_objecttype_inherit_abstracttype(): def test_generate_objecttype_inherit_abstracttype():
class MyAbstractType(AbstractType): class MyAbstractType(AbstractType):
field1 = MyScalar(MyType) field1 = MyScalar()
class MyObjectType(ObjectType, MyAbstractType): class MyObjectType(ObjectType, MyAbstractType):
field2 = MyScalar(MyType) field2 = MyScalar()
assert MyObjectType._meta.fields.keys() == ['field1', 'field2'] assert MyObjectType._meta.fields.keys() == ['field1', 'field2']
assert [type(x) for x in MyObjectType._meta.fields.values()] == [Field, Field] assert [type(x) for x in MyObjectType._meta.fields.values()] == [Field, Field]
@ -73,10 +73,10 @@ def test_generate_objecttype_inherit_abstracttype():
def test_generate_objecttype_inherit_abstracttype_reversed(): def test_generate_objecttype_inherit_abstracttype_reversed():
class MyAbstractType(AbstractType): class MyAbstractType(AbstractType):
field1 = MyScalar(MyType) field1 = MyScalar()
class MyObjectType(MyAbstractType, ObjectType): class MyObjectType(MyAbstractType, ObjectType):
field2 = MyScalar(MyType) field2 = MyScalar()
assert MyObjectType._meta.fields.keys() == ['field1', 'field2'] assert MyObjectType._meta.fields.keys() == ['field1', 'field2']
assert [type(x) for x in MyObjectType._meta.fields.values()] == [Field, Field] assert [type(x) for x in MyObjectType._meta.fields.values()] == [Field, Field]
@ -84,7 +84,7 @@ def test_generate_objecttype_inherit_abstracttype_reversed():
def test_generate_objecttype_unmountedtype(): def test_generate_objecttype_unmountedtype():
class MyObjectType(ObjectType): class MyObjectType(ObjectType):
field = MyScalar(MyType) field = MyScalar()
assert 'field' in MyObjectType._meta.fields assert 'field' in MyObjectType._meta.fields
assert isinstance(MyObjectType._meta.fields['field'], Field) assert isinstance(MyObjectType._meta.fields['field'], Field)

View File

@ -49,13 +49,14 @@ class UnmountedType(OrderedType):
**self.kwargs **self.kwargs
) )
# def as_argument(self): def as_argument(self):
# ''' '''
# Mount the UnmountedType as Argument Mount the UnmountedType as Argument
# ''' '''
# return Argument( from .argument import Argument
# self.get_type(), return Argument(
# *self.args, self.get_type(),
# _creation_counter=self.creation_counter, *self.args,
# **self.kwargs _creation_counter=self.creation_counter,
# ) **self.kwargs
)

View File

@ -54,9 +54,13 @@ def get_fields_in_type(in_type, attrs):
(attname, value) (attname, value)
) )
elif isinstance(value, UnmountedType): elif isinstance(value, UnmountedType):
fields_with_names.append( try:
(attname, unmounted_field_in_type(attname, value, in_type)) value = unmounted_field_in_type(attname, value, in_type)
) fields_with_names.append(
(attname, value)
)
except Exception as e:
raise Exception('Exception while mounting the field "{}": {}'.format(attname, str(e)))
return OrderedDict(sorted(fields_with_names, key=lambda f: f[1])) return OrderedDict(sorted(fields_with_names, key=lambda f: f[1]))