graphql-python/graphene-mongo

TypeError: 'List' object is not callable

claradaia opened this issue · 5 comments

Hello, guys

I updated graphene-mongo to 0.2.8 in my environment to make use of the new filters (#103), but I cannot for the life of me make it work with the other versions of packages I am using, namely

Flask==1.0.2
Flask-GraphQL==2.0.1
flask-mongoengine==0.9.5
graphene==2.1.3

I've had to pin the packages to certain versions because of this issue with graphene and flask which I am not sure interferes here.

I have tried multiple combinations of versions to these packages, but I either get the "backend" error mentioned in that issue or the following error:

ImportError while loading conftest '/usr/src/code/tests/conftest.py'.
tests/conftest.py:7: in <module>
    from commands.app import app as _app  # pylint: disable=wrong-import-order
commands/app.py:10: in <module>
    from commands.graphql.schema import schema  # pylint: disable=wrong-import-order
commands/graphql/schema.py:39: in <module>
    mutation=Mutation,
/usr/local/lib/python3.7/site-packages/graphene/types/schema.py:62: in __init__
    self.build_typemap()
/usr/local/lib/python3.7/site-packages/graphene/types/schema.py:126: in build_typemap
    initial_types, auto_camelcase=self.auto_camelcase, schema=self
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:80: in __init__
    super(TypeMap, self).__init__(types)
/usr/local/lib/python3.7/site-packages/graphql/type/typemap.py:28: in __init__
    self.update(reduce(self.reducer, types, OrderedDict()))  # type: ignore
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:88: in reducer
    return self.graphene_reducer(map, type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:117: in graphene_reducer
    return GraphQLTypeMap.reducer(map, internal_type)
/usr/local/lib/python3.7/site-packages/graphql/type/typemap.py:106: in reducer
    field_map = type.fields
/usr/local/lib/python3.7/site-packages/graphql/pyutils/cached_property.py:22: in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:226: in fields
    return define_field_map(self, self._fields)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:240: in define_field_map
    field_map = field_map()
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:274: in construct_fields_for_type
    map = self.reducer(map, field.type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:88: in reducer
    return self.graphene_reducer(map, type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:117: in graphene_reducer
    return GraphQLTypeMap.reducer(map, internal_type)
/usr/local/lib/python3.7/site-packages/graphql/type/typemap.py:106: in reducer
    field_map = type.fields
/usr/local/lib/python3.7/site-packages/graphql/pyutils/cached_property.py:22: in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:226: in fields
    return define_field_map(self, self._fields)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:240: in define_field_map
    field_map = field_map()
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:274: in construct_fields_for_type
    map = self.reducer(map, field.type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:88: in reducer
    return self.graphene_reducer(map, type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:93: in graphene_reducer
    return self.reducer(map, type.of_type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:88: in reducer
    return self.graphene_reducer(map, type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:93: in graphene_reducer
    return self.reducer(map, type.of_type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:88: in reducer
    return self.graphene_reducer(map, type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:117: in graphene_reducer
    return GraphQLTypeMap.reducer(map, internal_type)
/usr/local/lib/python3.7/site-packages/graphql/type/typemap.py:106: in reducer
    field_map = type.fields
/usr/local/lib/python3.7/site-packages/graphql/pyutils/cached_property.py:22: in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:226: in fields
    return define_field_map(self, self._fields)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:240: in define_field_map
    field_map = field_map()
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:274: in construct_fields_for_type
    map = self.reducer(map, field.type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:88: in reducer
    return self.graphene_reducer(map, type)
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:117: in graphene_reducer
    return GraphQLTypeMap.reducer(map, internal_type)
/usr/local/lib/python3.7/site-packages/graphql/type/typemap.py:106: in reducer
    field_map = type.fields
/usr/local/lib/python3.7/site-packages/graphql/pyutils/cached_property.py:22: in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:226: in fields
    return define_field_map(self, self._fields)
/usr/local/lib/python3.7/site-packages/graphql/type/definition.py:240: in define_field_map
    field_map = field_map()
/usr/local/lib/python3.7/site-packages/graphene/types/typemap.py:285: in construct_fields_for_type
    for arg_name, arg in field.args.items():
/usr/local/lib/python3.7/site-packages/graphene_mongo/fields.py:62: in args
    dict(dict(self.field_args, **self.reference_args), **self.filter_args)
/usr/local/lib/python3.7/site-packages/graphene_mongo/fields.py:105: in field_args
    return self._field_args(self.fields.items())
/usr/local/lib/python3.7/site-packages/graphene_mongo/fields.py:101: in _field_args
    return {k: get_type(v) for k, v in items if is_filterable(k)}
/usr/local/lib/python3.7/site-packages/graphene_mongo/fields.py:101: in <dictcomp>
    return {k: get_type(v) for k, v in items if is_filterable(k)}
/usr/local/lib/python3.7/site-packages/graphene_mongo/fields.py:98: in get_type
    return v.type.of_type()
E   TypeError: 'List' object is not callable

I tried other versions and the problem seems to have appeared in version 0.2.3 of graphene-mongo (I was using version 0.2.0 and 0.2.1 works as well).

Have you guys seen this before? Do you know what could be the cause of it?

Thank you in advance.

After some trial and error, I narrowed the problem down to the Node created from a Document structure that looks like this:

class Bar(EmbeddedDocument):
    chee = ListField(StringField(), required=True)

class Foo(Document):
    bars = EmbeddedDocumentListField(Bar)

I find that if the list field within the embedded document ("chee") is not required, the error goes away.

I added some models and a test case that reproduces the error to #122.
I'd appreciate if someone could review it. I can also try to resolve the issue if you think it's due.

Did some digging and the issue appears to be actually with graphene.

The Field class applies NonNull to the list type yielded by mongoengine, and the type that comes out has the _of_type attribute == [String] instead of String.

class Field(MountedType):
    [ docstring ]
    def __init__(self, type, [...], required=False, [...]):
        super(Field, self).__init__(_creation_counter=_creation_counter)
        # ... multiple assertions

        # type._of_type == String before this, as expected
        if required:
            type = NonNull(type)
            # type._of_type == [String] now

Will dig some more because it seems weird nobody else encountered this problem.

Upon reflection, I figure it's supposed to be this way because of the NonNull class. Maybe the intended interpretation is that type becomes NonNull, which is of_type [String].

If that is correct, then I believe method MongoengineConnectionField._field_args should address the NonNull List case. I will add that to the PR.

I updated #122 with the correction to MongoengineConnectionField._field_args.get_type.

Renamed the function to get_filter_type for clarity. Used recursion for abstraction, although I am not sure it is necessary.

Closing this because #122 was merged.