Repository: graphql-python/graphene-mongo (language: python)

Issue:
Is there a way to filter results?
Do you have a way to filter queries? I understand that the graphene-django project relied on django-filter for query filtering. Is there something similar already implemented in this project?

I am trying to perform the following query:

```
query {
    allUsers(name: "foo"){
        edges{
            node{
                id,
                name
            }
        }
    }
}
```


Discussion / hints:
@git-albertomarin : I am still working on it, and hope it can be resolved soon.
@git-albertomarin 

Now you can refer https://github.com/abawchen/graphene-mongo/blob/master/graphene_mongo/tests/test_query.py#L296 for the basic filtering, and I do not implement other filter usage but only `=` comparison at this moment.

Feel free to feedback or submit other issues.


Fix patch:
diff --git a/README.md b/README.md
index d99c2d31..126a3bf8 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ query = '''
         }
     }
 '''
-result = schema.execute(query)
+result = await schema.execute_async(query)
 ```
 
 To learn more check out the following [examples](examples/):
diff --git a/README.rst b/README.rst
index 993b28e1..0decfbee 100644
--- a/README.rst
+++ b/README.rst
@@ -71,7 +71,7 @@ Then you can simply query the schema:
             }
         }
     '''
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
 To learn more check out the `Flask MongoEngine example <https://github.com/graphql-python/graphene-mongo/tree/master/examples/flask_mongoengine>`__
 
diff --git a/examples/falcon_mongoengine/api.py b/examples/falcon_mongoengine/api.py
index b140cdfb..59f3781a 100644
--- a/examples/falcon_mongoengine/api.py
+++ b/examples/falcon_mongoengine/api.py
@@ -23,7 +23,7 @@ def on_post(self, req, resp):
 class GraphQLResource:
     def on_get(self, req, resp):
         query = req.params["query"]
-        result = schema.execute(query)
+        result = await schema.execute_async(query)
 
         if result.data:
             data_ret = {"data": result.data}
@@ -32,7 +32,7 @@ def on_get(self, req, resp):
 
     def on_post(self, req, resp):
         query = req.params["query"]
-        result = schema.execute(query)
+        result = await schema.execute_async(query)
         if result.data:
             data_ret = {"data": result.data}
             resp.status = falcon.HTTP_200
diff --git a/graphene_mongo/converter.py b/graphene_mongo/converter.py
index 5cba247c..d9a56245 100644
--- a/graphene_mongo/converter.py
+++ b/graphene_mongo/converter.py
@@ -9,6 +9,7 @@
 from . import advanced_types
 from .utils import import_single_dispatch, get_field_description, get_query_fields
 from concurrent.futures import ThreadPoolExecutor, as_completed
+from asgiref.sync import sync_to_async
 
 singledispatch = import_single_dispatch()
 
@@ -42,6 +43,14 @@ def convert_field_to_id(field, registry=None):
     )
 
 
+@convert_mongoengine_field.register(mongoengine.Decimal128Field)
+@convert_mongoengine_field.register(mongoengine.DecimalField)
+def convert_field_to_decimal(field, registry=None):
+    return graphene.Decimal(
+        description=get_field_description(field, registry), required=field.required
+    )
+
+
 @convert_mongoengine_field.register(mongoengine.IntField)
 @convert_mongoengine_field.register(mongoengine.LongField)
 @convert_mongoengine_field.register(mongoengine.SequenceField)
@@ -58,7 +67,6 @@ def convert_field_to_boolean(field, registry=None):
     )
 
 
-@convert_mongoengine_field.register(mongoengine.DecimalField)
 @convert_mongoengine_field.register(mongoengine.FloatField)
 def convert_field_to_float(field, registry=None):
     return graphene.Float(
@@ -66,13 +74,6 @@ def convert_field_to_float(field, registry=None):
     )
 
 
-@convert_mongoengine_field.register(mongoengine.Decimal128Field)
-def convert_field_to_decimal(field, registry=None):
-    return graphene.Decimal(
-        description=get_field_description(field, registry), required=field.required
-    )
-
-
 @convert_mongoengine_field.register(mongoengine.DateTimeField)
 def convert_field_to_datetime(field, registry=None):
     return graphene.DateTime(
@@ -246,7 +247,7 @@ def convert_field_to_union(field, registry=None):
     Meta = type("Meta", (object,), {"types": tuple(_types)})
     _union = type(name, (graphene.Union,), {"Meta": Meta})
 
-    def reference_resolver(root, *args, **kwargs):
+    async def reference_resolver(root, *args, **kwargs):
         de_referenced = getattr(root, field.name or field.db_name)
         if de_referenced:
             document = get_document(de_referenced["_cls"])
@@ -265,13 +266,14 @@ def reference_resolver(root, *args, **kwargs):
                     item = to_snake_case(each)
                     if item in document._fields_ordered + tuple(filter_args):
                         queried_fields.append(item)
-                return document.objects().no_dereference().only(*list(
-                    set(list(_type._meta.required_fields) + queried_fields))).get(
-                    pk=de_referenced["_ref"].id)
-            return document()
+                return await sync_to_async(document.objects().no_dereference().only(*list(
+                    set(list(_type._meta.required_fields) + queried_fields))).get, thread_sensitive=False,
+                                           executor=ThreadPoolExecutor())(pk=de_referenced["_ref"].id)
+            return await sync_to_async(document, thread_sensitive=False,
+                                       executor=ThreadPoolExecutor())()
         return None
 
-    def lazy_reference_resolver(root, *args, **kwargs):
+    async def lazy_reference_resolver(root, *args, **kwargs):
         document = getattr(root, field.name or field.db_name)
         if document:
             queried_fields = list()
@@ -288,10 +290,11 @@ def lazy_reference_resolver(root, *args, **kwargs):
                     if item in document.document_type._fields_ordered + tuple(filter_args):
                         queried_fields.append(item)
                 _type = registry.get_type_for_model(document.document_type)
-                return document.document_type.objects().no_dereference().only(
-                    *(set((list(_type._meta.required_fields) + queried_fields)))).get(
-                    pk=document.pk)
-            return document.document_type()
+                return await sync_to_async(document.document_type.objects().no_dereference().only(
+                    *(set((list(_type._meta.required_fields) + queried_fields)))).get, thread_sensitive=False,
+                                           executor=ThreadPoolExecutor())(pk=document.pk)
+            return await sync_to_async(document.document_type, thread_sensitive=False,
+                                       executor=ThreadPoolExecutor())()
         return None
 
     if isinstance(field, mongoengine.GenericLazyReferenceField):
@@ -327,7 +330,7 @@ def lazy_reference_resolver(root, *args, **kwargs):
 def convert_field_to_dynamic(field, registry=None):
     model = field.document_type
 
-    def reference_resolver(root, *args, **kwargs):
+    async def reference_resolver(root, *args, **kwargs):
         document = getattr(root, field.name or field.db_name)
         if document:
             queried_fields = list()
@@ -341,12 +344,12 @@ def reference_resolver(root, *args, **kwargs):
                 item = to_snake_case(each)
                 if item in field.document_type._fields_ordered + tuple(filter_args):
                     queried_fields.append(item)
-            return field.document_type.objects().no_dereference().only(
-                *(set(list(_type._meta.required_fields) + queried_fields))).get(
-                pk=document.id)
+            return await sync_to_async(field.document_type.objects().no_dereference().only(
+                *(set(list(_type._meta.required_fields) + queried_fields))).get, thread_sensitive=False,
+                                       executor=ThreadPoolExecutor())(pk=document.id)
         return None
 
-    def cached_reference_resolver(root, *args, **kwargs):
+    async def cached_reference_resolver(root, *args, **kwargs):
         if field:
             queried_fields = list()
             _type = registry.get_type_for_model(field.document_type)
@@ -359,9 +362,10 @@ def cached_reference_resolver(root, *args, **kwargs):
                 item = to_snake_case(each)
                 if item in field.document_type._fields_ordered + tuple(filter_args):
                     queried_fields.append(item)
-            return field.document_type.objects().no_dereference().only(
+            return await sync_to_async(field.document_type.objects().no_dereference().only(
                 *(set(
-                    list(_type._meta.required_fields) + queried_fields))).get(
+                    list(_type._meta.required_fields) + queried_fields))).get, thread_sensitive=False,
+                                       executor=ThreadPoolExecutor())(
                 pk=getattr(root, field.name or field.db_name))
         return None
 
@@ -394,7 +398,7 @@ def dynamic_type():
 def convert_lazy_field_to_dynamic(field, registry=None):
     model = field.document_type
 
-    def lazy_resolver(root, *args, **kwargs):
+    async def lazy_resolver(root, *args, **kwargs):
         document = getattr(root, field.name or field.db_name)
         if document:
             queried_fields = list()
@@ -408,9 +412,9 @@ def lazy_resolver(root, *args, **kwargs):
                 item = to_snake_case(each)
                 if item in document.document_type._fields_ordered + tuple(filter_args):
                     queried_fields.append(item)
-            return document.document_type.objects().no_dereference().only(
-                *(set((list(_type._meta.required_fields) + queried_fields)))).get(
-                pk=document.pk)
+            return await sync_to_async(document.document_type.objects().no_dereference().only(
+                *(set((list(_type._meta.required_fields) + queried_fields)))).get, thread_sensitive=False,
+                                       executor=ThreadPoolExecutor())(pk=document.pk)
         return None
 
     def dynamic_type():
diff --git a/graphene_mongo/fields.py b/graphene_mongo/fields.py
index 53942c5f..3778fa72 100644
--- a/graphene_mongo/fields.py
+++ b/graphene_mongo/fields.py
@@ -1,6 +1,5 @@
 from __future__ import absolute_import
 
-import logging
 from collections import OrderedDict
 from functools import partial, reduce
 
@@ -22,6 +21,8 @@
 from mongoengine.base import get_document
 from promise import Promise
 from pymongo.errors import OperationFailure
+from asgiref.sync import sync_to_async
+from concurrent.futures import ThreadPoolExecutor
 
 from .advanced_types import (
     FileFieldType,
@@ -314,7 +315,7 @@ def get_queryset(self, model, info, required_fields=None, skip=None, limit=None,
                     skip)
         return model.objects(**args).no_dereference().only(*required_fields).order_by(self.order_by)
 
-    def default_resolver(self, _root, info, required_fields=None, resolved=None, **args):
+    async def default_resolver(self, _root, info, required_fields=None, resolved=None, **args):
         if required_fields is None:
             required_fields = list()
         args = args or {}
@@ -357,7 +358,8 @@ def default_resolver(self, _root, info, required_fields=None, resolved=None, **a
 
             if isinstance(items, QuerySet):
                 try:
-                    count = items.count(with_limit_and_skip=True)
+                    count = await sync_to_async(items.count, thread_sensitive=False,
+                                                executor=ThreadPoolExecutor())(with_limit_and_skip=True)
                 except OperationFailure:
                     count = len(items)
             else:
@@ -400,12 +402,13 @@ def default_resolver(self, _root, info, required_fields=None, resolved=None, **a
                             args_copy[key] = args_copy[key].value
 
                 if PYMONGO_VERSION >= (3, 7):
-                    if hasattr(self.model, '_meta') and 'db_alias' in self.model._meta:
-                        count = (mongoengine.get_db(self.model._meta['db_alias'])[self.model._get_collection_name()]).count_documents(args_copy)
-                    else:
-                        count = (mongoengine.get_db()[self.model._get_collection_name()]).count_documents(args_copy)
+                    count = await sync_to_async(
+                        (mongoengine.get_db()[self.model._get_collection_name()]).count_documents,
+                        thread_sensitive=False,
+                        executor=ThreadPoolExecutor())(args_copy)
                 else:
-                    count = self.model.objects(args_copy).count()
+                    count = await sync_to_async(self.model.objects(args_copy).count, thread_sensitive=False,
+                                                executor=ThreadPoolExecutor())()
                 if count != 0:
                     skip, limit, reverse = find_skip_and_limit(first=first, after=after, last=last, before=before,
                                                                count=count)
@@ -467,7 +470,7 @@ def default_resolver(self, _root, info, required_fields=None, resolved=None, **a
         connection.list_length = list_length
         return connection
 
-    def chained_resolver(self, resolver, is_partial, root, info, **args):
+    async def chained_resolver(self, resolver, is_partial, root, info, **args):
 
         for key, value in dict(args).items():
             if value is None:
@@ -511,13 +514,13 @@ def chained_resolver(self, resolver, is_partial, root, info, **args):
                     elif not isinstance(resolved[0], DBRef):
                         return resolved
                     else:
-                        return self.default_resolver(root, info, required_fields, **args_copy)
+                        return await self.default_resolver(root, info, required_fields, **args_copy)
                 elif isinstance(resolved, QuerySet):
                     args.update(resolved._query)
                     args_copy = args.copy()
                     for arg_name, arg in args.copy().items():
-                        if "." in arg_name or arg_name not in self.model._fields_ordered \
-                                + ('first', 'last', 'before', 'after') + tuple(self.filter_args.keys()):
+                        if "." in arg_name or arg_name not in self.model._fields_ordered + (
+                                'first', 'last', 'before', 'after') + tuple(self.filter_args.keys()):
                             args_copy.pop(arg_name)
                             if arg_name == '_id' and isinstance(arg, dict):
                                 operation = list(arg.keys())[0]
@@ -537,38 +540,35 @@ def chained_resolver(self, resolver, is_partial, root, info, **args):
                                 operation = list(arg.keys())[0]
                                 args_copy[arg_name + operation.replace('$', '__')] = arg[operation]
                                 del args_copy[arg_name]
-                    return self.default_resolver(root, info, required_fields, resolved=resolved, **args_copy)
+
+                    return await self.default_resolver(root, info, required_fields, resolved=resolved, **args_copy)
                 elif isinstance(resolved, Promise):
                     return resolved.value
                 else:
-                    return resolved
+                    return await resolved
 
-        return self.default_resolver(root, info, required_fields, **args)
+        return await self.default_resolver(root, info, required_fields, **args)
 
     @classmethod
-    def connection_resolver(cls, resolver, connection_type, root, info, **args):
+    async def connection_resolver(cls, resolver, connection_type, root, info, **args):
         if root:
             for key, value in root.__dict__.items():
                 if value:
                     try:
                         setattr(root, key, from_global_id(value)[1])
-                    except Exception as error:
-                        logging.error("Exception Occurred: ", exc_info=error)
-        iterable = resolver(root, info, **args)
-
+                    except Exception:
+                        pass
+        iterable = await resolver(root, info, **args)
         if isinstance(connection_type, graphene.NonNull):
             connection_type = connection_type.of_type
 
-        on_resolve = partial(cls.resolve_connection, connection_type, args)
-
-        if Promise.is_thenable(iterable):
-            return Promise.resolve(iterable).then(on_resolve)
-
-        return on_resolve(iterable)
+        return await sync_to_async(cls.resolve_connection, thread_sensitive=False,
+                                   executor=ThreadPoolExecutor())(connection_type, args, iterable)
 
     def get_resolver(self, parent_resolver):
         super_resolver = self.resolver or parent_resolver
         resolver = partial(
             self.chained_resolver, super_resolver, isinstance(super_resolver, partial)
         )
+
         return partial(self.connection_resolver, resolver, self.type)
diff --git a/poetry.lock b/poetry.lock
index 11159ccb..58da7e7a 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
 
 [[package]]
 name = "aniso8601"
@@ -15,6 +15,24 @@ files = [
 [package.extras]
 dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"]
 
+[[package]]
+name = "asgiref"
+version = "3.6.0"
+description = "ASGI specs, helper code, and adapters"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "asgiref-3.6.0-py3-none-any.whl", hash = "sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac"},
+    {file = "asgiref-3.6.0.tar.gz", hash = "sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506"},
+]
+
+[package.dependencies]
+typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
+
+[package.extras]
+tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
+
 [[package]]
 name = "attrs"
 version = "22.2.0"
@@ -34,199 +52,6 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-
 tests = ["attrs[tests-no-zope]", "zope.interface"]
 tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
 
-[[package]]
-name = "bleach"
-version = "6.0.0"
-description = "An easy safelist-based HTML-sanitizing tool."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"},
-    {file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"},
-]
-
-[package.dependencies]
-six = ">=1.9.0"
-webencodings = "*"
-
-[package.extras]
-css = ["tinycss2 (>=1.1.0,<1.2)"]
-
-[[package]]
-name = "certifi"
-version = "2022.12.7"
-description = "Python package for providing Mozilla's CA Bundle."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
-    {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
-]
-
-[[package]]
-name = "cffi"
-version = "1.15.1"
-description = "Foreign Function Interface for Python calling C code."
-category = "dev"
-optional = false
-python-versions = "*"
-files = [
-    {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
-    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
-    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
-    {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
-    {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
-    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
-    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
-    {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
-    {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
-    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
-    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
-    {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
-    {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
-    {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
-    {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
-    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
-    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
-    {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
-    {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
-    {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
-    {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
-    {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
-    {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
-    {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
-    {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
-    {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
-    {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
-    {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
-    {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
-    {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
-    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
-    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
-    {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
-    {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
-    {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
-]
-
-[package.dependencies]
-pycparser = "*"
-
-[[package]]
-name = "charset-normalizer"
-version = "3.1.0"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "dev"
-optional = false
-python-versions = ">=3.7.0"
-files = [
-    {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"},
-    {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"},
-    {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"},
-    {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"},
-    {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"},
-    {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"},
-    {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"},
-]
-
 [[package]]
 name = "colorama"
 version = "0.4.6"
@@ -306,48 +131,6 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1
 [package.extras]
 toml = ["tomli"]
 
-[[package]]
-name = "cryptography"
-version = "40.0.1"
-description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "cryptography-40.0.1-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:918cb89086c7d98b1b86b9fdb70c712e5a9325ba6f7d7cfb509e784e0cfc6917"},
-    {file = "cryptography-40.0.1-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9618a87212cb5200500e304e43691111570e1f10ec3f35569fdfcd17e28fd797"},
-    {file = "cryptography-40.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a4805a4ca729d65570a1b7cac84eac1e431085d40387b7d3bbaa47e39890b88"},
-    {file = "cryptography-40.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63dac2d25c47f12a7b8aa60e528bfb3c51c5a6c5a9f7c86987909c6c79765554"},
-    {file = "cryptography-40.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0a4e3406cfed6b1f6d6e87ed243363652b2586b2d917b0609ca4f97072994405"},
-    {file = "cryptography-40.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1e0af458515d5e4028aad75f3bb3fe7a31e46ad920648cd59b64d3da842e4356"},
-    {file = "cryptography-40.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d8aa3609d337ad85e4eb9bb0f8bcf6e4409bfb86e706efa9a027912169e89122"},
-    {file = "cryptography-40.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cf91e428c51ef692b82ce786583e214f58392399cf65c341bc7301d096fa3ba2"},
-    {file = "cryptography-40.0.1-cp36-abi3-win32.whl", hash = "sha256:650883cc064297ef3676b1db1b7b1df6081794c4ada96fa457253c4cc40f97db"},
-    {file = "cryptography-40.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:a805a7bce4a77d51696410005b3e85ae2839bad9aa38894afc0aa99d8e0c3160"},
-    {file = "cryptography-40.0.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd033d74067d8928ef00a6b1327c8ea0452523967ca4463666eeba65ca350d4c"},
-    {file = "cryptography-40.0.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d36bbeb99704aabefdca5aee4eba04455d7a27ceabd16f3b3ba9bdcc31da86c4"},
-    {file = "cryptography-40.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:32057d3d0ab7d4453778367ca43e99ddb711770477c4f072a51b3ca69602780a"},
-    {file = "cryptography-40.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f5d7b79fa56bc29580faafc2ff736ce05ba31feaa9d4735048b0de7d9ceb2b94"},
-    {file = "cryptography-40.0.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7c872413353c70e0263a9368c4993710070e70ab3e5318d85510cc91cce77e7c"},
-    {file = "cryptography-40.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:28d63d75bf7ae4045b10de5413fb1d6338616e79015999ad9cf6fc538f772d41"},
-    {file = "cryptography-40.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6f2bbd72f717ce33100e6467572abaedc61f1acb87b8d546001328d7f466b778"},
-    {file = "cryptography-40.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cc3a621076d824d75ab1e1e530e66e7e8564e357dd723f2533225d40fe35c60c"},
-    {file = "cryptography-40.0.1.tar.gz", hash = "sha256:2803f2f8b1e95f614419926c7e6f55d828afc614ca5ed61543877ae668cc3472"},
-]
-
-[package.dependencies]
-cffi = ">=1.12"
-
-[package.extras]
-docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
-docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"]
-pep8test = ["black", "check-manifest", "mypy", "ruff"]
-sdist = ["setuptools-rust (>=0.11.4)"]
-ssh = ["bcrypt (>=3.1.5)"]
-test = ["iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist"]
-test-randomorder = ["pytest-randomly"]
-tox = ["tox"]
-
 [[package]]
 name = "dnspython"
 version = "2.3.0"
@@ -369,18 +152,6 @@ idna = ["idna (>=2.1,<4.0)"]
 trio = ["trio (>=0.14,<0.23)"]
 wmi = ["wmi (>=1.5.1,<2.0.0)"]
 
-[[package]]
-name = "docutils"
-version = "0.19"
-description = "Docutils -- Python Documentation Utilities"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"},
-    {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"},
-]
-
 [[package]]
 name = "exceptiongroup"
 version = "1.1.1"
@@ -466,18 +237,6 @@ files = [
 graphql-core = ">=3.2,<3.3"
 typing-extensions = {version = ">=4.1,<5", markers = "python_version < \"3.8\""}
 
-[[package]]
-name = "idna"
-version = "3.4"
-description = "Internationalized Domain Names in Applications (IDNA)"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-files = [
-    {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
-    {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
-]
-
 [[package]]
 name = "importlib-metadata"
 version = "6.1.0"
@@ -499,25 +258,6 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker
 perf = ["ipython"]
 testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
 
-[[package]]
-name = "importlib-resources"
-version = "5.12.0"
-description = "Read resources from Python packages"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"},
-    {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"},
-]
-
-[package.dependencies]
-zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
-testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
-
 [[package]]
 name = "iniconfig"
 version = "2.0.0"
@@ -542,92 +282,6 @@ files = [
     {file = "iso8601-1.1.0.tar.gz", hash = "sha256:32811e7b81deee2063ea6d2e94f8819a86d1f3811e49d23623a41fa832bef03f"},
 ]
 
-[[package]]
-name = "jaraco-classes"
-version = "3.2.3"
-description = "Utility functions for Python class constructs"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "jaraco.classes-3.2.3-py3-none-any.whl", hash = "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158"},
-    {file = "jaraco.classes-3.2.3.tar.gz", hash = "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a"},
-]
-
-[package.dependencies]
-more-itertools = "*"
-
-[package.extras]
-docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
-
-[[package]]
-name = "jeepney"
-version = "0.8.0"
-description = "Low-level, pure Python DBus protocol wrapper."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"},
-    {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"},
-]
-
-[package.extras]
-test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"]
-trio = ["async_generator", "trio"]
-
-[[package]]
-name = "keyring"
-version = "23.13.1"
-description = "Store and access your passwords safely."
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "keyring-23.13.1-py3-none-any.whl", hash = "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd"},
-    {file = "keyring-23.13.1.tar.gz", hash = "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678"},
-]
-
-[package.dependencies]
-importlib-metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""}
-importlib-resources = {version = "*", markers = "python_version < \"3.9\""}
-"jaraco.classes" = "*"
-jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""}
-pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""}
-SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""}
-
-[package.extras]
-completion = ["shtab"]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
-
-[[package]]
-name = "markdown-it-py"
-version = "2.2.0"
-description = "Python port of markdown-it. Markdown parsing, done right!"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"},
-    {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"},
-]
-
-[package.dependencies]
-mdurl = ">=0.1,<1.0"
-typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
-
-[package.extras]
-benchmarking = ["psutil", "pytest", "pytest-benchmark"]
-code-style = ["pre-commit (>=3.0,<4.0)"]
-compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
-linkify = ["linkify-it-py (>=1,<3)"]
-plugins = ["mdit-py-plugins"]
-profiling = ["gprof2dot"]
-rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
-testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
-
 [[package]]
 name = "mccabe"
 version = "0.6.1"
@@ -640,18 +294,6 @@ files = [
     {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
 ]
 
-[[package]]
-name = "mdurl"
-version = "0.1.2"
-description = "Markdown URL utilities"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
-    {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
-]
-
 [[package]]
 name = "mock"
 version = "5.0.1"
@@ -700,18 +342,6 @@ files = [
 packaging = "*"
 sentinels = "*"
 
-[[package]]
-name = "more-itertools"
-version = "9.1.0"
-description = "More routines for operating on iterables, beyond itertools"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "more-itertools-9.1.0.tar.gz", hash = "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d"},
-    {file = "more_itertools-9.1.0-py3-none-any.whl", hash = "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"},
-]
-
 [[package]]
 name = "packaging"
 version = "23.0"
@@ -724,21 +354,6 @@ files = [
     {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
 ]
 
-[[package]]
-name = "pkginfo"
-version = "1.9.6"
-description = "Query metadata from sdists / bdists / installed packages."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "pkginfo-1.9.6-py3-none-any.whl", hash = "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546"},
-    {file = "pkginfo-1.9.6.tar.gz", hash = "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"},
-]
-
-[package.extras]
-testing = ["pytest", "pytest-cov"]
-
 [[package]]
 name = "pluggy"
 version = "1.0.0"
@@ -787,18 +402,6 @@ files = [
     {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
 ]
 
-[[package]]
-name = "pycparser"
-version = "2.21"
-description = "C parser in Python"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
-    {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
-]
-
 [[package]]
 name = "pyflakes"
 version = "2.3.1"
@@ -811,21 +414,6 @@ files = [
     {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
 ]
 
-[[package]]
-name = "pygments"
-version = "2.14.0"
-description = "Pygments is a syntax highlighting package written in Python."
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
-    {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"},
-]
-
-[package.extras]
-plugins = ["importlib-metadata"]
-
 [[package]]
 name = "pymongo"
 version = "4.3.3"
@@ -965,126 +553,6 @@ pytest = ">=4.6"
 [package.extras]
 testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
 
-[[package]]
-name = "pywin32-ctypes"
-version = "0.2.0"
-description = ""
-category = "dev"
-optional = false
-python-versions = "*"
-files = [
-    {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
-    {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"},
-]
-
-[[package]]
-name = "readme-renderer"
-version = "37.3"
-description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "readme_renderer-37.3-py3-none-any.whl", hash = "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343"},
-    {file = "readme_renderer-37.3.tar.gz", hash = "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273"},
-]
-
-[package.dependencies]
-bleach = ">=2.1.0"
-docutils = ">=0.13.1"
-Pygments = ">=2.5.1"
-
-[package.extras]
-md = ["cmarkgfm (>=0.8.0)"]
-
-[[package]]
-name = "requests"
-version = "2.28.2"
-description = "Python HTTP for Humans."
-category = "dev"
-optional = false
-python-versions = ">=3.7, <4"
-files = [
-    {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
-    {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
-]
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<4"
-idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<1.27"
-
-[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
-
-[[package]]
-name = "requests-toolbelt"
-version = "0.10.1"
-description = "A utility belt for advanced users of python-requests"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "requests-toolbelt-0.10.1.tar.gz", hash = "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d"},
-    {file = "requests_toolbelt-0.10.1-py2.py3-none-any.whl", hash = "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7"},
-]
-
-[package.dependencies]
-requests = ">=2.0.1,<3.0.0"
-
-[[package]]
-name = "rfc3986"
-version = "2.0.0"
-description = "Validating URI References per RFC 3986"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"},
-    {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"},
-]
-
-[package.extras]
-idna2008 = ["idna"]
-
-[[package]]
-name = "rich"
-version = "13.3.3"
-description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
-category = "dev"
-optional = false
-python-versions = ">=3.7.0"
-files = [
-    {file = "rich-13.3.3-py3-none-any.whl", hash = "sha256:540c7d6d26a1178e8e8b37e9ba44573a3cd1464ff6348b99ee7061b95d1c6333"},
-    {file = "rich-13.3.3.tar.gz", hash = "sha256:dc84400a9d842b3a9c5ff74addd8eb798d155f36c1c91303888e0a66850d2a15"},
-]
-
-[package.dependencies]
-markdown-it-py = ">=2.2.0,<3.0.0"
-pygments = ">=2.13.0,<3.0.0"
-typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
-
-[package.extras]
-jupyter = ["ipywidgets (>=7.5.1,<9)"]
-
-[[package]]
-name = "secretstorage"
-version = "3.3.3"
-description = "Python bindings to FreeDesktop.org Secret Service API"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"},
-    {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"},
-]
-
-[package.dependencies]
-cryptography = ">=2.0"
-jeepney = ">=0.6"
-
 [[package]]
 name = "sentinels"
 version = "1.0.0"
@@ -1136,29 +604,6 @@ files = [
     {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
 ]
 
-[[package]]
-name = "twine"
-version = "4.0.2"
-description = "Collection of utilities for publishing packages on PyPI"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "twine-4.0.2-py3-none-any.whl", hash = "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8"},
-    {file = "twine-4.0.2.tar.gz", hash = "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8"},
-]
-
-[package.dependencies]
-importlib-metadata = ">=3.6"
-keyring = ">=15.1"
-pkginfo = ">=1.8.1"
-readme-renderer = ">=35.0"
-requests = ">=2.20"
-requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0"
-rfc3986 = ">=1.4.0"
-rich = ">=12.0.0"
-urllib3 = ">=1.26.0"
-
 [[package]]
 name = "typing-extensions"
 version = "4.5.0"
@@ -1171,35 +616,6 @@ files = [
     {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
 ]
 
-[[package]]
-name = "urllib3"
-version = "1.26.15"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
-files = [
-    {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"},
-    {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"},
-]
-
-[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
-secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
-socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
-
-[[package]]
-name = "webencodings"
-version = "0.5.1"
-description = "Character encoding aliases for legacy web content"
-category = "dev"
-optional = false
-python-versions = "*"
-files = [
-    {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
-    {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
-]
-
 [[package]]
 name = "zipp"
 version = "3.15.0"
@@ -1219,4 +635,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
 [metadata]
 lock-version = "2.0"
 python-versions = ">=3.7,<4"
-content-hash = "9d08c8286b859bd7381e3ef0660cb6563ae081eb1be7f24d187153d2631d33ab"
+content-hash = "51ad1be0be6ab1c6aff81bbedfa5bf8e986a1bd5e8e6471234d2adcc002bc30a"
diff --git a/pyproject.toml b/pyproject.toml
index 8c925d6d..1c208d3c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
 [tool.poetry]
 name = "graphene-mongo"
 packages = [{ include = "graphene_mongo" }]
-version = "0.3.0"
+version = "0.4.0"
 description = "Graphene Mongoengine integration"
 authors = [
     "Abaw Chen <abaw.chen@gmail.com>",
@@ -33,6 +33,7 @@ promise = ">=2.3"
 mongoengine = ">=0.27"
 singledispatch = ">=3.7.0"
 iso8601 = "*"
+asgiref = "^3.6.0"
 
 [tool.poetry.group.dev.dependencies]
 pytest = "*"


Test patch:
diff --git a/graphene_mongo/tests/test_converter.py b/graphene_mongo/tests/test_converter.py
index df572aef..7109bb8f 100644
--- a/graphene_mongo/tests/test_converter.py
+++ b/graphene_mongo/tests/test_converter.py
@@ -70,8 +70,8 @@ def test_should_boolean_convert_boolean():
     assert_conversion(mongoengine.BooleanField, graphene.Boolean)
 
 
-def test_should_decimal_convert_float():
-    assert_conversion(mongoengine.DecimalField, graphene.Float)
+def test_should_decimal_convert_decimal():
+    assert_conversion(mongoengine.DecimalField, graphene.Decimal)
 
 
 def test_should_float_convert_float():
diff --git a/graphene_mongo/tests/test_fields.py b/graphene_mongo/tests/test_fields.py
index 7dec7323..50792bfe 100644
--- a/graphene_mongo/tests/test_fields.py
+++ b/graphene_mongo/tests/test_fields.py
@@ -44,16 +44,16 @@ def test_field_args_with_unconverted_field():
     assert set(field.field_args.keys()) == set(field_args)
 
 
-def test_default_resolver_with_colliding_objects_field():
+async def test_default_resolver_with_colliding_objects_field():
     field = MongoengineConnectionField(nodes.ErroneousModelNode)
 
-    connection = field.default_resolver(None, {})
+    connection = await field.default_resolver(None, {})
     assert 0 == len(connection.iterable)
 
 
-def test_default_resolver_connection_list_length(fixtures):
+async def test_default_resolver_connection_list_length(fixtures):
     field = MongoengineConnectionField(nodes.ArticleNode)
 
-    connection = field.default_resolver(None, {}, **{"first": 1})
+    connection = await field.default_resolver(None, {}, **{"first": 1})
     assert hasattr(connection, "list_length")
     assert connection.list_length == 1
diff --git a/graphene_mongo/tests/test_inputs.py b/graphene_mongo/tests/test_inputs.py
index c5d3ff0b..93655e60 100644
--- a/graphene_mongo/tests/test_inputs.py
+++ b/graphene_mongo/tests/test_inputs.py
@@ -7,14 +7,14 @@
 from .types import ArticleInput, EditorInput
 
 
-def test_should_create(fixtures):
+async def test_should_create(fixtures):
     class CreateArticle(graphene.Mutation):
         class Arguments:
             article = ArticleInput(required=True)
 
         article = graphene.Field(ArticleNode)
 
-        def mutate(self, info, article):
+        async def mutate(self, info, article):
             article = Article(**article)
             article.save()
 
@@ -39,12 +39,12 @@ class Mutation(graphene.ObjectType):
     """
     expected = {"createArticle": {"article": {"headline": "My Article"}}}
     schema = graphene.Schema(query=Query, mutation=Mutation)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_update(fixtures):
+async def test_should_update(fixtures):
     class UpdateEditor(graphene.Mutation):
         class Arguments:
             id = graphene.ID(required=True)
@@ -52,7 +52,7 @@ class Arguments:
 
         editor = graphene.Field(EditorNode)
 
-        def mutate(self, info, id, editor):
+        async def mutate(self, info, id, editor):
             editor_to_update = Editor.objects.get(id=id)
             for key, value in editor.items():
                 if value:
@@ -85,7 +85,7 @@ class Mutation(graphene.ObjectType):
     """
     expected = {"updateEditor": {"editor": {"firstName": "Penny", "lastName": "Lane"}}}
     schema = graphene.Schema(query=Query, mutation=Mutation)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     # print(result.data)
     assert not result.errors
     assert result.data == expected
diff --git a/graphene_mongo/tests/test_mutation.py b/graphene_mongo/tests/test_mutation.py
index 78eb5f06..695ea32a 100644
--- a/graphene_mongo/tests/test_mutation.py
+++ b/graphene_mongo/tests/test_mutation.py
@@ -6,7 +6,7 @@
 from .nodes import ArticleNode, EditorNode
 
 
-def test_should_create(fixtures):
+async def test_should_create(fixtures):
     class CreateArticle(graphene.Mutation):
         class Arguments:
 
@@ -14,7 +14,7 @@ class Arguments:
 
         article = graphene.Field(ArticleNode)
 
-        def mutate(self, info, headline):
+        async def mutate(self, info, headline):
             article = Article(headline=headline)
             article.save()
 
@@ -41,12 +41,12 @@ class Mutation(graphene.ObjectType):
     """
     expected = {"createArticle": {"article": {"headline": "My Article"}}}
     schema = graphene.Schema(query=Query, mutation=Mutation)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_update(fixtures):
+async def test_should_update(fixtures):
     class UpdateEditor(graphene.Mutation):
         class Arguments:
             id = graphene.ID()
@@ -54,7 +54,7 @@ class Arguments:
 
         editor = graphene.Field(EditorNode)
 
-        def mutate(self, info, id, first_name):
+        async def mutate(self, info, id, first_name):
             editor = Editor.objects.get(id=id)
             editor.first_name = first_name
             editor.save()
@@ -82,7 +82,7 @@ class Mutation(graphene.ObjectType):
     """
     expected = {"updateEditor": {"editor": {"firstName": "Tony"}}}
     schema = graphene.Schema(query=Query, mutation=Mutation)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     # print(result.data)
     assert not result.errors
     assert result.data == expected
diff --git a/graphene_mongo/tests/test_query.py b/graphene_mongo/tests/test_query.py
index 14663be3..a1facbea 100644
--- a/graphene_mongo/tests/test_query.py
+++ b/graphene_mongo/tests/test_query.py
@@ -7,16 +7,15 @@
 from . import types
 
 
-def test_should_query_editor(fixtures, fixtures_dirname):
+async def test_should_query_editor(fixtures, fixtures_dirname):
     class Query(graphene.ObjectType):
-
         editor = graphene.Field(types.EditorType)
         editors = graphene.List(types.EditorType)
 
-        def resolve_editor(self, *args, **kwargs):
+        async def resolve_editor(self, *args, **kwargs):
             return models.Editor.objects.first()
 
-        def resolve_editors(self, *args, **kwargs):
+        async def resolve_editors(self, *args, **kwargs):
             return list(models.Editor.objects.all())
 
     query = """
@@ -65,18 +64,18 @@ def resolve_editors(self, *args, **kwargs):
     expected_metadata = {"age": "20", "nickname": "$1"}
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     metadata = result.data["editor"].pop("metadata")
     assert json.loads(metadata) == expected_metadata
     assert result.data == expected
 
 
-def test_should_query_reporter(fixtures):
+async def test_should_query_reporter(fixtures):
     class Query(graphene.ObjectType):
         reporter = graphene.Field(types.ReporterType)
 
-        def resolve_reporter(self, *args, **kwargs):
+        async def resolve_reporter(self, *args, **kwargs):
             return models.Reporter.objects.first()
 
     query = """
@@ -111,17 +110,16 @@ def resolve_reporter(self, *args, **kwargs):
     }
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_custom_kwargs(fixtures):
+async def test_should_custom_kwargs(fixtures):
     class Query(graphene.ObjectType):
-
         editors = graphene.List(types.EditorType, first=graphene.Int())
 
-        def resolve_editors(self, *args, **kwargs):
+        async def resolve_editors(self, *args, **kwargs):
             editors = models.Editor.objects()
             if "first" in kwargs:
                 editors = editors[: kwargs["first"]]
@@ -142,17 +140,16 @@ def resolve_editors(self, *args, **kwargs):
         ]
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_self_reference(fixtures):
+async def test_should_self_reference(fixtures):
     class Query(graphene.ObjectType):
-
         all_players = graphene.List(types.PlayerType)
 
-        def resolve_all_players(self, *args, **kwargs):
+        async def resolve_all_players(self, *args, **kwargs):
             return models.Player.objects.all()
 
     query = """
@@ -189,18 +186,18 @@ def resolve_all_players(self, *args, **kwargs):
         ]
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_with_embedded_document(fixtures):
+async def test_should_query_with_embedded_document(fixtures):
     class Query(graphene.ObjectType):
         professor_vector = graphene.Field(
             types.ProfessorVectorType, id=graphene.String()
         )
 
-        def resolve_professor_vector(self, info, id):
+        async def resolve_professor_vector(self, info, id):
             return models.ProfessorVector.objects(metadata__id=id).first()
 
     query = """
@@ -218,17 +215,16 @@ def resolve_professor_vector(self, info, id):
         "professorVector": {"vec": [1.0, 2.3], "metadata": {"firstName": "Steven"}}
     }
     schema = graphene.Schema(query=Query, types=[types.ProfessorVectorType])
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_child(fixtures):
+async def test_should_query_child(fixtures):
     class Query(graphene.ObjectType):
-
         children = graphene.List(types.ChildType)
 
-        def resolve_children(self, *args, **kwargs):
+        async def resolve_children(self, *args, **kwargs):
             return list(models.Child.objects.all())
 
     query = """
@@ -255,17 +251,16 @@ def resolve_children(self, *args, **kwargs):
     }
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_other_childs(fixtures):
+async def test_should_query_other_childs(fixtures):
     class Query(graphene.ObjectType):
-
         children = graphene.List(types.AnotherChildType)
 
-        def resolve_children(self, *args, **kwargs):
+        async def resolve_children(self, *args, **kwargs):
             return list(models.AnotherChild.objects.all())
 
     query = """
@@ -292,16 +287,16 @@ def resolve_children(self, *args, **kwargs):
     }
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_all_childs(fixtures):
+async def test_should_query_all_childs(fixtures):
     class Query(graphene.ObjectType):
         children = graphene.List(types.ChildUnionType)
 
-        def resolve_children(self, *args, **kwargs):
+        async def resolve_children(self, *args, **kwargs):
             return list(models.Parent.objects.all())
 
     query = """
@@ -339,23 +334,22 @@ def resolve_children(self, *args, **kwargs):
             {
                 "bar": "bar",
                 "qux": "qux",
-                "loc": {"type": "Point", "coordinates":  [20, 10]},
+                "loc": {"type": "Point", "coordinates": [20, 10]},
             },
         ]
     }
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_cell_tower(fixtures):
+async def test_should_query_cell_tower(fixtures):
     class Query(graphene.ObjectType):
-
         cell_towers = graphene.List(types.CellTowerType)
 
-        def resolve_cell_towers(self, *args, **kwargs):
+        async def resolve_cell_towers(self, *args, **kwargs):
             return list(models.CellTower.objects.all())
 
     query = """
@@ -410,6 +404,6 @@ def resolve_cell_towers(self, *args, **kwargs):
     }
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
diff --git a/graphene_mongo/tests/test_relay_query.py b/graphene_mongo/tests/test_relay_query.py
index 5e181861..010c2b0f 100644
--- a/graphene_mongo/tests/test_relay_query.py
+++ b/graphene_mongo/tests/test_relay_query.py
@@ -12,11 +12,11 @@
 from ..types import MongoengineObjectType
 
 
-def test_should_query_reporter(fixtures):
+async def test_should_query_reporter(fixtures):
     class Query(graphene.ObjectType):
         reporter = graphene.Field(nodes.ReporterNode)
 
-        def resolve_reporter(self, *args, **kwargs):
+        async def resolve_reporter(self, *args, **kwargs):
             return models.Reporter.objects.no_dereference().first()
 
     query = """
@@ -85,12 +85,12 @@ def resolve_reporter(self, *args, **kwargs):
     }
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_reporters_with_nested_document(fixtures):
+async def test_should_query_reporters_with_nested_document(fixtures):
     class Query(graphene.ObjectType):
         reporters = MongoengineConnectionField(nodes.ReporterNode)
 
@@ -130,12 +130,12 @@ class Query(graphene.ObjectType):
     }
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_all_editors(fixtures, fixtures_dirname):
+async def test_should_query_all_editors(fixtures, fixtures_dirname):
     class Query(graphene.ObjectType):
         editors = MongoengineConnectionField(nodes.EditorNode)
 
@@ -197,17 +197,17 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_editors_with_dataloader(fixtures):
+async def test_should_query_editors_with_dataloader(fixtures):
     from promise import Promise
     from promise.dataloader import DataLoader
 
     class ArticleLoader(DataLoader):
-        def batch_load_fn(self, instances):
+        async def batch_load_fn(self, instances):
             queryset = models.Article.objects(editor__in=instances)
             return Promise.resolve(
                 [
@@ -225,7 +225,7 @@ class Meta:
 
         articles = MongoengineConnectionField(nodes.ArticleNode)
 
-        def resolve_articles(self, *args, **kwargs):
+        async def resolve_articles(self, *args, **kwargs):
             return article_loader.load(self)
 
     class Query(graphene.ObjectType):
@@ -263,12 +263,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter_editors_by_id(fixtures):
+async def test_should_filter_editors_by_id(fixtures):
     class Query(graphene.ObjectType):
         editors = MongoengineConnectionField(nodes.EditorNode)
 
@@ -299,12 +299,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter(fixtures):
+async def test_should_filter(fixtures):
     class Query(graphene.ObjectType):
         articles = MongoengineConnectionField(nodes.ArticleNode)
 
@@ -337,12 +337,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter_by_reference_field(fixtures):
+async def test_should_filter_by_reference_field(fixtures):
     class Query(graphene.ObjectType):
         articles = MongoengineConnectionField(nodes.ArticleNode)
 
@@ -366,12 +366,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter_through_inheritance(fixtures):
+async def test_should_filter_through_inheritance(fixtures):
     class Query(graphene.ObjectType):
         node = Node.Field()
         children = MongoengineConnectionField(nodes.ChildNode)
@@ -406,12 +406,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter_by_list_contains(fixtures):
+async def test_should_filter_by_list_contains(fixtures):
     # Notes: https://goo.gl/hMNRgs
     class Query(graphene.ObjectType):
         reporters = MongoengineConnectionField(nodes.ReporterNode)
@@ -455,12 +455,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter_by_id(fixtures):
+async def test_should_filter_by_id(fixtures):
     # Notes: https://goo.gl/hMNRgs
     class Query(graphene.ObjectType):
         reporter = Node.Field(nodes.ReporterNode)
@@ -482,12 +482,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_first_n(fixtures):
+async def test_should_first_n(fixtures):
     class Query(graphene.ObjectType):
         editors = MongoengineConnectionField(nodes.EditorNode)
 
@@ -524,13 +524,13 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_after(fixtures):
+async def test_should_after(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -556,13 +556,13 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_before(fixtures):
+async def test_should_before(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -590,13 +590,13 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_last_n(fixtures):
+async def test_should_last_n(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -621,13 +621,13 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_self_reference(fixtures):
+async def test_should_self_reference(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -696,12 +696,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_lazy_reference(fixtures):
+async def test_should_lazy_reference(fixtures):
     class Query(graphene.ObjectType):
         node = Node.Field()
         parents = MongoengineConnectionField(nodes.ParentWithRelationshipNode)
@@ -756,12 +756,12 @@ class Query(graphene.ObjectType):
         }
     }
 
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_query_with_embedded_document(fixtures):
+async def test_should_query_with_embedded_document(fixtures):
     class Query(graphene.ObjectType):
         professors = MongoengineConnectionField(nodes.ProfessorVectorNode)
 
@@ -787,12 +787,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_get_queryset_returns_dict_filters(fixtures):
+async def test_should_get_queryset_returns_dict_filters(fixtures):
     class Query(graphene.ObjectType):
         node = Node.Field()
         articles = MongoengineConnectionField(
@@ -828,13 +828,13 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_get_queryset_returns_qs_filters(fixtures):
-    def get_queryset(model, info, **args):
+async def test_should_get_queryset_returns_qs_filters(fixtures):
+    async def get_queryset(model, info, **args):
         return model.objects(headline="World")
 
     class Query(graphene.ObjectType):
@@ -872,12 +872,12 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter_mongoengine_queryset(fixtures):
+async def test_should_filter_mongoengine_queryset(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -901,7 +901,7 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert json.dumps(result.data, sort_keys=True) == json.dumps(
@@ -909,11 +909,11 @@ class Query(graphene.ObjectType):
     )
 
 
-def test_should_query_document_with_embedded(fixtures):
+async def test_should_query_document_with_embedded(fixtures):
     class Query(graphene.ObjectType):
         foos = MongoengineConnectionField(nodes.FooNode)
 
-        def resolve_multiple_foos(self, *args, **kwargs):
+        async def resolve_multiple_foos(self, *args, **kwargs):
             return list(models.Foo.objects.all())
 
     query = """
@@ -935,11 +935,11 @@ def resolve_multiple_foos(self, *args, **kwargs):
     """
 
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
     assert not result.errors
 
 
-def test_should_filter_mongoengine_queryset_with_list(fixtures):
+async def test_should_filter_mongoengine_queryset_with_list(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -963,7 +963,7 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert json.dumps(result.data, sort_keys=True) == json.dumps(
@@ -971,7 +971,7 @@ class Query(graphene.ObjectType):
     )
 
 
-def test_should_get_correct_list_of_documents(fixtures):
+async def test_should_get_correct_list_of_documents(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -1014,13 +1014,13 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert result.data == expected
 
 
-def test_should_filter_mongoengine_queryset_by_id_and_other_fields(fixtures):
+async def test_should_filter_mongoengine_queryset_by_id_and_other_fields(fixtures):
     class Query(graphene.ObjectType):
         players = MongoengineConnectionField(nodes.PlayerNode)
 
@@ -1050,7 +1050,7 @@ class Query(graphene.ObjectType):
         }
     }
     schema = graphene.Schema(query=Query)
-    result = schema.execute(query)
+    result = await schema.execute_async(query)
 
     assert not result.errors
     assert json.dumps(result.data, sort_keys=True) == json.dumps(expected, sort_keys=True)