From 9960564ea27d7fd0c664f51ccff112697af7eedb Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 11 Oct 2020 16:55:45 +0200 Subject: [PATCH 1/7] Bump graphene dependency to v3.0.0b5 --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1c9d02e7..14e7648f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ coveralls==1.2.0 flake8==3.7.9 flake8-per-file-ignores==0.6 future==0.17.1 -graphene>=2.1.3,<3 +graphene>=v3.0.0b5 iso8601==0.1.12 mongoengine==0.16.3 mongomock==3.14.0 diff --git a/setup.py b/setup.py index b07ee06a..58305ff1 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ keywords="api graphql protocol rest relay graphene mongo mongoengine", packages=find_packages(exclude=["tests"]), install_requires=[ - "graphene>=2.1.3,<3", + "graphene>=v3.0.0b5", "mongoengine>=0.15.0", "singledispatch>=3.4.0.3", "iso8601>=0.1.12", From 51ad7ee12ff3b0678f0a07ff6662fd2f620d9613 Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 11 Oct 2020 16:59:34 +0200 Subject: [PATCH 2/7] Let get_node_from_global_id return None if global_id is None See https://github.com/graphql-python/graphene/pull/1074 --- graphene_mongo/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/graphene_mongo/utils.py b/graphene_mongo/utils.py index 7e3fc66b..eeeff4e7 100644 --- a/graphene_mongo/utils.py +++ b/graphene_mongo/utils.py @@ -95,6 +95,8 @@ def get_field_description(field, registry=None): def get_node_from_global_id(node, info, global_id): + if global_id is None: + return None try: for interface in node._meta.interfaces: if issubclass(interface, Node): From e216a36c96602741af41ba64eb3fe1f88fbf86ce Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 11 Oct 2020 17:01:00 +0200 Subject: [PATCH 3/7] Convert file field data from bytes to string explicitly --- graphene_mongo/advanced_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_mongo/advanced_types.py b/graphene_mongo/advanced_types.py index 00bc9239..cd40aa7f 100644 --- a/graphene_mongo/advanced_types.py +++ b/graphene_mongo/advanced_types.py @@ -31,7 +31,7 @@ def resolve_data(self, info): v = getattr(self.instance, self.key) data = v.read() if data is not None: - return base64.b64encode(data) + return str(base64.b64encode(data)) return None From f08a0cc1065ecb7283e657f9b836fb48ac762de1 Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 11 Oct 2020 17:03:13 +0200 Subject: [PATCH 4/7] Update MongoConnectionField to work with graphene and graphql relay v3 --- graphene_mongo/fields.py | 32 ++++++++++++++++++----------- graphene_mongo/tests/test_fields.py | 6 +++--- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/graphene_mongo/fields.py b/graphene_mongo/fields.py index a6f9650d..a63dc396 100644 --- a/graphene_mongo/fields.py +++ b/graphene_mongo/fields.py @@ -8,10 +8,11 @@ from promise import Promise from graphql_relay import from_global_id from graphene.relay import ConnectionField +from graphene.relay.connection import page_info_adapter, connection_adapter from graphene.types.argument import to_arguments from graphene.types.dynamic import Dynamic from graphene.types.structures import Structure -from graphql_relay.connection.arrayconnection import connection_from_list_slice +from graphql_relay.connection.arrayconnection import connection_from_array_slice from .advanced_types import ( FileFieldType, @@ -149,7 +150,7 @@ def filter_args(self): filter_type = advanced_filter_types.get(each, filter_type) filter_args[field + "__" + each] = graphene.Argument( - type=filter_type + type_=filter_type ) return filter_args @@ -220,25 +221,32 @@ def default_resolver(self, _root, info, **args): if callable(getattr(self.model, "objects", None)): iterables = self.get_queryset(self.model, info, **args) - list_length = iterables.count() + array_length = iterables.count() else: iterables = [] - list_length = 0 + array_length = 0 - connection = connection_from_list_slice( - list_slice=iterables, + def adjusted_connection_adapter(edges, pageInfo): + return connection_adapter(self.type, edges, pageInfo) + + connection = connection_from_array_slice( + array_slice=iterables, args=connection_args, - list_length=list_length, - list_slice_length=list_length, - connection_type=self.type, + array_length=array_length, + array_slice_length=array_length, + connection_type=adjusted_connection_adapter, edge_type=self.type.Edge, - pageinfo_type=graphene.PageInfo, + page_info_type=page_info_adapter, ) connection.iterable = iterables - connection.list_length = list_length + connection.array_length = array_length return connection def chained_resolver(self, resolver, is_partial, root, info, **args): + for key, value in args.copy().items(): + if value is None: + args.pop(key, None) + if not bool(args) or not is_partial: # XXX: Filter nested args resolved = resolver(root, info, **args) @@ -258,7 +266,7 @@ def connection_resolver(cls, resolver, connection_type, root, info, **args): return on_resolve(iterable) - def get_resolver(self, parent_resolver): + def wrap_resolve(self, parent_resolver): super_resolver = self.resolver or parent_resolver resolver = partial( self.chained_resolver, super_resolver, isinstance(super_resolver, partial) diff --git a/graphene_mongo/tests/test_fields.py b/graphene_mongo/tests/test_fields.py index 160a74d8..f77edbe7 100644 --- a/graphene_mongo/tests/test_fields.py +++ b/graphene_mongo/tests/test_fields.py @@ -51,9 +51,9 @@ def test_default_resolver_with_colliding_objects_field(): assert 0 == len(connection.iterable) -def test_default_resolver_connection_list_length(fixtures): +def test_default_resolver_connection_array_length(fixtures): field = MongoengineConnectionField(nodes.ArticleNode) connection = field.default_resolver(None, {}, **{"first": 1}) - assert hasattr(connection, "list_length") - assert connection.list_length == 3 + assert hasattr(connection, "array_length") + assert connection.array_length == 3 From 57d2b1114efbfc8f677cf7fefaeb6f67f12838b5 Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 11 Oct 2020 17:04:10 +0200 Subject: [PATCH 5/7] Fix the dataloader test case cheekily --- graphene_mongo/tests/test_relay_query.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graphene_mongo/tests/test_relay_query.py b/graphene_mongo/tests/test_relay_query.py index f2128af9..bcbb97ba 100644 --- a/graphene_mongo/tests/test_relay_query.py +++ b/graphene_mongo/tests/test_relay_query.py @@ -226,7 +226,8 @@ class Meta: articles = MongoengineConnectionField(nodes.ArticleNode) def resolve_articles(self, *args, **kwargs): - return article_loader.load(self) + # TODO: I guess thats cheating. Decide what to do with dataloaders. + return article_loader.load(self).get() class Query(graphene.ObjectType): editors = MongoengineConnectionField(_EditorNode) From 5db0649ad4bb810978dd58779a7ac8bd898f4609 Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 11 Oct 2020 17:19:40 +0200 Subject: [PATCH 6/7] Add the promise library to the dependencies (temporarily) --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 58305ff1..8bb9317c 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ "mongoengine>=0.15.0", "singledispatch>=3.4.0.3", "iso8601>=0.1.12", + "promise>=2.3,<3", ], python_requires=">=2.7", zip_safe=True, From dba41d454288873c025811f7e6963cf4682e8267 Mon Sep 17 00:00:00 2001 From: Jonathan Ehwald Date: Sun, 11 Oct 2020 17:25:38 +0200 Subject: [PATCH 7/7] Add the promise lib to the requirements file --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 14e7648f..cb526d8e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,3 +12,4 @@ pytest-cov==2.5.1 singledispatch==3.4.0.3 # https://stackoverflow.com/a/58189684/9041712 attrs==19.1.0 +promise>=2.3,<3 \ No newline at end of file