prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  snake_case_fallback_resolvers not calling obj.get(attr_name)
  **Ariadne version:** 0.13.0
  **Python version:** 3.8.11
  
  Hello. I am using the [databases](https://www.encode.io/databases/) package with an [asyncpg](https://magicstack.github.io/asyncpg/current/) backend to interact with a PostgreSQL database. The objects returned from my queries are of the type `databases.backends.postgres.Record`.  The desired attributes can only can accessed via the get method. However, when I use `snake_case_fallback_resolvers`, Ariadne has trouble resolving the requested fields and I receive the following error: `Cannot return null for non-nullable field`
  
  If I instead use the regular `fallback_resolvers` (adjusting my schema's naming conventions), Ariadne is able to resolve the requested fields.
  
  Is this a bug or am I doing something wrong? Thank you for your time.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `ariadne/utils.py`
  Content:
  ```
  1 import asyncio
  2 from functools import wraps
  3 from typing import Optional, Union, Callable, Dict, Any
  4 
  5 from graphql import GraphQLError, parse
  6 
  7 
  8 def convert_camel_case_to_snake(graphql_name: str) -> str:
  9     # pylint: disable=too-many-boolean-expressions
  10     max_index = len(graphql_name) - 1
  11     lowered_name = graphql_name.lower()
  12 
  13     python_name = ""
  14     for i, c in enumerate(lowered_name):
  15         if i > 0 and (
  16             # testWord -> test_word
  17             (
  18                 c != graphql_name[i]
  19                 and graphql_name[i - 1] != "_"
  20                 and graphql_name[i - 1] == python_name[-1]
  21             )
  22             # TESTWord -> test_word
  23             or (
  24                 i < max_index
  25                 and graphql_name[i] != lowered_name[i]
  26                 and graphql_name[i + 1] == lowered_name[i + 1]
  27             )
  28             # test134 -> test_134
  29             or (c.isdigit() and not graphql_name[i - 1].isdigit())
  30             # 134test -> 134_test
  31             or (not c.isdigit() and graphql_name[i - 1].isdigit())
  32         ):
  33             python_name += "_"
  34         python_name += c
  35     return python_name
  36 
  37 
  38 def gql(value: str) -> str:
  39     parse(value)
  40     return value
  41 
  42 
  43 def unwrap_graphql_error(
  44     error: Union[GraphQLError, Optional[Exception]]
  45 ) -> Optional[Exception]:
  46     if isinstance(error, GraphQLError):
  47         return unwrap_graphql_error(error.original_error)
  48     return error
  49 
  50 
  51 def convert_kwargs_to_snake_case(func: Callable) -> Callable:
  52     def convert_to_snake_case(d: Dict) -> Dict:
  53         converted: Dict = {}
  54         for k, v in d.items():
  55             if isinstance(v, dict):
  56                 v = convert_to_snake_case(v)
  57             if isinstance(v, list):
  58                 v = [convert_to_snake_case(i) if isinstance(i, dict) else i for i in v]
  59             converted[convert_camel_case_to_snake(k)] = v
  60         return converted
  61 
  62     if asyncio.iscoroutinefunction(func):
  63 
  64         @wraps(func)
  65         async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
  66             return await func(*args, **convert_to_snake_case(kwargs))
  67 
  68         return async_wrapper
  69 
  70     @wraps(func)
  71     def wrapper(*args: Any, **kwargs: Any) -> Any:
  72         return func(*args, **convert_to_snake_case(kwargs))
  73 
  74     return wrapper
  75
  ```
  
  Path: `ariadne/resolvers.py`
  Content:
  ```
  1 from typing import Any
  2 
  3 from graphql import default_field_resolver
  4 from graphql.type import (
  5     GraphQLField,
  6     GraphQLObjectType,
  7     GraphQLResolveInfo,
  8     GraphQLSchema,
  9 )
  10 
  11 from .types import Resolver, SchemaBindable
  12 from .utils import convert_camel_case_to_snake
  13 
  14 
  15 class FallbackResolversSetter(SchemaBindable):
  16     def bind_to_schema(self, schema: GraphQLSchema) -> None:
  17         for type_object in schema.type_map.values():
  18             if isinstance(type_object, GraphQLObjectType):
  19                 self.add_resolvers_to_object_fields(type_object)
  20 
  21     def add_resolvers_to_object_fields(self, type_object) -> None:
  22         for field_name, field_object in type_object.fields.items():
  23             self.add_resolver_to_field(field_name, field_object)
  24 
  25     def add_resolver_to_field(self, _: str, field_object: GraphQLField) -> None:
  26         if field_object.resolve is None:
  27             field_object.resolve = default_field_resolver
  28 
  29 
  30 class SnakeCaseFallbackResolversSetter(FallbackResolversSetter):
  31     def add_resolver_to_field(
  32         self, field_name: str, field_object: GraphQLField
  33     ) -> None:
  34         if field_object.resolve is None:
  35             field_name = convert_camel_case_to_snake(field_name)
  36             field_object.resolve = resolve_to(field_name)
  37 
  38 
  39 fallback_resolvers = FallbackResolversSetter()
  40 snake_case_fallback_resolvers = SnakeCaseFallbackResolversSetter()
  41 
  42 
  43 def resolve_parent_field(parent: Any, field_name: str) -> Any:
  44     if isinstance(parent, dict):
  45         return parent.get(field_name)
  46     return getattr(parent, field_name, None)
  47 
  48 
  49 def resolve_to(field_name: str) -> Resolver:
  50     def resolver(parent: Any, info: GraphQLResolveInfo, **kwargs) -> Any:
  51         value = resolve_parent_field(parent, field_name)
  52         if callable(value):
  53             return value(info, **kwargs)
  54         return value
  55 
  56     # pylint: disable=protected-access
  57     resolver._ariadne_alias_resolver = True  # type: ignore
  58     return resolver
  59 
  60 
  61 def is_default_resolver(resolver: Resolver) -> bool:
  62     # pylint: disable=comparison-with-callable
  63     if resolver == default_field_resolver:
  64         return True
  65     return hasattr(resolver, "_ariadne_alias_resolver")
  66
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/ariadne/resolvers.py b/ariadne/resolvers.py
  --- a/ariadne/resolvers.py
  +++ b/ariadne/resolvers.py
  @@ -1,3 +1,4 @@
  +from collections.abc import Mapping
   from typing import Any
   
   from graphql import default_field_resolver
  @@ -41,7 +42,7 @@
   
   
   def resolve_parent_field(parent: Any, field_name: str) -> Any:
  -    if isinstance(parent, dict):
  +    if isinstance(parent, Mapping):
           return parent.get(field_name)
       return getattr(parent, field_name, None)
   
  diff --git a/ariadne/utils.py b/ariadne/utils.py
  --- a/ariadne/utils.py
  +++ b/ariadne/utils.py
  @@ -1,4 +1,5 @@
   import asyncio
  +from collections.abc import Mapping
   from functools import wraps
   from typing import Optional, Union, Callable, Dict, Any
   
  @@ -49,13 +50,15 @@
   
   
   def convert_kwargs_to_snake_case(func: Callable) -> Callable:
  -    def convert_to_snake_case(d: Dict) -> Dict:
  +    def convert_to_snake_case(m: Mapping) -> Dict:
           converted: Dict = {}
  -        for k, v in d.items():
  -            if isinstance(v, dict):
  +        for k, v in m.items():
  +            if isinstance(v, Mapping):
                   v = convert_to_snake_case(v)
               if isinstance(v, list):
  -                v = [convert_to_snake_case(i) if isinstance(i, dict) else i for i in v]
  +                v = [
  +                    convert_to_snake_case(i) if isinstance(i, Mapping) else i for i in v
  +                ]
               converted[convert_camel_case_to_snake(k)] = v
           return converted
  
verification_info: {"golden_diff": "diff --git a/ariadne/resolvers.py b/ariadne/resolvers.py\n--- a/ariadne/resolvers.py\n+++ b/ariadne/resolvers.py\n@@ -1,3 +1,4 @@\n+from collections.abc import Mapping\n from typing import Any\n \n from graphql import default_field_resolver\n@@ -41,7 +42,7 @@\n \n \n def resolve_parent_field(parent: Any, field_name: str) -> Any:\n-    if isinstance(parent, dict):\n+    if isinstance(parent, Mapping):\n         return parent.get(field_name)\n     return getattr(parent, field_name, None)\n \ndiff --git a/ariadne/utils.py b/ariadne/utils.py\n--- a/ariadne/utils.py\n+++ b/ariadne/utils.py\n@@ -1,4 +1,5 @@\n import asyncio\n+from collections.abc import Mapping\n from functools import wraps\n from typing import Optional, Union, Callable, Dict, Any\n \n@@ -49,13 +50,15 @@\n \n \n def convert_kwargs_to_snake_case(func: Callable) -> Callable:\n-    def convert_to_snake_case(d: Dict) -> Dict:\n+    def convert_to_snake_case(m: Mapping) -> Dict:\n         converted: Dict = {}\n-        for k, v in d.items():\n-            if isinstance(v, dict):\n+        for k, v in m.items():\n+            if isinstance(v, Mapping):\n                 v = convert_to_snake_case(v)\n             if isinstance(v, list):\n-                v = [convert_to_snake_case(i) if isinstance(i, dict) else i for i in v]\n+                v = [\n+                    convert_to_snake_case(i) if isinstance(i, Mapping) else i for i in v\n+                ]\n             converted[convert_camel_case_to_snake(k)] = v\n         return converted\n", "issue": "snake_case_fallback_resolvers not calling obj.get(attr_name)\n**Ariadne version:** 0.13.0\r\n**Python version:** 3.8.11\r\n\r\nHello. I am using the [databases](https://www.encode.io/databases/) package with an [asyncpg](https://magicstack.github.io/asyncpg/current/) backend to interact with a PostgreSQL database. The objects returned from my queries are of the type `databases.backends.postgres.Record`.  The desired attributes can only can accessed via the get method. However, when I use `snake_case_fallback_resolvers`, Ariadne has trouble resolving the requested fields and I receive the following error: `Cannot return null for non-nullable field`\r\n\r\nIf I instead use the regular `fallback_resolvers` (adjusting my schema's naming conventions), Ariadne is able to resolve the requested fields.\r\n\r\nIs this a bug or am I doing something wrong? Thank you for your time.\r\n\n", "before_files": [{"content": "import asyncio\nfrom functools import wraps\nfrom typing import Optional, Union, Callable, Dict, Any\n\nfrom graphql import GraphQLError, parse\n\n\ndef convert_camel_case_to_snake(graphql_name: str) -> str:\n    # pylint: disable=too-many-boolean-expressions\n    max_index = len(graphql_name) - 1\n    lowered_name = graphql_name.lower()\n\n    python_name = \"\"\n    for i, c in enumerate(lowered_name):\n        if i > 0 and (\n            # testWord -> test_word\n            (\n                c != graphql_name[i]\n                and graphql_name[i - 1] != \"_\"\n                and graphql_name[i - 1] == python_name[-1]\n            )\n            # TESTWord -> test_word\n            or (\n                i < max_index\n                and graphql_name[i] != lowered_name[i]\n                and graphql_name[i + 1] == lowered_name[i + 1]\n            )\n            # test134 -> test_134\n            or (c.isdigit() and not graphql_name[i - 1].isdigit())\n            # 134test -> 134_test\n            or (not c.isdigit() and graphql_name[i - 1].isdigit())\n        ):\n            python_name += \"_\"\n        python_name += c\n    return python_name\n\n\ndef gql(value: str) -> str:\n    parse(value)\n    return value\n\n\ndef unwrap_graphql_error(\n    error: Union[GraphQLError, Optional[Exception]]\n) -> Optional[Exception]:\n    if isinstance(error, GraphQLError):\n        return unwrap_graphql_error(error.original_error)\n    return error\n\n\ndef convert_kwargs_to_snake_case(func: Callable) -> Callable:\n    def convert_to_snake_case(d: Dict) -> Dict:\n        converted: Dict = {}\n        for k, v in d.items():\n            if isinstance(v, dict):\n                v = convert_to_snake_case(v)\n            if isinstance(v, list):\n                v = [convert_to_snake_case(i) if isinstance(i, dict) else i for i in v]\n            converted[convert_camel_case_to_snake(k)] = v\n        return converted\n\n    if asyncio.iscoroutinefunction(func):\n\n        @wraps(func)\n        async def async_wrapper(*args: Any, **kwargs: Any) -> Any:\n            return await func(*args, **convert_to_snake_case(kwargs))\n\n        return async_wrapper\n\n    @wraps(func)\n    def wrapper(*args: Any, **kwargs: Any) -> Any:\n        return func(*args, **convert_to_snake_case(kwargs))\n\n    return wrapper\n", "path": "ariadne/utils.py"}, {"content": "from typing import Any\n\nfrom graphql import default_field_resolver\nfrom graphql.type import (\n    GraphQLField,\n    GraphQLObjectType,\n    GraphQLResolveInfo,\n    GraphQLSchema,\n)\n\nfrom .types import Resolver, SchemaBindable\nfrom .utils import convert_camel_case_to_snake\n\n\nclass FallbackResolversSetter(SchemaBindable):\n    def bind_to_schema(self, schema: GraphQLSchema) -> None:\n        for type_object in schema.type_map.values():\n            if isinstance(type_object, GraphQLObjectType):\n                self.add_resolvers_to_object_fields(type_object)\n\n    def add_resolvers_to_object_fields(self, type_object) -> None:\n        for field_name, field_object in type_object.fields.items():\n            self.add_resolver_to_field(field_name, field_object)\n\n    def add_resolver_to_field(self, _: str, field_object: GraphQLField) -> None:\n        if field_object.resolve is None:\n            field_object.resolve = default_field_resolver\n\n\nclass SnakeCaseFallbackResolversSetter(FallbackResolversSetter):\n    def add_resolver_to_field(\n        self, field_name: str, field_object: GraphQLField\n    ) -> None:\n        if field_object.resolve is None:\n            field_name = convert_camel_case_to_snake(field_name)\n            field_object.resolve = resolve_to(field_name)\n\n\nfallback_resolvers = FallbackResolversSetter()\nsnake_case_fallback_resolvers = SnakeCaseFallbackResolversSetter()\n\n\ndef resolve_parent_field(parent: Any, field_name: str) -> Any:\n    if isinstance(parent, dict):\n        return parent.get(field_name)\n    return getattr(parent, field_name, None)\n\n\ndef resolve_to(field_name: str) -> Resolver:\n    def resolver(parent: Any, info: GraphQLResolveInfo, **kwargs) -> Any:\n        value = resolve_parent_field(parent, field_name)\n        if callable(value):\n            return value(info, **kwargs)\n        return value\n\n    # pylint: disable=protected-access\n    resolver._ariadne_alias_resolver = True  # type: ignore\n    return resolver\n\n\ndef is_default_resolver(resolver: Resolver) -> bool:\n    # pylint: disable=comparison-with-callable\n    if resolver == default_field_resolver:\n        return True\n    return hasattr(resolver, \"_ariadne_alias_resolver\")\n", "path": "ariadne/resolvers.py"}], "after_files": [{"content": "import asyncio\nfrom collections.abc import Mapping\nfrom functools import wraps\nfrom typing import Optional, Union, Callable, Dict, Any\n\nfrom graphql import GraphQLError, parse\n\n\ndef convert_camel_case_to_snake(graphql_name: str) -> str:\n    # pylint: disable=too-many-boolean-expressions\n    max_index = len(graphql_name) - 1\n    lowered_name = graphql_name.lower()\n\n    python_name = \"\"\n    for i, c in enumerate(lowered_name):\n        if i > 0 and (\n            # testWord -> test_word\n            (\n                c != graphql_name[i]\n                and graphql_name[i - 1] != \"_\"\n                and graphql_name[i - 1] == python_name[-1]\n            )\n            # TESTWord -> test_word\n            or (\n                i < max_index\n                and graphql_name[i] != lowered_name[i]\n                and graphql_name[i + 1] == lowered_name[i + 1]\n            )\n            # test134 -> test_134\n            or (c.isdigit() and not graphql_name[i - 1].isdigit())\n            # 134test -> 134_test\n            or (not c.isdigit() and graphql_name[i - 1].isdigit())\n        ):\n            python_name += \"_\"\n        python_name += c\n    return python_name\n\n\ndef gql(value: str) -> str:\n    parse(value)\n    return value\n\n\ndef unwrap_graphql_error(\n    error: Union[GraphQLError, Optional[Exception]]\n) -> Optional[Exception]:\n    if isinstance(error, GraphQLError):\n        return unwrap_graphql_error(error.original_error)\n    return error\n\n\ndef convert_kwargs_to_snake_case(func: Callable) -> Callable:\n    def convert_to_snake_case(m: Mapping) -> Dict:\n        converted: Dict = {}\n        for k, v in m.items():\n            if isinstance(v, Mapping):\n                v = convert_to_snake_case(v)\n            if isinstance(v, list):\n                v = [\n                    convert_to_snake_case(i) if isinstance(i, Mapping) else i for i in v\n                ]\n            converted[convert_camel_case_to_snake(k)] = v\n        return converted\n\n    if asyncio.iscoroutinefunction(func):\n\n        @wraps(func)\n        async def async_wrapper(*args: Any, **kwargs: Any) -> Any:\n            return await func(*args, **convert_to_snake_case(kwargs))\n\n        return async_wrapper\n\n    @wraps(func)\n    def wrapper(*args: Any, **kwargs: Any) -> Any:\n        return func(*args, **convert_to_snake_case(kwargs))\n\n    return wrapper\n", "path": "ariadne/utils.py"}, {"content": "from collections.abc import Mapping\nfrom typing import Any\n\nfrom graphql import default_field_resolver\nfrom graphql.type import (\n    GraphQLField,\n    GraphQLObjectType,\n    GraphQLResolveInfo,\n    GraphQLSchema,\n)\n\nfrom .types import Resolver, SchemaBindable\nfrom .utils import convert_camel_case_to_snake\n\n\nclass FallbackResolversSetter(SchemaBindable):\n    def bind_to_schema(self, schema: GraphQLSchema) -> None:\n        for type_object in schema.type_map.values():\n            if isinstance(type_object, GraphQLObjectType):\n                self.add_resolvers_to_object_fields(type_object)\n\n    def add_resolvers_to_object_fields(self, type_object) -> None:\n        for field_name, field_object in type_object.fields.items():\n            self.add_resolver_to_field(field_name, field_object)\n\n    def add_resolver_to_field(self, _: str, field_object: GraphQLField) -> None:\n        if field_object.resolve is None:\n            field_object.resolve = default_field_resolver\n\n\nclass SnakeCaseFallbackResolversSetter(FallbackResolversSetter):\n    def add_resolver_to_field(\n        self, field_name: str, field_object: GraphQLField\n    ) -> None:\n        if field_object.resolve is None:\n            field_name = convert_camel_case_to_snake(field_name)\n            field_object.resolve = resolve_to(field_name)\n\n\nfallback_resolvers = FallbackResolversSetter()\nsnake_case_fallback_resolvers = SnakeCaseFallbackResolversSetter()\n\n\ndef resolve_parent_field(parent: Any, field_name: str) -> Any:\n    if isinstance(parent, Mapping):\n        return parent.get(field_name)\n    return getattr(parent, field_name, None)\n\n\ndef resolve_to(field_name: str) -> Resolver:\n    def resolver(parent: Any, info: GraphQLResolveInfo, **kwargs) -> Any:\n        value = resolve_parent_field(parent, field_name)\n        if callable(value):\n            return value(info, **kwargs)\n        return value\n\n    # pylint: disable=protected-access\n    resolver._ariadne_alias_resolver = True  # type: ignore\n    return resolver\n\n\ndef is_default_resolver(resolver: Resolver) -> bool:\n    # pylint: disable=comparison-with-callable\n    if resolver == default_field_resolver:\n        return True\n    return hasattr(resolver, \"_ariadne_alias_resolver\")\n", "path": "ariadne/resolvers.py"}]}