prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Use sentinel value for input parameters that aren't sent by the clients
  When using input types with optional fields we cannot differentiate by fields that have sent as null and fields that haven't been sent at all.
  
  So I think we should use a sentinel value that tells the field is unset, and also behaves as falsy:
  
  ```python
  class _Unset:
      def __bool__(self): return False
  
  UNSET = _Unset()
  
  # this utility might be useful, so we don't have to use an internal representation
  def is_unset(value: Any):
      return value is UNSET
  ```
  
  then we can use this class when instantiating the input types for a resolver:)
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `strawberry/utils/arguments.py`
  Content:
  ```
  1 import enum
  2 from dataclasses import is_dataclass
  3 from datetime import date, datetime, time
  4 
  5 from ..exceptions import UnsupportedTypeError
  6 from .str_converters import to_camel_case, to_snake_case
  7 from .typing import get_list_annotation, get_optional_annotation, is_list, is_optional
  8 
  9 
  10 SCALAR_TYPES = [int, str, float, bytes, bool, datetime, date, time]
  11 
  12 
  13 def _to_type(value, annotation):
  14     if value is None:
  15         return None
  16 
  17     if is_optional(annotation):
  18         annotation = get_optional_annotation(annotation)
  19 
  20     # TODO: change this to be a is_scalar util and make sure it works with any scalar
  21     if getattr(annotation, "__supertype__", annotation) in SCALAR_TYPES:
  22         return value
  23 
  24     # Convert Enum fields to instances using the value. This is safe
  25     # because graphql-core has already validated the input.
  26     if isinstance(annotation, enum.EnumMeta):
  27         return annotation(value)
  28 
  29     if is_list(annotation):
  30         annotation = get_list_annotation(annotation)
  31 
  32         return [_to_type(x, annotation) for x in value]
  33 
  34     if is_dataclass(annotation):
  35         fields = annotation.__dataclass_fields__
  36 
  37         kwargs = {}
  38 
  39         for name, field in fields.items():
  40             dict_name = name
  41 
  42             if hasattr(field, "field_name") and field.field_name:
  43                 dict_name = field.field_name
  44             else:
  45                 dict_name = to_camel_case(name)
  46 
  47             kwargs[name] = _to_type(value.get(dict_name), field.type)
  48 
  49         return annotation(**kwargs)
  50 
  51     raise UnsupportedTypeError(annotation)
  52 
  53 
  54 def convert_args(args, annotations):
  55     """Converts a nested dictionary to a dictionary of strawberry input types."""
  56 
  57     converted_args = {}
  58 
  59     for key, value in args.items():
  60         key = to_snake_case(key)
  61         annotation = annotations[key]
  62 
  63         converted_args[key] = _to_type(value, annotation)
  64 
  65     return converted_args
  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/strawberry/utils/arguments.py b/strawberry/utils/arguments.py
  --- a/strawberry/utils/arguments.py
  +++ b/strawberry/utils/arguments.py
  @@ -1,19 +1,49 @@
   import enum
  +import typing
   from dataclasses import is_dataclass
   from datetime import date, datetime, time
   
   from ..exceptions import UnsupportedTypeError
  -from .str_converters import to_camel_case, to_snake_case
  +from .str_converters import to_camel_case
   from .typing import get_list_annotation, get_optional_annotation, is_list, is_optional
   
   
   SCALAR_TYPES = [int, str, float, bytes, bool, datetime, date, time]
   
   
  -def _to_type(value, annotation):
  +class _Unset:
  +    def __str__(self):
  +        return ""
  +
  +    def __bool__(self):
  +        return False
  +
  +
  +UNSET = _Unset()
  +
  +
  +def is_unset(value: typing.Any) -> bool:
  +    return value is UNSET
  +
  +
  +def convert_args(
  +    value: typing.Union[typing.Dict[str, typing.Any], typing.Any],
  +    annotation: typing.Union[typing.Dict[str, typing.Type], typing.Type],
  +):
  +    """Converts a nested dictionary to a dictionary of actual types.
  +
  +    It deals with conversion of input types to proper dataclasses and
  +    also uses a sentinel value for unset values."""
  +
  +    if annotation == {}:
  +        return value
  +
       if value is None:
           return None
   
  +    if is_unset(value):
  +        return value
  +
       if is_optional(annotation):
           annotation = get_optional_annotation(annotation)
   
  @@ -24,19 +54,27 @@
       # Convert Enum fields to instances using the value. This is safe
       # because graphql-core has already validated the input.
       if isinstance(annotation, enum.EnumMeta):
  -        return annotation(value)
  +        return annotation(value)  # type: ignore
   
       if is_list(annotation):
           annotation = get_list_annotation(annotation)
   
  -        return [_to_type(x, annotation) for x in value]
  +        return [convert_args(x, annotation) for x in value]
  +
  +    fields = None
   
  -    if is_dataclass(annotation):
  -        fields = annotation.__dataclass_fields__
  +    # we receive dicts when converting resolvers arguments to
  +    # actual types
  +    if isinstance(annotation, dict):
  +        fields = annotation.items()
   
  +    elif is_dataclass(annotation):
  +        fields = annotation.__dataclass_fields__.items()
  +
  +    if fields:
           kwargs = {}
   
  -        for name, field in fields.items():
  +        for name, field in fields:
               dict_name = name
   
               if hasattr(field, "field_name") and field.field_name:
  @@ -44,22 +82,19 @@
               else:
                   dict_name = to_camel_case(name)
   
  -            kwargs[name] = _to_type(value.get(dict_name), field.type)
  -
  -        return annotation(**kwargs)
  -
  -    raise UnsupportedTypeError(annotation)
  -
  -
  -def convert_args(args, annotations):
  -    """Converts a nested dictionary to a dictionary of strawberry input types."""
  +            # dataclasses field have a .type attribute
  +            if hasattr(field, "type"):
  +                field_type = field.type
  +            # meanwhile when using dicts the value of the field is
  +            # the actual type, for example in: { 'name': str }
  +            else:
  +                field_type = field
   
  -    converted_args = {}
  +            kwargs[name] = convert_args(value.get(dict_name, UNSET), field_type)
   
  -    for key, value in args.items():
  -        key = to_snake_case(key)
  -        annotation = annotations[key]
  +        if is_dataclass(annotation):
  +            return annotation(**kwargs)  # type: ignore
   
  -        converted_args[key] = _to_type(value, annotation)
  +        return kwargs
   
  -    return converted_args
  +    raise UnsupportedTypeError(annotation)
  
verification_info: {"golden_diff": "diff --git a/strawberry/utils/arguments.py b/strawberry/utils/arguments.py\n--- a/strawberry/utils/arguments.py\n+++ b/strawberry/utils/arguments.py\n@@ -1,19 +1,49 @@\n import enum\n+import typing\n from dataclasses import is_dataclass\n from datetime import date, datetime, time\n \n from ..exceptions import UnsupportedTypeError\n-from .str_converters import to_camel_case, to_snake_case\n+from .str_converters import to_camel_case\n from .typing import get_list_annotation, get_optional_annotation, is_list, is_optional\n \n \n SCALAR_TYPES = [int, str, float, bytes, bool, datetime, date, time]\n \n \n-def _to_type(value, annotation):\n+class _Unset:\n+    def __str__(self):\n+        return \"\"\n+\n+    def __bool__(self):\n+        return False\n+\n+\n+UNSET = _Unset()\n+\n+\n+def is_unset(value: typing.Any) -> bool:\n+    return value is UNSET\n+\n+\n+def convert_args(\n+    value: typing.Union[typing.Dict[str, typing.Any], typing.Any],\n+    annotation: typing.Union[typing.Dict[str, typing.Type], typing.Type],\n+):\n+    \"\"\"Converts a nested dictionary to a dictionary of actual types.\n+\n+    It deals with conversion of input types to proper dataclasses and\n+    also uses a sentinel value for unset values.\"\"\"\n+\n+    if annotation == {}:\n+        return value\n+\n     if value is None:\n         return None\n \n+    if is_unset(value):\n+        return value\n+\n     if is_optional(annotation):\n         annotation = get_optional_annotation(annotation)\n \n@@ -24,19 +54,27 @@\n     # Convert Enum fields to instances using the value. This is safe\n     # because graphql-core has already validated the input.\n     if isinstance(annotation, enum.EnumMeta):\n-        return annotation(value)\n+        return annotation(value)  # type: ignore\n \n     if is_list(annotation):\n         annotation = get_list_annotation(annotation)\n \n-        return [_to_type(x, annotation) for x in value]\n+        return [convert_args(x, annotation) for x in value]\n+\n+    fields = None\n \n-    if is_dataclass(annotation):\n-        fields = annotation.__dataclass_fields__\n+    # we receive dicts when converting resolvers arguments to\n+    # actual types\n+    if isinstance(annotation, dict):\n+        fields = annotation.items()\n \n+    elif is_dataclass(annotation):\n+        fields = annotation.__dataclass_fields__.items()\n+\n+    if fields:\n         kwargs = {}\n \n-        for name, field in fields.items():\n+        for name, field in fields:\n             dict_name = name\n \n             if hasattr(field, \"field_name\") and field.field_name:\n@@ -44,22 +82,19 @@\n             else:\n                 dict_name = to_camel_case(name)\n \n-            kwargs[name] = _to_type(value.get(dict_name), field.type)\n-\n-        return annotation(**kwargs)\n-\n-    raise UnsupportedTypeError(annotation)\n-\n-\n-def convert_args(args, annotations):\n-    \"\"\"Converts a nested dictionary to a dictionary of strawberry input types.\"\"\"\n+            # dataclasses field have a .type attribute\n+            if hasattr(field, \"type\"):\n+                field_type = field.type\n+            # meanwhile when using dicts the value of the field is\n+            # the actual type, for example in: { 'name': str }\n+            else:\n+                field_type = field\n \n-    converted_args = {}\n+            kwargs[name] = convert_args(value.get(dict_name, UNSET), field_type)\n \n-    for key, value in args.items():\n-        key = to_snake_case(key)\n-        annotation = annotations[key]\n+        if is_dataclass(annotation):\n+            return annotation(**kwargs)  # type: ignore\n \n-        converted_args[key] = _to_type(value, annotation)\n+        return kwargs\n \n-    return converted_args\n+    raise UnsupportedTypeError(annotation)\n", "issue": "Use sentinel value for input parameters that aren't sent by the clients\nWhen using input types with optional fields we cannot differentiate by fields that have sent as null and fields that haven't been sent at all.\r\n\r\nSo I think we should use a sentinel value that tells the field is unset, and also behaves as falsy:\r\n\r\n```python\r\nclass _Unset:\r\n    def __bool__(self): return False\r\n\r\nUNSET = _Unset()\r\n\r\n# this utility might be useful, so we don't have to use an internal representation\r\ndef is_unset(value: Any):\r\n    return value is UNSET\r\n```\r\n\r\nthen we can use this class when instantiating the input types for a resolver:)\n", "before_files": [{"content": "import enum\nfrom dataclasses import is_dataclass\nfrom datetime import date, datetime, time\n\nfrom ..exceptions import UnsupportedTypeError\nfrom .str_converters import to_camel_case, to_snake_case\nfrom .typing import get_list_annotation, get_optional_annotation, is_list, is_optional\n\n\nSCALAR_TYPES = [int, str, float, bytes, bool, datetime, date, time]\n\n\ndef _to_type(value, annotation):\n    if value is None:\n        return None\n\n    if is_optional(annotation):\n        annotation = get_optional_annotation(annotation)\n\n    # TODO: change this to be a is_scalar util and make sure it works with any scalar\n    if getattr(annotation, \"__supertype__\", annotation) in SCALAR_TYPES:\n        return value\n\n    # Convert Enum fields to instances using the value. This is safe\n    # because graphql-core has already validated the input.\n    if isinstance(annotation, enum.EnumMeta):\n        return annotation(value)\n\n    if is_list(annotation):\n        annotation = get_list_annotation(annotation)\n\n        return [_to_type(x, annotation) for x in value]\n\n    if is_dataclass(annotation):\n        fields = annotation.__dataclass_fields__\n\n        kwargs = {}\n\n        for name, field in fields.items():\n            dict_name = name\n\n            if hasattr(field, \"field_name\") and field.field_name:\n                dict_name = field.field_name\n            else:\n                dict_name = to_camel_case(name)\n\n            kwargs[name] = _to_type(value.get(dict_name), field.type)\n\n        return annotation(**kwargs)\n\n    raise UnsupportedTypeError(annotation)\n\n\ndef convert_args(args, annotations):\n    \"\"\"Converts a nested dictionary to a dictionary of strawberry input types.\"\"\"\n\n    converted_args = {}\n\n    for key, value in args.items():\n        key = to_snake_case(key)\n        annotation = annotations[key]\n\n        converted_args[key] = _to_type(value, annotation)\n\n    return converted_args\n", "path": "strawberry/utils/arguments.py"}], "after_files": [{"content": "import enum\nimport typing\nfrom dataclasses import is_dataclass\nfrom datetime import date, datetime, time\n\nfrom ..exceptions import UnsupportedTypeError\nfrom .str_converters import to_camel_case\nfrom .typing import get_list_annotation, get_optional_annotation, is_list, is_optional\n\n\nSCALAR_TYPES = [int, str, float, bytes, bool, datetime, date, time]\n\n\nclass _Unset:\n    def __str__(self):\n        return \"\"\n\n    def __bool__(self):\n        return False\n\n\nUNSET = _Unset()\n\n\ndef is_unset(value: typing.Any) -> bool:\n    return value is UNSET\n\n\ndef convert_args(\n    value: typing.Union[typing.Dict[str, typing.Any], typing.Any],\n    annotation: typing.Union[typing.Dict[str, typing.Type], typing.Type],\n):\n    \"\"\"Converts a nested dictionary to a dictionary of actual types.\n\n    It deals with conversion of input types to proper dataclasses and\n    also uses a sentinel value for unset values.\"\"\"\n\n    if annotation == {}:\n        return value\n\n    if value is None:\n        return None\n\n    if is_unset(value):\n        return value\n\n    if is_optional(annotation):\n        annotation = get_optional_annotation(annotation)\n\n    # TODO: change this to be a is_scalar util and make sure it works with any scalar\n    if getattr(annotation, \"__supertype__\", annotation) in SCALAR_TYPES:\n        return value\n\n    # Convert Enum fields to instances using the value. This is safe\n    # because graphql-core has already validated the input.\n    if isinstance(annotation, enum.EnumMeta):\n        return annotation(value)  # type: ignore\n\n    if is_list(annotation):\n        annotation = get_list_annotation(annotation)\n\n        return [convert_args(x, annotation) for x in value]\n\n    fields = None\n\n    # we receive dicts when converting resolvers arguments to\n    # actual types\n    if isinstance(annotation, dict):\n        fields = annotation.items()\n\n    elif is_dataclass(annotation):\n        fields = annotation.__dataclass_fields__.items()\n\n    if fields:\n        kwargs = {}\n\n        for name, field in fields:\n            dict_name = name\n\n            if hasattr(field, \"field_name\") and field.field_name:\n                dict_name = field.field_name\n            else:\n                dict_name = to_camel_case(name)\n\n            # dataclasses field have a .type attribute\n            if hasattr(field, \"type\"):\n                field_type = field.type\n            # meanwhile when using dicts the value of the field is\n            # the actual type, for example in: { 'name': str }\n            else:\n                field_type = field\n\n            kwargs[name] = convert_args(value.get(dict_name, UNSET), field_type)\n\n        if is_dataclass(annotation):\n            return annotation(**kwargs)  # type: ignore\n\n        return kwargs\n\n    raise UnsupportedTypeError(annotation)\n", "path": "strawberry/utils/arguments.py"}]}