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()

```

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

{"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"}]}