From 26686da30e6aadbbc7d1e2921d36c79d392ded15 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sun, 23 Jul 2017 15:17:10 -0700 Subject: [PATCH] Added inputobjecttype containers --- graphene/types/inputobjecttype.py | 29 ++++++++++++++++++++++++++-- graphene/types/tests/test_typemap.py | 10 +++++++++- graphene/types/typemap.py | 1 + 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/graphene/types/inputobjecttype.py b/graphene/types/inputobjecttype.py index 5615db3d..19bb7c74 100644 --- a/graphene/types/inputobjecttype.py +++ b/graphene/types/inputobjecttype.py @@ -8,9 +8,10 @@ from .utils import yank_fields_from_attrs class InputObjectTypeOptions(BaseOptions): fields = None # type: Dict[str, Field] + create_container = None # type: Callable -class InputObjectType(UnmountedType, BaseType): +class InputObjectType(dict, UnmountedType, BaseType): ''' Input Object Type Definition @@ -19,9 +20,30 @@ class InputObjectType(UnmountedType, BaseType): Using `NonNull` will ensure that a value must be provided by the query ''' + def __init__(self, *args, **kwargs): + as_container = kwargs.pop('_as_container', False) + if as_container: + # Is inited as container for the input args + self.__init_container__(*args, **kwargs) + else: + # Is inited as UnmountedType, e.g. + # + # class MyObjectType(graphene.ObjectType): + # my_input = MyInputType(required=True) + # + UnmountedType.__init__(self, *args, **kwargs) + + def __init_container__(self, *args, **kwargs): + dict.__init__(self, *args, **kwargs) + for key, value in self.items(): + setattr(self, key, value) + + @classmethod + def create_container(cls, data): + return cls(data, _as_container=True) @classmethod - def __init_subclass_with_meta__(cls, **options): + def __init_subclass_with_meta__(cls, create_container=None, **options): _meta = InputObjectTypeOptions(cls) fields = OrderedDict() @@ -31,6 +53,9 @@ class InputObjectType(UnmountedType, BaseType): ) _meta.fields = fields + if create_container is None: + create_container = cls.create_container + _meta.create_container = create_container super(InputObjectType, cls).__init_subclass_with_meta__(_meta=_meta, **options) @classmethod diff --git a/graphene/types/tests/test_typemap.py b/graphene/types/tests/test_typemap.py index 475d0905..3a0f20dd 100644 --- a/graphene/types/tests/test_typemap.py +++ b/graphene/types/tests/test_typemap.py @@ -135,9 +135,17 @@ def test_inputobject(): assert graphql_type.name == 'MyInputObjectType' assert graphql_type.description == 'Description' + # Container + container = graphql_type.create_container({'bar': 'oh!'}) + assert isinstance(container, MyInputObjectType) + assert 'bar' in container + assert container.bar == 'oh!' + assert 'foo_bar' not in container + fields = graphql_type.fields assert list(fields.keys()) == ['fooBar', 'gizmo', 'own'] - assert fields['own'].type == graphql_type + own_field = fields['own'] + assert own_field.type == graphql_type foo_field = fields['fooBar'] assert isinstance(foo_field, GraphQLInputObjectField) assert foo_field.description == 'Field description' diff --git a/graphene/types/typemap.py b/graphene/types/typemap.py index acc0fbe3..7e0d9ca0 100644 --- a/graphene/types/typemap.py +++ b/graphene/types/typemap.py @@ -195,6 +195,7 @@ class TypeMap(GraphQLTypeMap): graphene_type=type, name=type._meta.name, description=type._meta.description, + container_type=type._meta.create_container, fields=partial( self.construct_fields_for_type, map, type, is_input_type=True), )